removed useless file
[qmc.git] / qmc.hpp
blob285075106b951a934935fc065e7b0682bf7a9448
1 /*
2 * Copyright (c) 2009 Mauro Iazzi
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
11 * conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 #ifndef __QMC_HPP
27 #define __QMC_HPP
29 #include <iostream>
30 #include <fstream>
31 #include <string>
32 #include <vector>
33 #include <cstdlib>
34 #include <cmath>
36 #define PI 3.141592653589792
37 #define DEFAULT_SIZE 10
38 #define MAX(a, b) ((a)>(b)?(a):(b))
39 #define MIN(a, b) ((a)<(b)?(a):(b))
42 // End of forward decl
44 class SpinChain {
45 private:
46 public:
47 struct Change {
48 int i;
49 int j;
52 SpinChain () : m_spins(DEFAULT_SIZE) {}
53 SpinChain (int size) : m_spins(size) {}
54 SpinChain (const SpinChain& other) : m_spins(other.m_spins) {}
56 Change trialChange () {
57 const int L = size();
58 Change ret;
59 do {
60 ret.i = int((rand()/(RAND_MAX+1.0))*L);
61 //ret.j = (rand()/(RAND_MAX+1.0))*(L-1);
62 //if (ret.j>=ret.i) ret.j = (ret.j+1)%L;
63 ret.j = (ret.i + 1) % L;
64 } while (parallel(ret.i, ret.j));
65 return ret;
68 SpinChain tryChange (const Change& change) const {
69 SpinChain ret(*this);
70 ret.m_spins[change.i] = !ret.m_spins[change.i];
71 ret.m_spins[change.j] = !ret.m_spins[change.j];
72 return ret;
75 SpinChain& applyChange (const Change& change) {
76 this->m_spins[change.i] = !this->m_spins[change.i];
77 this->m_spins[change.j] = !this->m_spins[change.j];
78 return *this;
81 int size () const { return m_spins.size(); }
82 int sigma (int i) const { return m_spins[i]?1:-1; }
83 bool at (int i) const { return m_spins[i]; }
84 bool parallel (int i, int j) const { return m_spins[i] == m_spins[j]; }
85 int magnetization () const {
86 int m = 0;
87 int L = m_spins.size();
88 for (int i=0;i<L;i++) {
89 m += m_spins[i]?1:-1;
91 return m;
93 int staggeredMagnetization () const {
94 int m = 0;
95 int L = m_spins.size();
96 for (int i=0;i<L;i++) {
97 m += (m_spins[i]?1:-1) * (i%2==0?1:-1);
99 return m;
102 static SpinChain up (int size = DEFAULT_SIZE) {
103 SpinChain ret(size);
104 for (int i=0;i<size;i++) {
105 ret.m_spins[i] = true;
107 return ret;
110 static SpinChain down (int size = DEFAULT_SIZE) {
111 SpinChain ret(size);
112 for (int i=0;i<size;i++) {
113 ret.m_spins[i] = false;
115 return ret;
118 static SpinChain neel (int size = DEFAULT_SIZE) {
119 SpinChain ret(size);
120 for (int i=0;i<size;i++) {
121 ret.m_spins[i] = i%2;
123 return ret;
126 static SpinChain half (int size = DEFAULT_SIZE) {
127 SpinChain ret(size);
128 for (int i=0;i<size;i++) {
129 ret.m_spins[i] = 2*i < size;
131 return ret;
134 static SpinChain random (int size = DEFAULT_SIZE) {
135 SpinChain ret(size);
136 for (int i=0;i<size;i++) {
137 ret.m_spins[i] = rand()/(RAND_MAX+1.0) < 0.5;
139 return ret;
142 static SpinChain halfRandom (int size = DEFAULT_SIZE) {
143 SpinChain ret(size);
144 for (int i=0;i<size/2;i++) {
145 ret.m_spins[i] = rand()/(RAND_MAX+1.0) < 0.5;
146 ret.m_spins[size-1-i] = !ret.m_spins[i];
148 return ret;
151 static SpinChain fromString (const char *s, int size) {
152 SpinChain ret(size);
153 for (int i=0;i<size;i++) {
154 bool c;
155 switch (s[i]) {
156 case '1':
157 case 'u':
158 case 'U':
159 case '+':
160 case '^':
161 c = true;
162 break;
163 case '0':
164 case 'd':
165 case 'D':
166 case '-':
167 case 'v':
168 c = false;
169 break;
171 ret.m_spins[i] = c;
173 return ret;
176 std::string toString () const {
177 const int L = size();
178 std::string t(L, '\0');
179 for (int i=0;i<L;i++) {
180 t[i] = at(i)?'1':'0';
182 return t;
185 std::string toSString () const {
186 const int L = size();
187 std::string t(L, '\0');
188 for (int i=0;i<L;i++) {
189 t[i] = at(i)?(i%2==0)?'1':'0':(i%2==0)?'0':'1';
191 return t;
194 std::string toBoundarBoundary () const {
195 const int L = size();
196 std::string t(L, '\0');
197 for (int i=0;i<L;i++) {
198 if (i%2==0) {
199 t[i] = parallel(i, (i+1)%L)?(at(i)?'L':'R'):'0';
200 } else {
201 t[i] = parallel(i, (i+1)%L)?(at(i)?'r':'l'):'0';
204 return t;
207 friend std::ostream& operator << (std::ostream&, const SpinChain&);
208 const SpinChain& operator = (const SpinChain& other) { m_spins = other.m_spins; return *this; }
209 bool operator == (const SpinChain& other) { return m_spins == other.m_spins; }
210 SpinChain& swap (SpinChain& other) { m_spins.swap(other.m_spins); return *this; }
212 private:
213 std::vector<bool> m_spins;
216 std::ostream& operator << (std::ostream& out, const SpinChain& s) {
217 out << s.toString ();
218 return out;
221 class VarProb {
222 private:
223 // distance between the two spins in the lattice
224 static double _distance (double i, double j) { return 2.0*std::sin(PI*std::abs(i-j)); }
225 // coefficient between the two spins in the lattice
226 static double _V_ij (double i, double j) { return 2.0*std::log(_distance(i, j)); }
227 // (-1)^(# of spin ups in even indices)
228 static int _sign (const SpinChain& s) {
229 int ret = 1;
230 const int L = s.size();
231 for (int i=0;i<L;i+=2) {
232 ret *= s.at(i)?-1:1;
234 return ret;
236 // ratio between the signs of the two states
237 static int _signRatio (const SpinChain::Change& c) {
238 return (c.i%2)==(c.j%2)?1:-1; // each flip on even site bears a sign change
240 public:
241 typedef SpinChain State;
242 typedef struct {
243 std::vector<double> V;
244 std::vector<double> v_ij;
245 } Helper;
247 VarProb() : alpha(1.0) {}
248 VarProb(double a) : alpha(a) {}
250 double compute (const SpinChain& state) const {
251 const int L = state.size();
252 double x = 0.0;
253 int ups = 0;
254 for (int i=0;i<L;i++) {
255 ups += state.sigma(i);
256 for (int j=i+1;j<L;j++) {
257 double d = _V_ij(double(i)/L, double(j)/L);
258 x += d*(state.parallel(i, j)?1.0:-1.0);
261 if (ups!=0) return 0.0;
262 return alpha*x;
265 double diff (const SpinChain& state, const SpinChain::Change& c) const {
266 double ret = 0.0;
267 const int L = state.size();
268 const int i = MAX(c.i, c.j);
269 const int j = MIN(c.i, c.j);
270 if (state.parallel(i, j)) return 0.0;
271 for (int k=0;k<j;k++) {
272 double di = _V_ij(double(k)/L, double(i)/L);
273 double dj = _V_ij(double(k)/L, double(j)/L);
274 ret += di*(state.parallel(k, i)?-1.0:1.0);
275 ret += dj*(state.parallel(k, j)?-1.0:1.0);
277 for (int k=j+1;k<i;k++) {
278 double di = _V_ij(double(k)/L, double(i)/L);
279 double dj = _V_ij(double(k)/L, double(j)/L);
280 ret += di*(state.parallel(k, i)?-1.0:1.0);
281 ret += dj*(state.parallel(k, j)?-1.0:1.0);
283 for (int k=i+1;k<L;k++) {
284 double di = _V_ij(double(k)/L, double(i)/L);
285 double dj = _V_ij(double(k)/L, double(j)/L);
286 ret += di*(state.parallel(k, i)?-1.0:1.0);
287 ret += dj*(state.parallel(k, j)?-1.0:1.0);
289 return 2.0 * alpha * ret;
292 double ratio (const SpinChain& s, const SpinChain::Change& c) const {
293 const double exponent = diff(s, c);
294 return _signRatio(c)*exp(exponent);
297 double diffHelper (const Helper& h, const SpinChain::Change& c) const {
298 const std::vector<double>& V = h.V;
299 const std::vector<double>& v_ij = h.v_ij;
300 const int L = V.size();
301 double d = v_ij[std::abs(c.i-c.j)];
302 // compensate double counting: i, j are surely antiparallel, so had a -1 sign
303 // they are counted once in v[i] and once in v[j]
304 // with the wrong sign
305 double x = 2.0 * d;
306 return -2.0* alpha * (V[c.i]+V[c.j]+x);
308 double ratioHelper (const Helper& h, const SpinChain::Change& c) const {
309 const double exponent = diffHelper(h, c);
310 return _signRatio(c)*exp(exponent);
312 void applyChangeHelper (const SpinChain& s, Helper& h, const SpinChain::Change& c) const {
313 std::vector<double>& V = h.V;
314 std::vector<double>& v_ij = h.v_ij;
315 const int L = V.size();
316 const int i = MAX(c.i, c.j);
317 const int j = MIN(c.i, c.j);
318 V[i] = -V[i];
319 V[j] = -V[j];
320 for (int k=0;k<j;k++) {
321 double di = v_ij[i-k];
322 double dj = v_ij[j-k];
323 V[k] -= 2.0*di*(s.parallel(k, i)?-1.0:1.0);
324 V[k] -= 2.0*dj*(s.parallel(k, j)?-1.0:1.0);
326 for (int k=j+1;k<i;k++) {
327 double di = v_ij[i-k];
328 double dj = v_ij[k-j];
329 V[k] -= 2.0*di*(s.parallel(k, i)?-1.0:1.0);
330 V[k] -= 2.0*dj*(s.parallel(k, j)?-1.0:1.0);
332 for (int k=i+1;k<L;k++) {
333 double di = v_ij[k-i];
334 double dj = v_ij[k-j];
335 V[k] -= 2.0*di*(s.parallel(k, i)?-1.0:1.0);
336 V[k] -= 2.0*dj*(s.parallel(k, j)?-1.0:1.0);
338 double d = v_ij[i-j];
339 V[i] -= 2.0*d;
340 V[j] -= 2.0*d;
342 void computeHelper (const SpinChain& s, Helper& h) {
343 const int L = s.size();
344 std::vector<double>& V = h.V;
345 std::vector<double>& v_ij = h.v_ij;
346 if (V.size()<L) V.resize(L);
347 if (v_ij.size()<L) v_ij.resize(L);
348 for (int i=0;i<L;i++) {
349 v_ij[i] = _V_ij(double(i)/L, 0.0);
351 for (int i=0;i<L;i++) {
352 double x = 0.0;
353 for (int j=0;j<i;j++) {
354 double d = v_ij[i-j];
355 x += d*(s.parallel(i, j)?1.0:-1.0);
357 for (int j=i+1;j<L;j++) {
358 double d = v_ij[j-i];
359 x += d*(s.parallel(i, j)?1.0:-1.0);
361 V[i] = x;
365 private:
366 double alpha;
369 class Energy {
370 private:
371 double _H_i (const SpinChain& s, const VarProb& p, int i) const {
372 double self = 0.0;
373 double other = 0.0;
374 const int L = s.size();
375 if (s.parallel(i, (i+1)%L)) {
376 self += D*J;
377 } else {
378 SpinChain::Change flip = { i, (i+1)%L };
379 self -= D*J;
380 other += 0.5*J*(p.ratio(s, flip));
382 return (0.25*self)+other;
385 double _H_i (const SpinChain& s, const VarProb::Helper& h, const VarProb& p, int i) const {
386 double self = 0.0;
387 double other = 0.0;
388 const int L = h.V.size();
389 if (s.parallel(i, (i+1)%L)) {
390 self += D*J;
391 } else {
392 SpinChain::Change flip = { i, (i+1)%L };
393 self -= D*J;
394 other += 0.5*J*(p.ratioHelper(h, flip));
396 return (0.25*self)+other;
398 public:
399 Energy() : J(1.0), D(1.0) {}
400 Energy(double j) : J(j), D(1.0) {}
401 Energy(double j, double d) : J(j), D(d) {}
402 Energy(const Energy &e) : J(e.J), D(e.D) {}
404 double compute (const SpinChain& s, const VarProb& p) const {
405 double ret = 0.0;
406 const int L = s.size();
407 for (int i=0;i<L;i++) {
408 ret += _H_i (s, p, i);
410 return ret;
413 double compute (const SpinChain& s, const VarProb::Helper& h, const VarProb& p) const {
414 double ret = 0.0;
415 const int L = s.size();
416 for (int i=0;i<L;i++) {
417 ret += _H_i (s, h, p, i);
419 return ret;
422 double J;
423 double D;
424 private:
427 template <typename Probability>
428 class QMC {
429 private:
430 void _recompute () {
431 m_probability.computeHelper(m_state, m_helper);
433 public:
435 typedef typename Probability::State State;
436 typedef typename State::Change Change;
437 typedef typename Probability::Helper Helper;
439 QMC (const Probability& p, const State& s) : m_probability(p), m_state(s) {
440 _recompute();
443 const State& state () const { return m_state; }
444 const State* statePointer () const { return &m_state; }
445 void setState (const State& s) { m_state = s; _recompute(); }
446 const Probability& probability () const { return m_probability; }
447 void setProbability (const Probability& p) { m_probability = p; _recompute(); }
448 const Change& lastChange () const { return last_change; }
449 const Helper& helper () const { return m_helper; }
450 double weight () const { return 1.0; }
452 bool step() {
453 bool ret = false; // whether it's accepted
454 Change trial = m_state.trialChange(); // description of a trial step
455 double pchange_h = m_probability.ratioHelper(m_helper, trial);
456 double a = pchange_h*pchange_h; // pchange is in fact related to an amplitude
457 if (a>(rand()/(RAND_MAX+1.0))) {
458 // accept
459 m_state.applyChange(trial);
460 m_probability.applyChangeHelper(m_state, m_helper, trial); // XXX: leave after applyChange()
461 last_change = trial;
462 ret = true;
463 } else {
464 // reject
465 ret = false;
467 return ret;
469 private:
470 State m_state;
471 Probability m_probability;
472 Change last_change;
473 Helper m_helper;
476 class Walker {
477 private:
478 void _recompute () {
479 m_prob.computeHelper(m_state, m_helper);
480 _fillG();
483 void _fillG () {
484 const double J = m_energy.J;
485 const double D = m_energy.D;
486 const int L = m_state.size();
487 double e_L = 0.0;
488 double self = 0.0;
489 int j = 0;
490 _G.resize(L+2, -1.0); // L spins can flip or no flip at all
491 _x.resize(L+2, -1); // L spins can flip or no flip at all
492 for (int i=0;i<L;i++) {
493 if (m_state.parallel(i, (i+1)%L)) {
494 self += J*D;
495 } else {
496 Change c = { i, (i+1)%L };
497 const double g_i = 0.5 * J * m_prob.ratioHelper(m_helper, c); // guiding function
498 e_L += g_i; // e_L is the sum of all the green function column
499 _G[j] = -g_i; // the energy due to the change
500 _x[j++] = i; // the spin that is flipped
501 self -= J*D; // the energy of the state
504 self = 0.25*self; // spin-1/2
505 _G[j] = Lambda-self;
506 _x[j++] = -1;
507 e_L = self+e_L; // e_L is now correct
508 m_localEnergy = e_L;
509 for (;j<L+2;j++) { // overwrite possible leftover values
510 _G[j] = -1.0;
511 _x[j] = -1;
513 //std::cout << e_L-m_energy.compute(m_state, m_helper, m_prob) << std::endl;
514 //std::cout << e_L-m_energy.compute(m_state, m_prob) << std::endl;
516 public:
517 typedef SpinChain State;
518 typedef /*typename*/ State::Change Change;
519 typedef VarProb Probability;
520 typedef /*typename*/ Probability::Helper Helper;
522 explicit Walker(const Probability &p, const State &s, Energy e = Energy()) : Lambda(0.0), m_weight(1.0), m_energy(e), m_state(s), m_prob(p) {
523 // Lambda = s.size() * 0.25 * e.J * (0.01 + e.D); // surely higher than any value in H
524 _recompute();
527 const State& state () const { return m_state; }
528 void setState (const State& s) { m_state = s; _recompute(); }
529 const Probability& probability () const { return m_prob; }
530 void setProbability (const Probability& p) { m_prob = p; _recompute(); }
531 const Helper& helper () const { return m_helper; }
532 double weight () const { return m_weight; }
533 double coeff () const { return m_coeff; }
534 double localEnergy () const { return m_localEnergy; }
536 bool step () {
537 const int L = m_state.size();
538 const double b = (Lambda - m_localEnergy); // will be the new weight
539 double r = b*rand()/(RAND_MAX+1.0);
540 double r2=r;
541 int j = 0;
542 while (r>_G[j]) {
543 r -= (_G[j++]);
545 if (_G[j]<0) {
546 for (int i=0;i<L+2;i++) std::cerr << "(" << _G[i] << ", " << _x[i] << ") ";
547 std::cerr << r2 << " (" << _G[j] << ", " << _x[j] << ") " << m_state.toString() << "\n";
549 m_weight = b;
550 m_coeff = _G[j];
552 // now j contains the index of the spin that must be flipped
553 const int pos = _x[j];
554 //std::cout << "stuck on " << j << " " << r << " " << _G[j] << " " << pos << std::endl;
555 //std::cout << pos << "\n"; // to check for translation invariance
556 if (pos == -1) {
557 // no change needed?
558 } else {
559 // let's recompute
560 const Change f = { pos, (pos+1)%L };
561 m_state.applyChange(f);
562 m_prob.applyChangeHelper(m_state, m_helper, f); // XXX: leave after applyChange()
563 _fillG();
565 return pos!=-1;
568 void copyOn (Walker *other) {
569 other->Lambda = this->Lambda;
570 other->m_weight = this->m_weight;
571 other->m_coeff = this->m_coeff;
572 other->m_localEnergy = this->m_localEnergy;
573 other->m_energy = this->m_energy;
574 other->m_state = this->m_state;
575 other->m_helper = this->m_helper;
576 other->m_helper.V = this->m_helper.V;
577 other->m_helper.v_ij = this->m_helper.v_ij;
578 other->m_prob = this->m_prob;
579 other->_G = this->_G;
580 other->_x = this->_x;
582 private:
583 double Lambda;
584 double m_weight;
585 double m_coeff;
586 double m_localEnergy;
587 Energy m_energy;
588 State m_state;
589 Helper m_helper;
590 Probability m_prob;
591 std::vector<double> _G; // green function for a flip
592 std::vector<int> _x; // which spin is flipped
596 #endif // __QMC_HPP