Skip to content

Commit

Permalink
add method to reduce hash collision
Browse files Browse the repository at this point in the history
  • Loading branch information
qnkhuat committed Jan 31, 2021
1 parent 2ce2d75 commit 51ed5ae
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 182 deletions.
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
.DEFAULT_GOAL := lifeterm
CC=gcc

lifeterm: lifeterm.c
@$(CC) lifeterm.c hashlife.c -g -o lifeterm.o -Wall -Wextra -pedantic -std=c99
@$(CC) lifeterm.c hashlife.c log.c -g -o lifeterm.o -Wall -Wextra -pedantic -std=c99

hashlife: hashlife.c
@$(CC) hashlife.c hashlife.c -g -o hashlife.o -Wall -Wextra -pedantic -std=c99 -Wno-incompatible-pointer-types-discards-qualifiers

test: test.c
@$(CC) test.c hashlife.c lifeterm.c -g -o test.o -Wall -Wextra -pedantic -std=c11
test_hash: test_hash.c
@$(CC) test_hash.c -g -o test_hash.o -Wall -Wextra -pedantic -std=c11

clean:
@rm -rf *.dSYM *.swp
Binary file added assets/gosper-84.pdf
Binary file not shown.
Binary file added assets/life.xlsx
Binary file not shown.
197 changes: 89 additions & 108 deletions hashlife.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Node on = {1, 0, NULL, NULL, NULL, NULL};
Node off = {0, 0, NULL, NULL, NULL, NULL};
Node **hashtab;


/*** Node operations ***/
Node *join(const Node *a, const Node *b, const Node *c, const Node *d){
assert((a->k ^ b->k ^ c->k ^ d->k) == 0); // make sure all nodes are the same level
Expand All @@ -14,15 +15,13 @@ Node *join(const Node *a, const Node *b, const Node *c, const Node *d){
}


void init(){ hashtab = (Node **)calloc(MAX_NODES, sizeof(Node *)); }
void init(){
hashtab = (Node **)calloc(MAX_NODES, sizeof(Node *));
}

unsigned int node_hash(Node *a, Node *b, Node *c, Node *d) {
// TODO: is there a better way to hash?
unsigned int h = a->k + 2
+ 5131830419411 * (int)a
+ 3758991985019 * (int)b
+ 8973110871315 * (int)c
+ 4318490180473 * (int)d;
// Refer to test_hash.c for different hash methods
unsigned int h = 65537*(unsigned int)(d)+257*(unsigned int)(c)+17*(unsigned int)(b)+5*(unsigned int)(a);
return h % MAX_NODES;
}

Expand All @@ -34,25 +33,35 @@ Node *newnode(Node *a, Node *b, Node *c, Node *d){

// init value of node
int n = a->n + b->n + c->n + d->n;
node->n = n;
node->k = a->k+1;
node->n = n;
node->a = a;
node->b = b;
node->c = c;
node->d = d;
node->next = NULL;

int h = node_hash(a, b, c, d);
if (hashtab[h] != NULL){
log_info("Create: Hash collided");
node->next = hashtab[h];
}

hashtab[h] = node; // push in to hashtable
#if DEBUG
printf("Create new node: "); print_node(node);
#endif

log_info("Create new node: Node k=%d, %d x %d, population %d", node->k, 1 << node->k, 1 << node->k, node->n);
return node;
}

Node *find_node(Node *a, Node *b, Node *c, Node *d){
int h = node_hash(a, b, c, d);
Node *p = hashtab[h];
Node *p;
for (p=hashtab[h]; p; p = p->next) { /* make sure to compare a first */
if (p->a == a && p->b == b && p->c == c && p->d == d) {// In case hash collision compare its value
log_info("Find: hash collided");
return p ;
}
}
p = NULL;
return p;
}

Expand Down Expand Up @@ -87,9 +96,7 @@ Node *construct(int points[][2], int n){
for (int i=0; i < n; i++){
int x = points[i][0] - min_x;
int y = points[i][1] - min_y;
#if DEBUG
printf("construct x:%d, y:%d\n", x, y);
#endif
log_info("construct x:%d, y:%d", x, y);
pattern[i] = (MapNode){.p = ON, .x = x, .y = y};
}

Expand Down Expand Up @@ -139,12 +146,13 @@ Node *construct(int points[][2], int n){

Node *result = pattern->p;
free(pattern); // Can't let the garbage floatting around
return result;
result = pad(result);
log_info("Constructed node: Node k=%d, %d x %d, population %d", result->k, 1 << result->k, 1 << result->k, result->n);
return pad(result);
}


void mark(Node *node, int x, int y, int mx, int my){

// (mx, my) are not in this node
int size = 1 << node->k;
if (mx < x || mx > x + size || my < y || my > y + size)
Expand Down Expand Up @@ -176,15 +184,10 @@ void expand(Node *node, int x, int y){
if (x + size <= E.x || x >= E.x + E.screencols || y + size <= E.y || y >= E.y + E.screenrows)
return;


// TODO: add assert x, y are inside the view

// base case
if (node->k == 0){
E.grid[x][y] = 1;
#if DEBUG
printf("expand x:%d, y:%d\n", x, y);
#endif
E.grid[y][x] = 1;
log_info("expand x:%d, y:%d", x, y);
return;
}

Expand All @@ -196,27 +199,6 @@ void expand(Node *node, int x, int y){
}

Node *successor(Node *p, int j){
/*
* +---+---+---+---+++---+---+---+---+
* |aaa aab aba abb|||baa bab bba bbb|
* + + + + +++ + + + +
* |aac aad abc abd|||bac bad bbc bbd|
* + + + + +++ + + + +
* |aca acb ada|adb|||bca bcb bda bdb|
* + + + + +++ + + + +
* |acc acd adc add|||bcc bcd bdc bdd|
* +---+---+---+---+++---+---+---+---+
* +---+---+---+---+++---+---+---+---+
* |caa cab cba cbb|||daa dab dba dbb|
* + + + + +++ + + + +
* |cac cad cbc cbd|||dac dad dbc dbd|
* + + + + +++ + + + +
* |cca ccb cda cdb|||dca dcb dda ddb|
* + + + + +++ + + + +
* |ccc ccd cdc cdd|||dcc dcd ddc ddd|
* +---+---+---+---+++---+---+---+---+
*/

/*
* +--+--+--+--+
* |aa|ab|ba|bb|
Expand All @@ -229,13 +211,14 @@ Node *successor(Node *p, int j){
* +--+--+--+--+
*/

assert(p->k >=2);
Node *result;
if (p->n ==0)
result = p->a;
else if (p->k == 2)
result = life4x4(p);
else {
//j = j < p->k - 2 ? j : p->k -2;
j = j < p->k - 2 ? j : p->k -2;
Node *c1 = successor(join(p->a->a, p->a->b, p->a->c, p->a->d), j);
Node *c2 = successor(join(p->a->b, p->b->a, p->a->d, p->b->c), j);
Node *c3 = successor(join(p->b->a, p->b->b, p->b->c, p->b->d), j);
Expand All @@ -245,24 +228,29 @@ Node *successor(Node *p, int j){
Node *c7 = successor(join(p->c->a, p->c->b, p->c->c, p->c->d), j);
Node *c8 = successor(join(p->c->b, p->d->a, p->c->d, p->d->c), j);
Node *c9 = successor(join(p->d->a, p->d->b, p->d->c, p->d->d), j);
//if (j < p->k - 2){
result = join(
join(c1->d, c2->c, c4->b, c5->a),
join(c2->d, c3->c, c5->b, c6->a),
join(c4->d, c5->c, c7->b, c8->a),
join(c5->d, c6->c, c8->b, c9->a));
//} else {
// s = join(
// sucessor(join(c1->d, c2->c, c4->b, c5->a), j),
// sucessor(join(c2->d, c3->c, c5->b, c6->a), j),
// sucessor(join(c4->d, c5->c, c7->b, c8->a), j),
// sucessor(join(c5->d, c6->c, c8->b, c9->a), j));
//}
if (j < p->k - 2){
result = join(
join(c1->d, c2->c, c4->b, c5->a),
join(c2->d, c3->c, c5->b, c6->a),
join(c4->d, c5->c, c7->b, c8->a),
join(c5->d, c6->c, c8->b, c9->a));
} else {
result = join(
successor(join(c1->d, c2->c, c4->b, c5->a), j),
successor(join(c2->d, c3->c, c5->b, c6->a), j),
successor(join(c4->d, c5->c, c7->b, c8->a), j),
successor(join(c5->d, c6->c, c8->b, c9->a), j));
}
}
return result;
}

Node *advance(Node *p, int step){
Node *advance(Node *p, int n){
// TODO : add advance expansion
if (n==0)
return p;
p = centre(p); // p->k+=1
p = successor(p, 0); // p->k-=1
return p;
}

Expand All @@ -276,16 +264,17 @@ Node *life(Node *n1, Node *n2, Node *n3, Node *n4, Node *c, Node *n6, Node *n7,
* +--+--+--+
* |n7|n8|n9|
* +--+--+--+
*
* 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
* 2. Any live cell with two or three live neighbours lives on to the next generation.
* 3. Any live cell with more than three live neighbours dies, as if by overpopulation.
* 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
*/

// assert all node are level 0;
assert(n1->k ^ n2->k ^ n3->k ^ n4->k ^ c->k ^ n6->k ^ n7->k ^ n8->k ^ n9 ->k == 0 && n1->k == 0);
int nb = n1->n + n2->n + n3->n + n4->n +
n6->n + n7->n + n8->n + n9->n;
if ((c->n == 1 && nb == 2) || nb == 3)
return ON;
else
return OFF;
int nb = n1->n + n2->n + n3->n + n4->n + n6->n + n7->n + n8->n + n9->n;
return ((c->n == 1 && nb == 2) || nb == 3) ? ON : OFF;
}

Node *life4x4(Node *p){
Expand Down Expand Up @@ -327,14 +316,14 @@ Node *inner(Node *p){
}

Node *crop(Node *p){
if (p->k <= 3 || ! is_padded(p))
if (p->k <= 3 || !is_padded(p))
return p;
else
return crop(inner(p));
}

Node *centre(Node *p){
Node *z = get_zero(p->k-1);
Node *z = get_zero(p->k - 1);
return join(
join(z, z, z, p->a),
join(z, z, p->b, z),
Expand All @@ -353,24 +342,19 @@ void print_node(const Node *node){
printf("Node k=%d, %d x %d, population %d\n", node->k, 1 << node->k, 1 << node->k, node->n);
}

void reset(){
// free
for ( int i = 0; i < E.gridcols; i++ )
free(E.grid[i]);
free(E.grid);

// re-allocte with zeros
E.grid = calloc( E.gridcols, sizeof(int *) );
for ( int i = 0; i < E.gridcols; i++ )
E.grid[i] = calloc( E.gridrows, sizeof(int) );
}

void render(Node *p){
reset();
expand(p, 0, 0);
int next_prime(int i) {
int j ;
i |= 1 ;
for (;; i+=2) {
for (j=3; j*j<=i; j+=2)
if (i % j == 0)
break ;
if (j*j > i)
return i ;
}
}


/*** Tests ***/
void test_get_zero(){
Node *p = get_zero(3);
Expand Down Expand Up @@ -400,9 +384,7 @@ void test_construct(){
// for (int x = 0; x < E.gridcols; x++){
// for (int y = 0; y < E.gridrows ; y++){
// if (E.grid[x][y] == 1){
//#if DEBUG
// printf("grid x:%d, y:%d\n", x, y);
//#endif
// log_info("grid x:%d, y:%d", x, y);
// }
// }
// }
Expand Down Expand Up @@ -443,28 +425,28 @@ void test_life4x4(){
int points[4][2] = {{0, 0}, {2, 1}, {2, 2}, {2, 3}};

Node *p = construct(points, 4);
printf("The constructed node is: "); print_node(p);
log_info("The constructed node is: "); print_node(p);
expand(p, 0, 0);
p = life4x4(p);
printf("The out node is: "); print_node(p);
log_info("The out node is: "); print_node(p);
expand(p, 0, 0);
}


void test_centre(){
Node *p = join(OFF, OFF, OFF, OFF);
printf("Node before centre: "); print_node(p);
log_info("Node before centre: "); print_node(p);
p = centre(p);
printf("Node after centre: "); print_node(p);
log_info("Node after centre: "); print_node(p);
expand(p, 0, 0);
}


void test_pad(){
Node *p = join(ON, OFF, OFF, OFF);
printf("Node before centre: "); print_node(p);
log_info("Node before centre: "); print_node(p);
p = pad(p);
printf("Node after centre: "); print_node(p);
log_info("Node after centre: "); print_node(p);
expand(p, 0, 0);
}

Expand All @@ -473,16 +455,27 @@ void test_successor(){
int points[4][2] = {{0, 0}, {4, 1}, {4, 2}, {4, 3}};

Node *p = construct(points, 4);
printf("Before update: "); print_node(p);
log_info("Before update: "); print_node(p);
expand(p, 0, 0);
p = successor(p, 0);
printf("After update1: ");print_node(p);
log_info("After update1: ");print_node(p);
expand(p, 0, 0);
p = successor(p, 0);
printf("After update2: ");print_node(p);
log_info("After update2: ");print_node(p);
expand(p, 0, 0);

}

void test_new_collided(){
// In order for this test to work, hardcode the hash_node to return h=2 in find_node and newnnode funciton
Node *n1 = newnode(ON, ON, ON, ON);
print_node(n1);
Node *n2 = newnode(OFF, OFF, OFF, OFF);
print_node(n2);
printf("Popullation needs to be 0: "); print_node(hashtab[2]); // n2
printf("Popullation needs to be 4: "); print_node(hashtab[2]->next); // n1
//print_node(hashtab[2]->next->next); // NULL
expand(n2, 0, 0);
}

void init_e(){
Expand All @@ -501,15 +494,3 @@ void init_e(){
E.grid[i] = calloc( E.gridrows, sizeof(int) );
}

//int main(){
// init();
// init_e();
// //test_construct();
// //test_expand();
// //test_life();
// //test_life4x4();
// //test_centre();
// test_successor();
// return 0;
//}
//
Loading

0 comments on commit 51ed5ae

Please sign in to comment.