Example #1
0
std::vector<unsigned int> some_random_configuration (unsigned int N_filled, const Lattice &lattice, RandomNumberGenerator &rng)
{
    BOOST_ASSERT(N_filled <= lattice.total_sites());

    const unsigned int n_dimensions = lattice.n_dimensions();

    // If in more than one dimension, occasionally we want to try placing
    // particles such that they are distributed as well as possible over a
    // certain dimension (rungs, legs, etc).  For determinantal wavefunctions
    // with certain orbital configurations, this can often be necessary to find
    // a non-zero amplitude in a reasonable amount of time.
    //
    // This method could be further optimized, but it is fast enough for now
    // (and is unlikely to be the bottleneck anyway).
    if (n_dimensions > 1 && rng.random_small_uint(3) == 0) {
        std::vector<unsigned int> v;
        std::set<unsigned int> vs;
        unsigned int spread_dimension = rng.random_small_uint(n_dimensions);
        unsigned int remaining = N_filled;
        while (remaining != 0) {
            std::vector<unsigned int> spread_coordinate;
            random_combination(spread_coordinate,
                               std::min(remaining, (unsigned int) lattice.dimensions[spread_dimension]),
                               lattice.dimensions[spread_dimension], rng);
            for (unsigned int i = 0; i < spread_coordinate.size(); ++i) {
                unsigned int proposed_site_index;
                do {
                    LatticeSite proposed_site(lattice.n_dimensions());
                    proposed_site[spread_dimension] = spread_coordinate[i];
                    for (unsigned int j = 0; j < n_dimensions; ++j) {
                        if (j != spread_dimension)
                            proposed_site[j] = rng.random_small_uint(lattice.dimensions[j]);
                    }
                    proposed_site.basis_index = rng.random_small_uint(lattice.basis_indices);
                    proposed_site_index = lattice.site_to_index(proposed_site);
                } while (!vs.insert(proposed_site_index).second); // try again until successful
                v.push_back(proposed_site_index);
            }
            remaining -= spread_coordinate.size();
        }
        return v;
    }

    // otherwise, fall back to just blindly choosing a random combination of sites
    std::vector<unsigned int> v;
    random_combination(v, N_filled, lattice.total_sites(), rng);
    return v;
}
Example #2
0
// http://stackoverflow.com/questions/2394246/algorithm-to-select-a-single-random-combination-of-values
void random_combination (std::vector<unsigned int> &v, unsigned int r, unsigned int n, RandomNumberGenerator &rng, unsigned int keep)
{
    // per Jon Bentley's article in CACM, September 1987, Volume 30, Number 9
    BOOST_ASSERT(n > 0);
    BOOST_ASSERT(r > 0);
    BOOST_ASSERT(r <= n);
    BOOST_ASSERT(keep <= n);
    BOOST_ASSERT(v.size() >= keep);

    if (n == r && keep == 0) {
        // the loop below fails if k == 0 is ever true, so here we handle the
        // only special case that could cause that
        v.resize(r);
        for (unsigned int i = 0; i < r; ++i)
            v[i] = i;
        return;
    }

    std::set<int> vs;
    v.resize(keep);
    v.reserve(r);
    for (std::vector<unsigned int>::const_iterator i = v.begin(); i != v.end(); ++i)
        vs.insert(*i);
    BOOST_ASSERT(v.size() == vs.size());

    for (unsigned int k = n - r + keep; k < n; ++k) {
        BOOST_ASSERT(k > 0);
        unsigned int x = rng.random_small_uint(k);
        unsigned int a = (vs.find(x) != vs.end()) ? k : x;
        v.push_back(a);
        vs.insert(a);
    }

    BOOST_ASSERT(v.size() == r);
}
Example #3
0
probability_t BaseSwapPossibleWalk::compute_probability_ratio_of_random_transition (RandomNumberGenerator &rng)
{
    BOOST_ASSERT(!transition_in_progress);
    transition_in_progress = true;

    const Lattice &lattice = phialpha1->get_lattice();
    const Subsystem &subsystem = swapped_system->get_subsystem();

    // decide which (zero-indexed) copy of the system to base this move around.
    // We call the chosen copy "copy A."
    const unsigned int copy_A = rng.random_small_uint(2);

    const PositionArguments &r_A = (copy_A == 0) ? phialpha1->get_positions() : phialpha2->get_positions();
    const PositionArguments &r_B = (copy_A == 0) ? phialpha2->get_positions() : phialpha1->get_positions();

    // first choose a random move in copy A
    chosen_particle_A = choose_random_particle(r_A, rng);
    const unsigned int particle_A_destination = plan_particle_move_to_nearby_empty_site(chosen_particle_A, r_A, lattice, rng);

    if (r_A[chosen_particle_A] == particle_A_destination) {
        autoreject_in_progress = true;
        return 0;
    }

    // If the particle we are moving in copy A is not going to change its
    // subsystem status, then we go ahead and make that move.  If, however, the
    // particle we are moving in copy A changes its subsystem status (i.e.,
    // enters or leaves the subsystem), then we must also choose a move in copy
    // B that does likewise, and take into account the transition probability
    // ratio so that the simulation maintains balance.

    unsigned int particle_B_destination = -1; // uninitialized
    real_t transition_ratio(1);

    const int copy_A_subsystem_particle_change = calculate_subsystem_particle_change(swapped_system->get_subsystem(), r_A[chosen_particle_A], particle_A_destination, lattice);
    const unsigned int species = chosen_particle_A.species;
    if (copy_A_subsystem_particle_change != 0) {
        const bool candidate_particle_B_subsystem_status = (copy_A_subsystem_particle_change == -1);

        // determine reverse/forward transition attempt probability ratios
        const unsigned int N_sites = r_A.get_N_sites();
        const unsigned int N_filled = r_A.get_N_filled(species);
        const unsigned int N_within_subsystem = swapped_system->get_N_subsystem(species);
        const unsigned int N_outside_subsystem = N_filled - N_within_subsystem;
        const unsigned int N_vacant_within_subsystem = N_subsystem_sites - N_within_subsystem;
        const unsigned int N_vacant_outside_subsystem = (N_sites - N_filled) - N_vacant_within_subsystem;
        unsigned int forward_particle_possibilities, forward_vacant_possibilities,
            reverse_particle_possibilities, reverse_vacant_possibilities;
        if (copy_A_subsystem_particle_change == 1) {
            forward_particle_possibilities = N_outside_subsystem;
            forward_vacant_possibilities = N_vacant_within_subsystem;
            reverse_particle_possibilities = N_within_subsystem + 1;
            reverse_vacant_possibilities = N_vacant_outside_subsystem + 1;
        } else {
            BOOST_ASSERT(copy_A_subsystem_particle_change == -1);
            forward_particle_possibilities = N_within_subsystem;
            forward_vacant_possibilities = N_vacant_outside_subsystem;
            reverse_particle_possibilities = N_outside_subsystem + 1;
            reverse_vacant_possibilities = N_vacant_within_subsystem + 1;
        }
        if (forward_particle_possibilities == 0 || forward_vacant_possibilities == 0) {
            autoreject_in_progress = true;
            return 0;
        }
        transition_ratio = real_t(forward_particle_possibilities * forward_vacant_possibilities) / real_t(reverse_particle_possibilities * reverse_vacant_possibilities);

        // choose a particle from B with the same subsystem status as the
        // particle we are moving in A
        std::vector<unsigned int> candidate_particle_B_array;
        candidate_particle_B_array.reserve(forward_particle_possibilities);
        for (unsigned int i = 0; i < N_filled; ++i) {
            if (subsystem.position_is_within(r_B[Particle(i, species)], lattice) == candidate_particle_B_subsystem_status)
                candidate_particle_B_array.push_back(i);
        }
        BOOST_ASSERT(forward_particle_possibilities == candidate_particle_B_array.size());
        chosen_particle_B = Particle(candidate_particle_B_array[rng.random_small_uint(candidate_particle_B_array.size())], species);

        // choose a destination such that the particle in copy B will change its
        // subsystem status
        const bool destination_B_in_subsystem = !candidate_particle_B_subsystem_status;
        std::vector<unsigned int> candidate_destination_B_array;
        candidate_destination_B_array.reserve(forward_vacant_possibilities);
        for (unsigned int i = 0; i < N_sites; ++i) {
            if (!r_B.is_occupied(i, species) && subsystem.position_is_within(i, lattice) == destination_B_in_subsystem)
            candidate_destination_B_array.push_back(i);
        }
        BOOST_ASSERT(forward_vacant_possibilities == candidate_destination_B_array.size());
        particle_B_destination = candidate_destination_B_array[rng.random_small_uint(candidate_destination_B_array.size())];
    }

    // translate from "copy A or B" language back to "copy 1 or 2"
    const Particle * const chosen_particle_B_ptr = (copy_A_subsystem_particle_change != 0) ? &chosen_particle_B : 0;
    chosen_particle1 = (copy_A == 0) ? &chosen_particle_A : chosen_particle_B_ptr;
    chosen_particle2 = (copy_A == 0) ? chosen_particle_B_ptr : &chosen_particle_A;

    // move particles, determining phialpha probability ratios
    amplitude_t phialpha1_ratio(1), phialpha2_ratio(1);
    if (chosen_particle1) {
        const Big<amplitude_t> old_phialpha1_psi(phialpha1->psi());
        if (!phialpha1.unique()) // copy-on-write
            phialpha1 = phialpha1->clone();
        Move move;
        move.push_back(SingleParticleMove(*chosen_particle1, (copy_A == 0) ? particle_A_destination : particle_B_destination));
        phialpha1->perform_move(move);
        phialpha1_ratio = phialpha1->psi().ratio(old_phialpha1_psi);
    }
    if (chosen_particle2) {
        const Big<amplitude_t> old_phialpha2_psi(phialpha2->psi());
        if (!phialpha2.unique()) // copy-on-write
            phialpha2 = phialpha2->clone();
        Move move;
        move.push_back(SingleParticleMove(*chosen_particle2, (copy_A == 0) ? particle_B_destination : particle_A_destination));
        phialpha2->perform_move(move);
        phialpha2_ratio = phialpha2->psi().ratio(old_phialpha2_psi);
    }

    amplitude_t phibeta1_ratio(0), phibeta2_ratio(0);

    if (update_swapped_system_before_accepting) {
        // remember old phibeta's
        const Big<amplitude_t> old_phibeta1_psi(swapped_system->get_phibeta1().psi());
        const Big<amplitude_t> old_phibeta2_psi(swapped_system->get_phibeta2().psi());
        // implement copy-on-write
        if (!swapped_system.unique())
            swapped_system = boost::make_shared<SwappedSystem>(*swapped_system);
        // update phibeta's
        swapped_system->update(chosen_particle1, chosen_particle2, *phialpha1, *phialpha2);
        // determine probability ratios
        phibeta1_ratio = swapped_system->get_phibeta1().psi().ratio(old_phibeta1_psi);
        phibeta2_ratio = swapped_system->get_phibeta2().psi().ratio(old_phibeta2_psi);
    }

    // return a probability
    return transition_ratio * probability_ratio(phialpha1_ratio, phialpha2_ratio, phibeta1_ratio, phibeta2_ratio);
}