summaryrefslogtreecommitdiff
path: root/lib/include/wolff/cluster.hpp
blob: 3912446921f7d5085f69cbbb91d68667dd71aea3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

#ifndef WOLFF_CLUSTER_H
#define WOLFF_CLUSTER_H

#include <random>
#include <cmath>
#include <vector>
#include <queue>

#include "system.hpp"

namespace wolff {

template <class R_t, class X_t>
void system<R_t, X_t>::flip_cluster(v_t i0, const R_t& r,
                  std::mt19937& rng, measurement<R_t, X_t>& A) {
  std::uniform_real_distribution<double> dist(0.0, 1.0);

  std::queue<v_t> queue;
  queue.push(i0);

  std::vector<bool> marks(G.nv, false);

  while (!queue.empty()) {
    v_t i = queue.front();
    queue.pop();

    if (!marks[i]) { // don't reprocess anyone we've already visited!
      marks[i] = true;

      X_t si_new;
#ifndef WOLFF_NO_FIELD
      R_t s0_new;

      bool we_are_ghost = (i == nv);

      if (we_are_ghost) {
        s0_new = r.act(s0);
      } else
#endif
      {
        si_new = r.act(s[i]);
      }

      for (const v_t &j : G.adjacency[i]) {
        double dE, p;

#ifndef WOLFF_NO_FIELD
        bool neighbor_is_ghost = (j == nv);

        if (we_are_ghost || neighbor_is_ghost) {
          X_t s0s_old, s0s_new;
          v_t non_ghost;

          if (neighbor_is_ghost) {
            non_ghost = i;
            s0s_old = s0.act_inverse(s[i]);
            s0s_new = s0.act_inverse(si_new);
          } else {
            non_ghost = j;
            s0s_old = s0.act_inverse(s[j]);
            s0s_new = s0_new.act_inverse(s[j]);
          }

#ifdef WOLFF_SITE_DEPENDENCE
          dE = B(non_ghost, s0s_old) - B(non_ghost, s0s_new);
#else
          dE = B(s0s_old) - B(s0s_new);
#endif

#ifdef WOLFF_USE_FINITE_STATES
          p = Bp[s0s_old.enumerate()][s0s_new.enumerate()];
#endif

          // run measurement hooks for encountering a ghost bond
          A.ghost_bond_visited(*this, non_ghost, s0s_old, s0s_new, dE);
        } else // this is a perfectly normal bond!
#endif
        {
#ifdef WOLFF_BOND_DEPENDENCE
          dE = Z(i, s[i], j, s[j]) - Z(i, si_new, j, s[j]);
#else
          dE = Z(s[i], s[j]) - Z(si_new, s[j]);
#endif

#ifdef WOLFF_USE_FINITE_STATES
          p = Zp[s[i].enumerate()][si_new.enumerate()][s[j].enumerate()];
#endif

          // run measurement hooks for encountering a plain bond
          A.plain_bond_visited(*this, i, si_new, j, dE);
        }

#ifndef WOLFF_USE_FINITE_STATES
        p = 1.0 - exp(-dE / T);
#endif

        if (dist(rng) < p) {
          queue.push(j); // push the neighboring vertex to the queue 
        }
      }

#ifndef WOLFF_NO_FIELD
      if (we_are_ghost) {
        A.ghost_site_transformed(*this, s0_new);
        s0 = s0_new;
      } else
#endif
      {
        A.plain_site_transformed(*this, i, si_new);
        s[i] = si_new;
      }
    }
  }
}

}

#endif