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
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.
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
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 () {
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
));
68 SpinChain
tryChange (const Change
& change
) const {
70 ret
.m_spins
[change
.i
] = !ret
.m_spins
[change
.i
];
71 ret
.m_spins
[change
.j
] = !ret
.m_spins
[change
.j
];
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
];
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 {
87 int L
= m_spins
.size();
88 for (int i
=0;i
<L
;i
++) {
93 int staggeredMagnetization () const {
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);
102 static SpinChain
up (int size
= DEFAULT_SIZE
) {
104 for (int i
=0;i
<size
;i
++) {
105 ret
.m_spins
[i
] = true;
110 static SpinChain
down (int size
= DEFAULT_SIZE
) {
112 for (int i
=0;i
<size
;i
++) {
113 ret
.m_spins
[i
] = false;
118 static SpinChain
neel (int size
= DEFAULT_SIZE
) {
120 for (int i
=0;i
<size
;i
++) {
121 ret
.m_spins
[i
] = i
%2;
126 static SpinChain
half (int size
= DEFAULT_SIZE
) {
128 for (int i
=0;i
<size
;i
++) {
129 ret
.m_spins
[i
] = 2*i
< size
;
134 static SpinChain
random (int size
= DEFAULT_SIZE
) {
136 for (int i
=0;i
<size
;i
++) {
137 ret
.m_spins
[i
] = rand()/(RAND_MAX
+1.0) < 0.5;
142 static SpinChain
halfRandom (int size
= DEFAULT_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
];
151 static SpinChain
fromString (const char *s
, int size
) {
153 for (int i
=0;i
<size
;i
++) {
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';
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';
194 std::string
toBoundarBoundary () const {
195 const int L
= size();
196 std::string
t(L
, '\0');
197 for (int i
=0;i
<L
;i
++) {
199 t
[i
] = parallel(i
, (i
+1)%L
)?(at(i
)?'L':'R'):'0';
201 t
[i
] = parallel(i
, (i
+1)%L
)?(at(i
)?'r':'l'):'0';
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; }
213 std::vector
<bool> m_spins
;
216 std::ostream
& operator << (std::ostream
& out
, const SpinChain
& s
) {
217 out
<< s
.toString ();
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
) {
230 const int L
= s
.size();
231 for (int i
=0;i
<L
;i
+=2) {
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
241 typedef SpinChain State
;
243 std::vector
<double> V
;
244 std::vector
<double> v_ij
;
247 VarProb() : alpha(1.0) {}
248 VarProb(double a
) : alpha(a
) {}
250 double compute (const SpinChain
& state
) const {
251 const int L
= state
.size();
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;
265 double diff (const SpinChain
& state
, const SpinChain::Change
& c
) const {
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
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
);
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
];
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
++) {
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);
371 double _H_i (const SpinChain
& s
, const VarProb
& p
, int i
) const {
374 const int L
= s
.size();
375 if (s
.parallel(i
, (i
+1)%L
)) {
378 SpinChain::Change flip
= { i
, (i
+1)%L
};
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 {
388 const int L
= h
.V
.size();
389 if (s
.parallel(i
, (i
+1)%L
)) {
392 SpinChain::Change flip
= { i
, (i
+1)%L
};
394 other
+= 0.5*J
*(p
.ratioHelper(h
, flip
));
396 return (0.25*self
)+other
;
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 {
406 const int L
= s
.size();
407 for (int i
=0;i
<L
;i
++) {
408 ret
+= _H_i (s
, p
, i
);
413 double compute (const SpinChain
& s
, const VarProb::Helper
& h
, const VarProb
& p
) const {
415 const int L
= s
.size();
416 for (int i
=0;i
<L
;i
++) {
417 ret
+= _H_i (s
, h
, p
, i
);
427 template <typename Probability
>
431 m_probability
.computeHelper(m_state
, m_helper
);
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
) {
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; }
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))) {
459 m_state
.applyChange(trial
);
460 m_probability
.applyChangeHelper(m_state
, m_helper
, trial
); // XXX: leave after applyChange()
471 Probability m_probability
;
479 m_prob
.computeHelper(m_state
, m_helper
);
484 const double J
= m_energy
.J
;
485 const double D
= m_energy
.D
;
486 const int L
= m_state
.size();
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
)) {
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
507 e_L
= self
+e_L
; // e_L is now correct
509 for (;j
<L
+2;j
++) { // overwrite possible leftover values
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;
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
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
; }
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);
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";
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
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()
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
;
586 double m_localEnergy
;
591 std::vector
<double> _G
; // green function for a flip
592 std::vector
<int> _x
; // which spin is flipped