Пример #1
0
/* 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;
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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);
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
/*
 * 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);
}
Пример #9
0
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
}