/* Returns a test case which is a sequence of 'values' insertions, * and then a random mix of 'search_successes' searches for values actually inserted * and 'search_failures' searches for values never inserted. */ test_case insert_then_search( int values, int search_successes, int search_failures, unsigned int seed ) { std::mt19937 rng(seed); test_case ret( values + search_successes + search_failures ); /* Simple trick to guarantee success/failure: * the values inserted will all be even, * and the search failures will all be odd. * * To guarantee no value is inserted twice, * we will simply insert all value from 2 to 2*values. * and shuffle the operation. */ for( int i = 0; i < values; i++ ) ret[i] = operation{ operation_type::insert, 2 * i + 2 }; std::shuffle( ret.begin(), ret.begin() + values, rng ); std::uniform_int_distribution<> success(1, values); std::uniform_int_distribution<> failure(0, values); auto bits = random_bits(search_failures, search_successes, rng); for( int i = 0; i < search_successes + search_failures; i++ ) if( bits[i] ) ret[i + values] = operation{ operation_type::count, 2*success(rng) }; else ret[i + values] = operation{ operation_type::count, 2*failure(rng) + 1}; return ret; }
test_case mixed_workload( int initial_insertions, int total_insertions, int removals, int search_successes, int search_failures, unsigned int seed ) { std::mt19937 rng(seed); test_case ret( total_insertions + removals + search_successes + search_failures ); auto rem = efficiently_choose_target_to_remove{ std::vector<std::pair<int,bool>>(initial_insertions), initial_insertions }; for( int i = 0; i < total_insertions; i++ ) ret[i] = operation{ operation_type::insert, 2 * i + 2 }; std::shuffle( ret.begin(), ret.begin() + total_insertions, rng ); /* The first initial_insertions values will not be changed anymore. * The other values will be shuffled together with the other values. */ for( int i = 0; i < initial_insertions; i++ ) rem.keys[i] = std::make_pair( ret[i].key, true ); // rem is usable. for( int i = 0; i < removals; i++ ) ret[i+total_insertions].type = operation_type::erase; for( int i = 0; i < search_successes + search_failures; i++ ) ret[i+total_insertions+removals].type = operation_type::count; std::shuffle( ret.begin()+initial_insertions, ret.end(), rng ); /* All the operation types are correctly set, * and every insert operation has the correct key set. * Now, we will set the keys of the removals and the searches. */ auto bits = random_bits(search_failures, search_successes, rng); int decision = 0; std::uniform_int_distribution<> failure(0, total_insertions); for( int i = initial_insertions; i < ret.size(); i++ ) { switch( ret[i].type ) { case operation_type::insert: rem.push_key( ret[i].key ); break; case operation_type::erase: ret[i].key = rem.get_key(rng); break; case operation_type::count: if( bits[decision++] ) ret[i].key = rem.peek_key(rng); else ret[i].key = 2*failure(rng) + 1; break; } } return ret; }
int work_bpsk_c(_Complex float *output, int block_size) { int j; random_bits(tmp_binary,block_size); for (j=0;j<block_size;j++) { if (tmp_binary[j]) { __real__ output[j] = BPSK_SYMB; } else { __real__ output[j] = -BPSK_SYMB; } } random_bits(tmp_binary,block_size); for (j=0;j<block_size;j++) { if (tmp_binary[j]) { __imag__ output[j] = BPSK_SYMB; } else { __imag__ output[j] = -BPSK_SYMB; } } return block_size*sizeof(_Complex float); }
int work_bpsk_re(float *output, int block_size) { int j; random_bits(tmp_binary,block_size); for (j=0;j<block_size;j++) { if (tmp_binary[j]) { output[j] = BPSK_SYMB; } else { output[j] = -BPSK_SYMB; } } return block_size*sizeof(float); }
int work_binary(char *output, int block_size) { int j; for (j=0;j<block_size;j++) { switch(TYPE) { case RAND: output[j] = rand()%2; break; case FIXED: output[j] = j%2; break; case SEQ: random_bits(tmp_binary,block_size); output[j] = tmp_binary[j]; break; } } return block_size; }
test_case insert_then_remove_then_search( int insertions, int removals, int search_successes, int search_failures, unsigned int seed ) { std::mt19937 rng(seed); test_case ret( insertions + search_successes + search_failures + removals ); auto rem = efficiently_choose_target_to_remove{ std::vector<std::pair<int,bool>>(insertions), insertions }; // Generate the insertions for( int i = 0; i < insertions; i++ ) { ret[i] = operation{ operation_type::insert, 2 * i + 2 }; rem.keys[i] = std::make_pair( 2 * i + 2, true ); } std::shuffle( ret.begin(), ret.begin() + insertions, rng ); // Generate the removals for( int i = 0; i < removals; i++ ) ret[i+insertions] = operation{ operation_type::erase, rem.get_key(rng) }; // Generate the searches std::uniform_int_distribution<> success_index(0, rem.keys.size()-1); std::uniform_int_distribution<> failure(0, insertions); auto bits = random_bits(search_failures, search_successes, rng); for( int i = 0; i < search_successes + search_failures; i++ ) if( bits[i] ) ret[i + insertions+removals] = operation{ operation_type::count, rem.keys[success_index(rng)].first }; else ret[i + insertions+removals] = operation{ operation_type::count, 2*failure(rng) + 1}; return ret; }
test_case ascending_insert_then_search( int values, int search_successes, int search_failures, unsigned int seed ) { std::mt19937 rng(seed); test_case ret( values + search_successes + search_failures ); for( int i = 0; i < values; i++ ) ret[i] = operation{ operation_type::insert, 2 * i + 2 }; std::uniform_int_distribution<> success(1, values); std::uniform_int_distribution<> failure(0, values); auto bits = random_bits(search_failures, search_successes, rng); for( int i = 0; i < search_successes + search_failures; i++ ) if( bits[i] ) ret[i + values] = operation{ operation_type::count, 2*success(rng) }; else ret[i + values] = operation{ operation_type::count, 2*failure(rng) + 1}; return ret; }
/* * Generate a new complete random closed loop for the given grid. * * The method is to generate a WHITE/BLACK colouring of all the faces, * such that the WHITE faces will define the inside of the path, and the * BLACK faces define the outside. * To do this, we initially colour all faces GREY. The infinite space outside * the grid is coloured BLACK, and we choose a random face to colour WHITE. * Then we gradually grow the BLACK and the WHITE regions, eliminating GREY * faces, until the grid is filled with BLACK/WHITE. As we grow the regions, * we avoid creating loops of a single colour, to preserve the topological * shape of the WHITE and BLACK regions. * We also try to make the boundary as loopy and twisty as possible, to avoid * generating paths that are uninteresting. * The algorithm works by choosing a BLACK/WHITE colour, then choosing a GREY * face that can be coloured with that colour (without violating the * topological shape of that region). It's not obvious, but I think this * algorithm is guaranteed to terminate without leaving any GREY faces behind. * Indeed, if there are any GREY faces at all, both the WHITE and BLACK * regions can be grown. * This is checked using assert()ions, and I haven't seen any failures yet. * * Hand-wavy proof: imagine what can go wrong... * * Could the white faces get completely cut off by the black faces, and still * leave some grey faces remaining? * No, because then the black faces would form a loop around both the white * faces and the grey faces, which is disallowed because we continually * maintain the correct topological shape of the black region. * Similarly, the black faces can never get cut off by the white faces. That * means both the WHITE and BLACK regions always have some room to grow into * the GREY regions. * Could it be that we can't colour some GREY face, because there are too many * WHITE/BLACK transitions as we walk round the face? (see the * can_colour_face() function for details) * No. Imagine otherwise, and we see WHITE/BLACK/WHITE/BLACK as we walk * around the face. The two WHITE faces would be connected by a WHITE path, * and the BLACK faces would be connected by a BLACK path. These paths would * have to cross, which is impossible. * Another thing that could go wrong: perhaps we can't find any GREY face to * colour WHITE, because it would create a loop-violation or a corner-violation * with the other WHITE faces? * This is a little bit tricky to prove impossible. Imagine you have such a * GREY face (that is, if you coloured it WHITE, you would create a WHITE loop * or corner violation). * That would cut all the non-white area into two blobs. One of those blobs * must be free of BLACK faces (because the BLACK stuff is a connected blob). * So we have a connected GREY area, completely surrounded by WHITE * (including the GREY face we've tentatively coloured WHITE). * A well-known result in graph theory says that you can always find a GREY * face whose removal leaves the remaining GREY area connected. And it says * there are at least two such faces, so we can always choose the one that * isn't the "tentative" GREY face. Colouring that face WHITE leaves * everything nice and connected, including that "tentative" GREY face which * acts as a gateway to the rest of the non-WHITE grid. */ void generate_loop(grid *g, char *board, random_state *rs, loopgen_bias_fn_t bias, void *biasctx) { int i, j; int num_faces = g->num_faces; struct face_score *face_scores; /* Array of face_score objects */ struct face_score *fs; /* Points somewhere in the above list */ struct grid_face *cur_face; tree234 *lightable_faces_sorted; tree234 *darkable_faces_sorted; int *face_list; int do_random_pass; /* Make a board */ memset(board, FACE_GREY, num_faces); /* Create and initialise the list of face_scores */ face_scores = snewn(num_faces, struct face_score); for (i = 0; i < num_faces; i++) { face_scores[i].random = random_bits(rs, 31); face_scores[i].black_score = face_scores[i].white_score = 0; } /* Colour a random, finite face white. The infinite face is implicitly * coloured black. Together, they will seed the random growth process * for the black and white areas. */ i = random_upto(rs, num_faces); board[i] = FACE_WHITE; /* We need a way of favouring faces that will increase our loopiness. * We do this by maintaining a list of all candidate faces sorted by * their score and choose randomly from that with appropriate skew. * In order to avoid consistently biasing towards particular faces, we * need the sort order _within_ each group of scores to be completely * random. But it would be abusing the hospitality of the tree234 data * structure if our comparison function were nondeterministic :-). So with * each face we associate a random number that does not change during a * particular run of the generator, and use that as a secondary sort key. * Yes, this means we will be biased towards particular random faces in * any one run but that doesn't actually matter. */ lightable_faces_sorted = newtree234(white_sort_cmpfn); darkable_faces_sorted = newtree234(black_sort_cmpfn); /* Initialise the lists of lightable and darkable faces. This is * slightly different from the code inside the while-loop, because we need * to check every face of the board (the grid structure does not keep a * list of the infinite face's neighbours). */ for (i = 0; i < num_faces; i++) { grid_face *f = g->faces + i; struct face_score *fs = face_scores + i; if (board[i] != FACE_GREY) continue; /* We need the full colourability check here, it's not enough simply * to check neighbourhood. On some grids, a neighbour of the infinite * face is not necessarily darkable. */ if (can_colour_face(g, board, i, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } if (can_colour_face(g, board, i, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } } /* Colour faces one at a time until no more faces are colourable. */ while (TRUE) { enum face_colour colour; tree234 *faces_to_pick; int c_lightable = count234(lightable_faces_sorted); int c_darkable = count234(darkable_faces_sorted); if (c_lightable == 0 && c_darkable == 0) { /* No more faces we can use at all. */ break; } assert(c_lightable != 0 && c_darkable != 0); /* Choose a colour, and colour the best available face * with that colour. */ colour = random_upto(rs, 2) ? FACE_WHITE : FACE_BLACK; if (colour == FACE_WHITE) faces_to_pick = lightable_faces_sorted; else faces_to_pick = darkable_faces_sorted; if (bias) { /* * Go through all the candidate faces and pick the one the * bias function likes best, breaking ties using the * ordering in our tree234 (which is why we replace only * if score > bestscore, not >=). */ int j, k; struct face_score *best = NULL; int score, bestscore = 0; for (j = 0; (fs = (struct face_score *)index234(faces_to_pick, j))!=NULL; j++) { assert(fs); k = fs - face_scores; assert(board[k] == FACE_GREY); board[k] = colour; score = bias(biasctx, board, k); board[k] = FACE_GREY; bias(biasctx, board, k); /* let bias know we put it back */ if (!best || score > bestscore) { bestscore = score; best = fs; } } fs = best; } else { fs = (struct face_score *)index234(faces_to_pick, 0); } assert(fs); i = fs - face_scores; assert(board[i] == FACE_GREY); board[i] = colour; if (bias) bias(biasctx, board, i); /* notify bias function of the change */ /* Remove this newly-coloured face from the lists. These lists should * only contain grey faces. */ del234(lightable_faces_sorted, fs); del234(darkable_faces_sorted, fs); /* Remember which face we've just coloured */ cur_face = g->faces + i; /* The face we've just coloured potentially affects the colourability * and the scores of any neighbouring faces (touching at a corner or * edge). So the search needs to be conducted around all faces * touching the one we've just lit. Iterate over its corners, then * over each corner's faces. For each such face, we remove it from * the lists, recalculate any scores, then add it back to the lists * (depending on whether it is lightable, darkable or both). */ for (i = 0; i < cur_face->order; i++) { grid_dot *d = cur_face->dots[i]; for (j = 0; j < d->order; j++) { grid_face *f = d->faces[j]; int fi; /* face index of f */ if (f == NULL) continue; if (f == cur_face) continue; /* If the face is already coloured, it won't be on our * lightable/darkable lists anyway, so we can skip it without * bothering with the removal step. */ if (FACE_COLOUR(f) != FACE_GREY) continue; /* Find the face index and face_score* corresponding to f */ fi = f - g->faces; fs = face_scores + fi; /* Remove from lightable list if it's in there. We do this, * even if it is still lightable, because the score might * be different, and we need to remove-then-add to maintain * correct sort order. */ del234(lightable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } /* Do the same for darkable list. */ del234(darkable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } } } } /* Clean up */ freetree234(lightable_faces_sorted); freetree234(darkable_faces_sorted); sfree(face_scores); /* The next step requires a shuffled list of all faces */ face_list = snewn(num_faces, int); for (i = 0; i < num_faces; ++i) { face_list[i] = i; } shuffle(face_list, num_faces, sizeof(int), rs); /* The above loop-generation algorithm can often leave large clumps * of faces of one colour. In extreme cases, the resulting path can be * degenerate and not very satisfying to solve. * This next step alleviates this problem: * Go through the shuffled list, and flip the colour of any face we can * legally flip, and which is adjacent to only one face of the opposite * colour - this tends to grow 'tendrils' into any clumps. * Repeat until we can find no more faces to flip. This will * eventually terminate, because each flip increases the loop's * perimeter, which cannot increase for ever. * The resulting path will have maximal loopiness (in the sense that it * cannot be improved "locally". Unfortunately, this allows a player to * make some illicit deductions. To combat this (and make the path more * interesting), we do one final pass making random flips. */ /* Set to TRUE for final pass */ do_random_pass = FALSE; while (TRUE) { /* Remember whether a flip occurred during this pass */ int flipped = FALSE; for (i = 0; i < num_faces; ++i) { int j = face_list[i]; enum face_colour opp = (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE; if (can_colour_face(g, board, j, opp)) { grid_face *face = g->faces +j; if (do_random_pass) { /* final random pass */ if (!random_upto(rs, 10)) board[j] = opp; } else { /* normal pass - flip when neighbour count is 1 */ if (face_num_neighbours(g, board, face, opp) == 1) { board[j] = opp; flipped = TRUE; } } } } if (do_random_pass) break; if (!flipped) do_random_pass = TRUE; } sfree(face_list); }
static void cmd_write(struct g_bde_key *gl, struct g_bde_softc *sc, int dfd , int key, const char *l_opt) { int i, ffd; uint64_t off[2]; u_char keyloc[16]; u_char *sbuf, *q; off_t offset, offset2; sbuf = malloc(gl->sectorsize); /* * Find the byte-offset in the lock sector where we will put the lock * data structure. We can put it any random place as long as the * structure fits. */ for(;;) { random_bits(off, sizeof off); off[0] &= (gl->sectorsize - 1); if (off[0] + G_BDE_LOCKSIZE > gl->sectorsize) continue; break; } /* Add the sector offset in bytes */ off[0] += (gl->lsector[key] & ~(gl->sectorsize - 1)); gl->lsector[key] = off[0]; i = g_bde_keyloc_encrypt(sc->sha2, off[0], off[1], keyloc); if (i) errx(1, "g_bde_keyloc_encrypt()"); if (l_opt != NULL) { ffd = open(l_opt, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (ffd < 0) err(1, "%s", l_opt); write(ffd, keyloc, sizeof keyloc); close(ffd); } else if (gl->flags & GBDE_F_SECT0) { offset2 = lseek(dfd, 0, SEEK_SET); if (offset2 != 0) err(1, "lseek"); i = read(dfd, sbuf, gl->sectorsize); if (i != (int)gl->sectorsize) err(1, "read"); memcpy(sbuf + key * 16, keyloc, sizeof keyloc); offset2 = lseek(dfd, 0, SEEK_SET); if (offset2 != 0) err(1, "lseek"); i = write(dfd, sbuf, gl->sectorsize); if (i != (int)gl->sectorsize) err(1, "write"); } else { errx(1, "No -L option and no space in sector 0 for lockfile"); } /* Allocate a sectorbuffer and fill it with random junk */ if (sbuf == NULL) err(1, "malloc"); random_bits(sbuf, gl->sectorsize); /* Fill random bits in the spare field */ random_bits(gl->spare, sizeof(gl->spare)); /* Encode the structure where we want it */ q = sbuf + (off[0] % gl->sectorsize); i = g_bde_encode_lock(sc->sha2, gl, q); if (i < 0) errx(1, "programming error encoding lock"); encrypt_sector(q, G_BDE_LOCKSIZE, 256, sc->sha2 + 16); offset = gl->lsector[key] & ~(gl->sectorsize - 1); offset2 = lseek(dfd, offset, SEEK_SET); if (offset2 != offset) err(1, "lseek"); i = write(dfd, sbuf, gl->sectorsize); if (i != (int)gl->sectorsize) err(1, "write"); free(sbuf); #if 0 printf("Wrote key %d at %jd\n", key, (intmax_t)offset); printf("s0 = %jd\n", (intmax_t)gl->sector0); printf("sN = %jd\n", (intmax_t)gl->sectorN); printf("l[0] = %jd\n", (intmax_t)gl->lsector[0]); printf("l[1] = %jd\n", (intmax_t)gl->lsector[1]); printf("l[2] = %jd\n", (intmax_t)gl->lsector[2]); printf("l[3] = %jd\n", (intmax_t)gl->lsector[3]); printf("k = %jd\n", (intmax_t)gl->keyoffset); printf("ss = %jd\n", (intmax_t)gl->sectorsize); #endif }