Esempio n. 1
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);
}
Esempio n. 2
0
AmplitudeType BasicOperatorEvaluator::evaluate (const typename Wavefunction<AmplitudeType>::Amplitude &wfa, const BoundaryConditions<AmplitudeType> &bcs) const
{
    typedef AmplitudeType PhaseType;

    assert(&wfa.get_lattice() == m_operator.lattice.get());
    assert(wfa.get_positions().get_N_species() >= min_required_species);

    const PositionArguments &r = wfa.get_positions();
    const Lattice &lattice = wfa.get_lattice();
    const bool is_sum_over_sites = (bcs.size() != 0);

    AmplitudeType meas = 0;

    const Big<AmplitudeType> old_psi(wfa.psi());

    // we only iterate if doing a sum, and even then we only want to iterate
    // over BraivaisSite's
    const unsigned int n_iterations = is_sum_over_sites ? lattice.total_sites() / lattice.basis_indices : 1;

    // FIXME: need a faster way of iterating the lattice
    for (unsigned int i = 0; i < n_iterations; ++i) {
        const LatticeSite site_offset(lattice[i]);
        // we only want to iterate over BravaisSite's
        assert(site_offset.basis_index == 0);

        PhaseType phase = 1;

        Move move;
        for (unsigned int j = 0; j < m_operator.hopv.size(); ++j) {
            PhaseType srcphase;
            const unsigned int species = m_operator.hopv[j].get_species();
            LatticeSite src(m_operator.hopv[j].get_source());
            lattice.asm_add_site_vector(src, site_offset.bravais_site());
            assert(is_sum_over_sites || lattice.site_is_valid(src));
            srcphase = lattice.enforce_boundary(src, bcs);
            if (srcphase == PhaseType(0))
                goto current_measurement_is_zero;
            const int particle_index = r.particle_index_at_position(lattice.index(src), species);
            if (particle_index < 0)
                goto current_measurement_is_zero;
            if (m_operator.hopv[j].get_source() != m_operator.hopv[j].get_destination()) {
                LatticeSite dest(m_operator.hopv[j].get_destination());
                lattice.asm_add_site_vector(dest, site_offset.bravais_site());
                assert(is_sum_over_sites || lattice.site_is_valid(dest));
                phase *= lattice.enforce_boundary(dest, bcs) / srcphase;
                if (phase == PhaseType(0))
                    goto current_measurement_is_zero;
                const unsigned int dest_index = lattice.index(dest);
                if (r.is_occupied(dest_index, species))
                    goto current_measurement_is_zero;
                move.push_back(SingleParticleMove(Particle(particle_index, species), dest_index));
            }
        }

        // now perform the move (if necessary)
        if (move.size() != 0) {
            BasicOperatorEvaluatorLocal::TemporaryMove<AmplitudeType> temp_move(wfa, move);
            // fixme: check logic of multiplying by phase (c.f. above), as
            // well as logic of source and destination
            meas += vmc_conj(phase * wfa.psi().ratio(old_psi));
        } else {
            meas += 1;
        }

    current_measurement_is_zero: ;
    }

    return meas;
}
Esempio n. 3
0
void SwappedSystem::update (const Particle *particle1, const Particle *particle2, const Wavefunction<amplitude_t>::Amplitude &phialpha1, const Wavefunction<amplitude_t>::Amplitude &phialpha2)
{
    // this function should be called *after* the phialpha's have been updated

    assert(current_state == READY);
    current_state = UPDATE_IN_PROGRESS;

    const PositionArguments &r1 = phialpha1.get_positions();
    const PositionArguments &r2 = phialpha2.get_positions();

#ifndef NDEBUG
    assert(r1.get_N_species() == r2.get_N_species());
    for (unsigned int i = 0; i < r1.get_N_species(); ++i)
        assert(r1.get_N_filled(i) == r2.get_N_filled(i));
#endif

    assert(!particle1 || r1.particle_is_valid(*particle1));
    assert(!particle2 || r2.particle_is_valid(*particle2));

    const Lattice &lattice = phialpha1.get_lattice();

    // these will be will be >= 0 if the particle was in the subsystem before,
    // -1 if the particle was not in the subsystem before, and -2 if the
    // particle isn't even being moved.
    int pairing_index1 = (!particle1) ? -2 : vector_find(copy1_subsystem_indices[particle1->species], particle1->index);
    int pairing_index2 = (!particle2) ? -2 : vector_find(copy2_subsystem_indices[particle2->species], particle2->index);

    const bool particle1_now_in_subsystem = (particle1 && subsystem->position_is_within(r1[*particle1], lattice));
    const bool particle2_now_in_subsystem = (particle2 && subsystem->position_is_within(r2[*particle2], lattice));

    const int delta1 = (particle1_now_in_subsystem ? 1 : 0) + (pairing_index1 >= 0 ? -1 : 0);
#ifndef NDEBUG
    const int delta2 = (particle2_now_in_subsystem ? 1 : 0) + (pairing_index2 >= 0 ? -1 : 0);
#endif

    assert(particle1 || delta1 == 0);
    assert(particle2 || delta2 == 0);

    assert(delta1 == delta2);
    const int delta = delta1;

    assert(delta == 0 || (particle1 && particle2 && particle1->species == particle2->species));

    assert(delta == 0 || particle1_now_in_subsystem == particle2_now_in_subsystem);
    // to ensure only a single update is necessary to the phibeta's, we require
    // that a particle only be moved in one copy if the particle number is not
    // changing
    assert(delta != 0 || !(particle1 && particle2));

    // remember a few things in case we need to cancel
    recent_delta = delta;
    if (particle1)
        recent_particle1 = *particle1;
    if (particle2)
        recent_particle2 = *particle2;

    if (delta == -1) {
        // if a particle of the same type leaves each subsystem simultaneously,
        // we need to use some special logic in case we have to re-pair the
        // remaining particles in the subsystem.  (re-pair in the sense of what
        // gets swapped with what)

        // these repeat some logic in the "if" statement, but are a useful
        // sanity check nonetheless (for now)
        assert(pairing_index1 >= 0 && pairing_index2 >= 0);
        assert(!particle1_now_in_subsystem);
        assert(!particle2_now_in_subsystem);

        const unsigned int species = particle1->species;
        std::vector<unsigned int> &c1_s = copy1_subsystem_indices[species];
        std::vector<unsigned int> &c2_s = copy2_subsystem_indices[species];

        if (pairing_index1 != pairing_index2) {
            // in order to re-pair the particles left behind, we move the pair
            // that is leaving the subsystem to the max_pairing_index, and move
            // the pair that is staying behind to the min_pairing_index.
            phibeta1->swap_particles(c1_s[pairing_index1], c1_s[pairing_index2], species);
            phibeta2->swap_particles(c2_s[pairing_index1], c2_s[pairing_index2], species);
            if (pairing_index1 < pairing_index2)
                std::swap(c1_s[pairing_index1], c1_s[pairing_index2]);
            else
                std::swap(c2_s[pairing_index1], c2_s[pairing_index2]);
        }

        // update the phibeta's
        const unsigned int max_pairing_index = std::max(pairing_index1, pairing_index2);
        assert(!phibeta1_dirty && !phibeta2_dirty);
        {
            Move move;
            move.push_back(SingleParticleMove(Particle(c1_s[max_pairing_index], species), r1[*particle1]));
            phibeta1->perform_move(move);
        }
        {
            Move move;
            move.push_back(SingleParticleMove(Particle(c2_s[max_pairing_index], species), r2[*particle2]));
            phibeta2->perform_move(move);
        }
        phibeta1_dirty = true;
        phibeta2_dirty = true;

        // remove the empty pair in the subsystem indices (yes, these steps
        // make sense whether we had to re-pair or not)
        c1_s[max_pairing_index] = c1_s[c1_s.size() - 1];
        c1_s.pop_back();
        c2_s[max_pairing_index] = c2_s[c2_s.size() - 1];
        c2_s.pop_back();
    } else {
        assert(delta == 0 || delta == 1);

        // either both particles moved within their respective subsystems
        // (if they moved at all), or both entered the subsystem and paired
        // with each other immediately

        // update the subsystem indices if necessary
        if (delta == 1) {
            std::vector<unsigned int> &c1_s = copy1_subsystem_indices[particle1->species];
            std::vector<unsigned int> &c2_s = copy2_subsystem_indices[particle2->species];
            c1_s.push_back(particle1->index);
            pairing_index1 = c1_s.size() - 1;
            c2_s.push_back(particle2->index);
            pairing_index2 = c2_s.size() - 1;
        }

        assert(subsystem_particle_counts_match());

        // update the phibeta's
        if (particle1) {
            std::unique_ptr<Wavefunction<amplitude_t>::Amplitude> &phibeta = particle1_now_in_subsystem ? phibeta2 : phibeta1;
            bool &phibeta_dirty = particle1_now_in_subsystem ? phibeta2_dirty : phibeta1_dirty;
            const Particle phibeta_particle = particle1_now_in_subsystem ? Particle(copy2_subsystem_indices[particle1->species][pairing_index1], particle1->species) : *particle1;
            assert(!phibeta_dirty);
            Move move;
            move.push_back(SingleParticleMove(phibeta_particle, r1[*particle1]));
            phibeta->perform_move(move);
            phibeta_dirty = true;
        }

        if (particle2) {
            std::unique_ptr<Wavefunction<amplitude_t>::Amplitude> &phibeta = particle2_now_in_subsystem ? phibeta1 : phibeta2;
            bool &phibeta_dirty = particle2_now_in_subsystem ? phibeta1_dirty : phibeta2_dirty;
            const Particle phibeta_particle = particle2_now_in_subsystem ? Particle(copy1_subsystem_indices[particle2->species][pairing_index2], particle2->species) : *particle2;
            // the only time both particles will move here is when delta == 1,
            // in which case this phibeta and the phibeta above will be
            // different, so we know that phibeta_dirty will never be true
            // here.
            assert(!phibeta_dirty);
            Move move;
            move.push_back(SingleParticleMove(phibeta_particle, r2[*particle2]));
            phibeta->perform_move(move);
            phibeta_dirty = true;
        }
    }
}