void run(alps::ObservableSet& obs) { ++mcs; // initialize cluster information std::fill(fragments.begin(), fragments.end(), fragment_t()); // cluster generation for (double t = r_time(); t < 1; t += r_time()) { int s0 = lattice.num_sites() * uniform_01(); int s1 = lattice.num_sites() * uniform_01(); if (spins[s0] == spins[s1]) unify(fragments, s0, s1); } // assign cluster id & accumulate cluster properties int nc = 0; double mag2 = 0, mag4 = 0; BOOST_FOREACH(fragment_t& f, fragments) { if (f.is_root()) { f.set_id(nc++); double w = f.weight(); mag2 += power2(w); mag4 += power4(w); } } BOOST_FOREACH(fragment_t& f, fragments) f.set_id(cluster_id(fragments, f)); // flip spins for (int c = 0; c < nc; ++c) flip[c] = (uniform_01() < 0.5); for (int s = 0; s < lattice.num_sites(); ++s) if (flip[fragments[s].id()]) spins[s] ^= 1; double mu = 0; for (int s = 0; s < lattice.num_sites(); ++s) mu += 2 * spins[s] - 1; obs["Number of Clusters"] << (double)nc; obs["Magnetization (unimproved)"] << mu; obs["Magnetization^2 (unimproved)"] << power2(mu); obs["Magnetization^4 (unimproved)"] << power4(mu); obs["Magnetization^2"] << mag2; obs["Magnetization^4"] << (3 * power2(mag2) - 2 * mag4); }
int main(int argc, char* argv[]) { std::cout << "Loop Algorithm for Spin-1/2 Antiferromagnetic Heisenberg Chain\n"; options p(argc, argv); if (!p.valid) std::exit(127); const unsigned int nsites = p.length; const unsigned int nbonds = nsites; const unsigned int sweeps = p.sweeps; const unsigned int therm = p.therm; const double beta = 1. / p.temperature; const double lb2 = nbonds * beta / 2; // random number generators boost::mt19937 eng(p.seed); boost::variate_generator<boost::mt19937&, boost::uniform_real<> > random(eng, boost::uniform_real<>()); // vector of operators std::vector<local_operator_t> operators(nbonds); unsigned int nop = 0; // number of non-identity operators // spin configuration at t = 0 (1 for down and 0 for up) std::vector<int> spins(nsites, 0); // initialized with all up // cluster information std::vector<fragment_t> fragments; std::vector<unsigned int> current(nsites); // id of fragments at current time std::vector<cluster_t> clusters; // oservables stat::accumulator energy("Energy Density"), smag("Staggered Magnetizetion^2"), ssus("Staggered Susceptibility"), usus("Uniform Susceptibility"); // // Monte Carlo steps // boost::timer tm; for (unsigned int mcs = 0; mcs < therm + sweeps; ++mcs) { // adjust length of operator string if (nop > 0.8 * operators.size()) { std::vector<local_operator_t> operators_new(2 * operators.size()); std::vector<local_operator_t>::iterator itr_new = operators_new.begin(); for (std::vector<local_operator_t>::iterator itr = operators.begin(); itr!= operators.end(); ++itr, itr_new += 2) *itr_new = *itr; std::swap(operators, operators_new); } // initialize cluster information (setup s cluster fragments) fragments.resize(nsites); std::fill(fragments.begin(), fragments.end(), fragment_t()); for (unsigned int s = 0; s < nsites; ++s) current[s] = s; for (std::vector<local_operator_t>::iterator oi = operators.begin(); oi != operators.end(); ++oi) { // diagonal update if (oi->type == identity) { unsigned int b = nbonds * random(); if (spins[left(nbonds, b)] != spins[right(nbonds, b)] && (operators.size() - nop) * random() < lb2) { *oi = local_operator_t(b); ++nop; } else { continue; } } else { if (oi->type == diagonal && lb2 * random() < operators.size() - nop + 1) { oi->type = identity; --nop; continue; } } // cluster generation unsigned int s0 = left(nbonds, oi->bond); unsigned int s1 = right(nbonds, oi->bond); oi->lower_loop = unify(fragments, current[s0], current[s1]); oi->upper_loop = current[s0] = current[s1] = add(fragments); if (oi->type == offdiagonal) { spins[s0] ^= 1; spins[s1] ^= 1; } } // connect bottom and top cluster fragments for (int s = 0; s < nsites; ++s) unify(fragments, s, current[s]); // // cluster flip // // assign cluster id & determine if clusters are to be flipped int nc = 0; BOOST_FOREACH(fragment_t& f, fragments) { if (f.is_root()) f.set_id(nc++); } clusters.resize(nc); BOOST_FOREACH(fragment_t& f, fragments) { f.set_id(cluster_id(fragments, f)); } for (int c = 0; c < nc; ++c) clusters[c] = cluster_t(random() < 0.5); // 'flip' operators & do improved measurements unsigned int t = 0; for (std::vector<local_operator_t>::iterator oi = operators.begin(); oi != operators.end(); ++oi) { if (oi->type == identity) continue; int id_l = fragments[oi->lower_loop].id(); int id_u = fragments[oi->upper_loop].id(); clusters[id_l].length += 2 * t; clusters[id_u].length -= 2 * t; if (clusters[id_l].to_flip ^ clusters[id_u].to_flip) oi->flip(); ++t; } // flip spins & do improved measurements for (unsigned int s = 0; s < nsites; ++s) { int id = fragments[s].id(); clusters[id].size += 1; clusters[id].mag += 1 - 2 * spins[s]; clusters[id].length += nop; if (clusters[id].to_flip) spins[s] ^= 1; } if (mcs < therm) continue; // // measurements // // accumurate loop length and magnetization double s2 = 0; double m2 = 0; double l2 = 0; for (std::vector<cluster_t>::const_iterator pi = clusters.begin(); pi != clusters.end(); ++pi) { s2 += power2(pi->size); m2 += power2(pi->mag); l2 += power2(pi->length); } energy << (0.25 * nbonds - nop / beta) / nsites; smag << 0.25 * s2 / nsites; usus << 0.25 * beta * m2 / nsites; ssus << 0.25 * beta * ((nop ? l2 / nop : 0) + s2) / (nop + 1) / nsites; }