From 5346b0e7fa175a0b9fe9025eed02dd2de07b8b6b Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sat, 22 Jan 2022 19:37:25 +0100 Subject: [PATCH] day 19, after optimization (8.5s -> 0.06s) --- 2021/day19/Makefile | 12 ++- 2021/day19/aoc-c.c | 176 +++++++++++++++++++++----------------------- 2 files changed, 95 insertions(+), 93 deletions(-) diff --git a/2021/day19/Makefile b/2021/day19/Makefile index 6d616e2..77c2652 100644 --- a/2021/day19/Makefile +++ b/2021/day19/Makefile @@ -27,10 +27,12 @@ export LD_LIBRARY_PATH = $(LIBDIR) CFLAGS += -std=gnu99 CFLAGS += -O2 CFLAGS += -g -#CFLAGS += -pg +CFLAGS += -pg CFLAGS += -Wall CFLAGS += -Wextra CFLAGS += -march=native +# Next one may be useful for valgrind (some invalid instructions) +# CFLAGS += -mno-tbm CFLAGS += -Wmissing-declarations CFLAGS += -Wno-unused-result @@ -40,7 +42,7 @@ CFLAGS += -DDEBUG_POOL # memory pools management TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n" export PATH := .:$(PATH) -.PHONY: clean all compile memcheck memcheck1 memcheck2 ex1 ex2 +.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 all: ex1 ex2 @@ -54,6 +56,8 @@ memcheck2: compile: aoc-c +assembly: aoc-c.s + ex1: aoc-c @$(TIME) aoc-c -p 1 < $(INPUT) @@ -66,3 +70,7 @@ clean: .c: @echo compiling $< @$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@ + +.c.s: + @echo generating $@ + @$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@ diff --git a/2021/day19/aoc-c.c b/2021/day19/aoc-c.c index 7ded02c..8f8b538 100644 --- a/2021/day19/aoc-c.c +++ b/2021/day19/aoc-c.c @@ -23,31 +23,28 @@ #define MAX_SCANNERS 32 /* I know, I know... */ typedef struct vector { - s64 x, y, z; + int x, y, z; } vector_t; typedef struct beacon { - int scanner; /* original scanner for beacon */ - int num; /* original # in original scanner */ - int common; /* has common distance with 1st scanner */ vector_t vec; /* beacon coordinates */ struct list_head list_beacons; } beacon_t; typedef struct dist { - u64 dist; /* square distance... */ - beacon_t *beacon1, *beacon2; /* ... between these beacons */ + int common; /* matched in last dists compare */ + uint dist; /* square distance... */ + beacon_t *beacon1, *beacon2; /* ... between these beacons */ struct list_head list_dists; } dist_t; typedef struct scanner { int nbeacons, ndists; int adjusted; + beacon_t *ref[3]; /* reference beacons */ vector_t rel; /* relative position to scanner 0 */ struct list_head list_beacons; struct list_head list_dists; - beacon_t *ref[3]; /* reference beacons */ - //vector_t ref[3]; } scanner_t; static pool_t *pool_beacon; @@ -96,7 +93,7 @@ vector_t rotations[] = { /* vector_rotate: returns vector rotation vector by "nrot"th rotations matrix */ -static vector_t vector_rotate(const vector_t *vector, int nrot) +static inline vector_t vector_rotate(const vector_t *vector, const int nrot) { vector_t *rot = &rotations[nrot*3], res; @@ -108,7 +105,7 @@ static vector_t vector_rotate(const vector_t *vector, int nrot) /* beacon_diff: returns difference between 2 vectors */ -static vector_t vector_diff(const vector_t *vec1, vector_t *vec2) +static inline vector_t vector_diff(const vector_t *vec1, const vector_t *vec2) { vector_t res; @@ -120,7 +117,7 @@ static vector_t vector_diff(const vector_t *vec1, vector_t *vec2) /* beacon_diff: calculate sum of two vectors */ -static vector_t vector_add(const vector_t *vec1, vector_t *vec2) +static inline vector_t vector_add(const vector_t *vec1, const vector_t *vec2) { vector_t res; @@ -130,19 +127,27 @@ static vector_t vector_add(const vector_t *vec1, vector_t *vec2) return res; } +/* compare two beacons by x, y, and z. + */ +static inline int vector_cmp(const vector_t *v1, const vector_t *v2) +{ + if (v1->x < v2->x || + (v1->x == v2->x && (v1->y < v2->y || + (v1->y == v2->y && v1->z < v2->z)))) { + return -1; + } else if (v1->x == v2->x && v1->y == v2->y && v1->z == v2->z) { + return 0; + } + return 1; +} + /* insert a new distance in scanner's (sorted) distances list */ -static int insert_dist(scanner_t *scanner, dist_t *dist) +static inline int insert_dist(scanner_t *scanner, dist_t *dist) { dist_t *cur; uint newdist = dist->dist; - cur = list_first_entry_or_null(&scanner->list_dists, dist_t, list_dists); - /* special case: first distance or new dist lower than first dist */ - if (!cur || newdist < cur->dist) { - list_add(&dist->list_dists, &scanner->list_dists); - goto end; - } /* normal case: insert before current when new dist is lower than current dist */ list_for_each_entry(cur, &scanner->list_dists, list_dists) { if (newdist < cur->dist) { @@ -150,15 +155,17 @@ static int insert_dist(scanner_t *scanner, dist_t *dist) goto end; } } - /* special case: we went to end, insert at list's tail */ + /* special case: we went to end without inserting, insert at list's tail. + * This includes the case list was empty. + */ list_add_tail(&dist->list_dists, &scanner->list_dists); end: return ++scanner->ndists; } -/* add distances between beacon and all others +/* add distances between beacon and all other beacons in scanner. */ -static int add_beacon_dists1(scanner_t *scanner, beacon_t *beacon) +static int add_beacon_dists(scanner_t *scanner, beacon_t *beacon) { beacon_t *cur; dist_t *dist; @@ -180,41 +187,35 @@ static int add_beacon_dists1(scanner_t *scanner, beacon_t *beacon) return count; } -/* compare two beacons by x, y, and z. +/* move non common dists from scanner s2 to scanner s1 */ -static inline int compare_beacons(beacon_t *b1, beacon_t *b2) +static int move_beacon_dists(scanner_t *s1, scanner_t *s2) { - vector_t *v1 = &b1->vec, *v2 = &b2->vec; - //u64 m1 = b1->manhattan, m2 = b2->manhattan; + struct list_head *cur, *tmp; + int count = 0; - if (v1->x < v2->x || - (v1->x == v2->x && (v1->y < v2->y || - (v1->y == v2->y && v1->z < v2->z)))) { - return -1; - } else if (v1->x == v2->x && v1->y == v2->y && v1->z == v2->z) { - return 0; + list_for_each_safe(cur, tmp, &s2->list_dists) { + dist_t *dist = list_entry(cur, dist_t, list_dists); + if (!dist->common) { + list_del(cur); + insert_dist(s1, dist); + count++; + } } - return 1; + return count; } /* insert a new beacon in scanner's list. - * keep the list ordered by: - * 1) manhattan distance - * 2) x, then y, then z + * keep the list ordered by x, y, then z. */ static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon) { beacon_t *cur; - cur = list_first_entry_or_null(&scanner->list_beacons, beacon_t, list_beacons); - /* special case: first beacon or new beacon lower than first beacon */ - if (!cur || compare_beacons(beacon, cur) < 0) { - list_add(&beacon->list_beacons, &scanner->list_beacons); - goto end; - } - /* normal case: insert before current when new dist is lower than current dist */ + /* normal case: insert before current when new dist is lower than current dist + */ list_for_each_entry(cur, &scanner->list_beacons, list_beacons) { - switch (compare_beacons(beacon, cur)) { + switch (vector_cmp(&beacon->vec, &cur->vec)) { case -1: list_add_tail(&beacon->list_beacons, &cur->list_beacons); goto end; @@ -222,33 +223,36 @@ static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon) return -1; } } - /* special case: we went to end, insert at list's tail */ + /* special case: we went to end without inserting, insert at list's tail. + * This includes the case list was empty. + */ list_add_tail(&beacon->list_beacons, &scanner->list_beacons); end: return ++scanner->nbeacons; } -/* using scanner's reference points, find the correct rotation and translation +/* using scanner's 3 reference beacons, find the correct rotation and translation */ -static int adjust_scanner(scanner_t *ref, scanner_t *s) +static int adjust_scanner(scanner_t *ref, scanner_t *scanner) { - beacon_t *beacon_ref[3], *beacon[3], *cur; + beacon_t *cur; int error = -1; + vector_t *vec_ref[3], *vec[3]; for (uint i = 0; i < 3; ++i) { - beacon_ref[i] = ref->ref[i]; - beacon[i] = s->ref[i]; + vec_ref[i] = &ref->ref[i]->vec; + vec[i] = &scanner->ref[i]->vec; } for (uint rotnum = 0; rotnum < NROTATIONS; ++rotnum) { - vector_t rot[3], diff[3]; + vector_t diff[3]; /* rotate the first beacon and translate to match ref's (x, y, z) */ for (int bref = 0; bref < 3; ++bref) { - rot[bref] = vector_rotate(&beacon[bref]->vec, rotnum); - diff[bref] = vector_diff(&beacon_ref[bref]->vec, rot + bref); + diff[bref] = vector_rotate(vec[bref], rotnum); + diff[bref] = vector_diff(vec_ref[bref], diff + bref); - /* check that rotation/translation works for the 3 reference points + /* Does rotation/translation works for the 3 reference points ? */ if (bref > 0 && (diff[bref].x != diff[0].x || diff[bref].y != diff[0].y || @@ -256,14 +260,14 @@ static int adjust_scanner(scanner_t *ref, scanner_t *s) goto next_rot; } } - s->rel = diff[0]; + scanner->rel = diff[0]; /* we found a match */ error = 0; /* adjust all beacons */ - list_for_each_entry(cur, &s->list_beacons, list_beacons) { + list_for_each_entry(cur, &scanner->list_beacons, list_beacons) { cur->vec = vector_rotate(&cur->vec, rotnum); - cur->vec = vector_add(&cur->vec, &diff[0]); + cur->vec = vector_add(&cur->vec, diff); } - s->adjusted = 1; + scanner->adjusted = 1; break; next_rot: @@ -274,7 +278,7 @@ static int adjust_scanner(scanner_t *ref, scanner_t *s) /* merge scanner s2 (already translated) beacons into scanner s1. * - ignore duplicate beacons - * - recalculate all distances for new beacons + * - move dists lists which were */ static int merge_scanner(scanner_t *s1, scanner_t *s2) { @@ -283,14 +287,15 @@ static int merge_scanner(scanner_t *s1, scanner_t *s2) dist_t *dist; int count = 0; + move_beacon_dists(s1, s2); list_for_each_safe(cur, tmp, &s2->list_beacons) { beacon = list_entry(cur, beacon_t, list_beacons); list_del(cur); s2->nbeacons--; - if (insert_unique_beacon(s1, beacon) > 0) - add_beacon_dists1(s1, beacon); + if (insert_unique_beacon(s1, beacon) < 0) + pool_add(pool_beacon, beacon); } - /* free all dists */ + /* free all remaining dists from s2 */ list_for_each_safe(cur, tmp, &s2->list_dists) { dist = list_entry(cur, dist_t, list_dists); list_del(cur); @@ -310,10 +315,8 @@ static int merge_scanner(scanner_t *s1, scanner_t *s2) static int count_common_distances(scanner_t *s1, scanner_t *s2) { struct list_head *plist1, *plist2; - dist_t *pdist1, *pdist2; - beacon_t *tmpbeacon; - int cur1 = 0, cur2 = 0; - u64 dist1, dist2; + dist_t *pdist1, *pdist2, *tmpdist; + uint dist1, dist2; int nref = 0; uint count = 0; @@ -333,10 +336,10 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2) plist1 = s1->list_dists.next; plist2 = s2->list_dists.next; - /* initialize second scanner common beacons + /* initialize second scanner dists */ - list_for_each_entry(tmpbeacon, &s2->list_beacons, list_beacons) { - tmpbeacon->common = 0; + list_for_each_entry(tmpdist, &s2->list_dists, list_dists) { + tmpdist->common = 0; } while (plist1 != &s1->list_dists && plist2 != &s2->list_dists) { @@ -346,15 +349,11 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2) dist2 = pdist2->dist; if (dist1 == dist2) { + pdist2->common = 1; plist1 = plist1->next; plist2 = plist2->next; - cur1++; - cur2++; count++; - pdist2->beacon1->common++; /* mark beacons as common in 2nd scanner */ - pdist2->beacon2->common++; - switch (nref) { case 0: /* first 2 reference points */ s1->ref[0] = pdist1->beacon1; @@ -424,17 +423,16 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2) } else if (dist1 < dist2) { plist1 = plist1->next; - cur1++; } else { /* dist1 > dist2 */ plist2 = plist2->next; - cur2++; } } return count; } -/* match all scanners +/* match all scanners with scanner 0. + * When a match is found, merge it into scanner 0. */ static void match_scanners() { @@ -469,46 +467,44 @@ static int scanners_read() while ((buflen = getline(&buf, &alloc, stdin)) > 0) { switch (buf[1]) { - case '-': + case '-': /* scanner header */ scanner = scanners + nscanners; INIT_LIST_HEAD(&scanner->list_beacons); INIT_LIST_HEAD(&scanner->list_dists); nscanners++; scanner->nbeacons = 0; break; - case '\0': + case '\0': /* empty line */ break; default: beacon = pool_get(pool_beacon); - beacon->scanner = nscanners; - beacon->num = scanner->nbeacons; - sscanf(buf, "%ld,%ld,%ld", &beacon->vec.x, &beacon->vec.y, + sscanf(buf, "%d,%d,%d", &beacon->vec.x, &beacon->vec.y, &beacon->vec.z); if (insert_unique_beacon(scanner, beacon) > 0) - add_beacon_dists1(scanner, beacon); + add_beacon_dists(scanner, beacon); } } free(buf); return nscanners; } -static s64 part1() +static int part1() { return (*scanners).nbeacons; } -static s64 part2() +static int part2() { vector_t *v1, *v2; - s64 max = 0, cur; + int max = 0, cur; for (int i = 0; i < nscanners; ++i) { v1 = &scanners[i].rel; for (int j = i + 1; j < nscanners; ++j) { v2 = &scanners[j].rel; - cur = labs(v2->x - v1->x) - + labs(v2->y - v1->y) - + labs(v2->z - v1->z); + cur = abs(v2->x - v1->x) + + abs(v2->y - v1->y) + + abs(v2->z - v1->z); if (cur > max) { max = cur; } @@ -554,10 +550,8 @@ int main(int ac, char **av) } scanners_read(); match_scanners(); - printf("%s : res=%ld\n", *av, part == 1? part1(): part2()); - pool_stats(pool_beacon); pool_destroy(pool_beacon); - pool_stats(pool_dist); pool_destroy(pool_dist); + printf("%s : res=%d\n", *av, part == 1? part1(): part2()); exit(0); }