14 #define PI 3.141592653589792
15 #define DEFAULT_SIZE 10
16 #define MAX(a, b) ((a)>(b)?(a):(b))
17 #define MIN(a, b) ((a)<(b)?(a):(b))
21 // End of forward decl
31 SpinChain () : m_spins(DEFAULT_SIZE
) {}
32 SpinChain (int size
) : m_spins(size
) {}
33 SpinChain (const SpinChain
& other
) : m_spins(other
.m_spins
) {}
35 Change
trialChange () {
39 ret
.i
= (rand()/(RAND_MAX
+1.0))*L
;
40 ret
.j
= (rand()/(RAND_MAX
+1.0))*(L
-1);
41 if (ret
.j
>=ret
.i
) ret
.j
= (ret
.j
+1)%L
;
42 } while (parallel(ret
.i
, ret
.j
));
46 SpinChain
tryChange (const Change
& change
) const {
48 ret
.m_spins
[change
.i
] = !ret
.m_spins
[change
.i
];
49 ret
.m_spins
[change
.j
] = !ret
.m_spins
[change
.j
];
53 SpinChain
& applyChange (const Change
& change
) {
54 this->m_spins
[change
.i
] = !this->m_spins
[change
.i
];
55 this->m_spins
[change
.j
] = !this->m_spins
[change
.j
];
59 int size () const { return m_spins
.size(); }
60 int at (int i
) const { return m_spins
[i
]?1:-1; }
61 bool parallel (int i
, int j
) const { return m_spins
[i
] == m_spins
[j
]; }
62 int magnetization () const {
64 int L
= m_spins
.size();
65 for (int i
=0;i
<L
;i
++) {
71 static SpinChain
up (int size
= DEFAULT_SIZE
) {
73 for (int i
=0;i
<size
;i
++) {
74 ret
.m_spins
[i
] = true;
79 static SpinChain
down (int size
= DEFAULT_SIZE
) {
81 for (int i
=0;i
<size
;i
++) {
82 ret
.m_spins
[i
] = false;
87 static SpinChain
neel (int size
= DEFAULT_SIZE
) {
89 for (int i
=0;i
<size
;i
++) {
95 static SpinChain
half (int size
= DEFAULT_SIZE
) {
97 for (int i
=0;i
<size
;i
++) {
98 ret
.m_spins
[i
] = 2*i
< size
;
103 static SpinChain
random (int size
= DEFAULT_SIZE
) {
105 for (int i
=0;i
<size
;i
++) {
106 ret
.m_spins
[i
] = rand()/(RAND_MAX
+1.0) < 0.5;
111 static SpinChain
fromString (const char *s
, int size
) {
113 for (int i
=0;i
<size
;i
++) {
128 friend ostream
& operator << (ostream
&, const SpinChain
&);
129 const SpinChain
& operator = (const SpinChain
& other
) { m_spins
= other
.m_spins
; return *this; }
130 bool operator == (const SpinChain
& other
) { return m_spins
== other
.m_spins
; }
131 SpinChain
& swap (SpinChain
& other
) { m_spins
.swap(other
.m_spins
); return *this; }
134 std::vector
<bool> m_spins
;
137 ostream
& operator << (ostream
& out
, const SpinChain
& s
) {
138 for (std::vector
<bool>::const_iterator iter
= s
.m_spins
.begin();iter
!= s
.m_spins
.end();iter
++) {
146 // distance between the two spins in the lattice
147 static double _distance (double i
, double j
) { return 2.0*sin(PI
*abs(i
-j
)); }
148 // coefficient between the two spins in the lattice
149 static double _V_ij (double i
, double j
) { return 2.0*log(_distance(i
, j
)); }
150 // (-1)^(# of spin ups in even indices)
151 static int _sign (const SpinChain
& s
) {
153 const int L
= s
.size();
154 for (int i
=0;i
<L
;i
+=2) {
159 // ratio between the signs of the two states
160 static int _signRatio (const SpinChain::Change
& c
) {
161 return (c
.i
%2)==(c
.j
%2)?1:-1; // each flip on even site bears a sign change
164 typedef std::vector
<double> Helper
;
166 VarProb() : alpha(1.0) {}
167 VarProb(double a
) : alpha(a
) {}
169 double compute (const SpinChain
& state
) const {
170 const int L
= state
.size();
173 for (int i
=0;i
<L
;i
++) {
175 for (int j
=i
+1;j
<L
;j
++) {
176 double d
= _V_ij(double(i
)/L
, double(j
)/L
);
177 x
+= d
*(state
.parallel(i
, j
)?1.0:-1.0);
180 if (ups
!=0) return 0.0;
184 double diff (const SpinChain
& state
, const SpinChain::Change
& c
) const {
186 const int L
= state
.size();
187 const int i
= MAX(c
.i
, c
.j
);
188 const int j
= MIN(c
.i
, c
.j
);
189 if (state
.parallel(i
, j
)) return 0.0;
190 for (int k
=0;k
<j
;k
++) {
191 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
192 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
193 ret
+= di
*(state
.parallel(k
, i
)?-1.0:1.0);
194 ret
+= dj
*(state
.parallel(k
, j
)?-1.0:1.0);
196 for (int k
=j
+1;k
<i
;k
++) {
197 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
198 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
199 ret
+= di
*(state
.parallel(k
, i
)?-1.0:1.0);
200 ret
+= dj
*(state
.parallel(k
, j
)?-1.0:1.0);
202 for (int k
=i
+1;k
<L
;k
++) {
203 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
204 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
205 ret
+= di
*(state
.parallel(k
, i
)?-1.0:1.0);
206 ret
+= dj
*(state
.parallel(k
, j
)?-1.0:1.0);
208 return 2.0 * alpha
* ret
;
211 double ratio (const SpinChain
& s
, const SpinChain::Change
& c
) const {
212 const double exponent
= diff(s
, c
);
213 return _signRatio(c
)*exp(exponent
);
216 double diffHelper (const Helper
& h
, const SpinChain::Change
& c
) const {
217 const vector
<double>& v
= h
;
218 const int L
= v
.size();
219 double d
= _V_ij(double(c
.i
)/L
, double(c
.j
)/L
);
220 // compensate double counting: i, j are surely antiparallel, so had a -1 sign
221 // they are counted once in v[i] and once in v[j]
222 // with the wrong sign
224 return -2.0* alpha
* (v
[c
.i
]+v
[c
.j
]+x
);
226 double ratioHelper (const Helper
& h
, const SpinChain::Change
& c
) const {
227 const double exponent
= diffHelper(h
, c
);
228 return _signRatio(c
)*exp(exponent
);
230 void applyChangeHelper (const SpinChain
& s
, Helper
& h
, const SpinChain::Change
& c
) const {
231 vector
<double>& v
= h
;
232 const int L
= v
.size();
233 const int i
= MAX(c
.i
, c
.j
);
234 const int j
= MIN(c
.i
, c
.j
);
237 for (int k
=0;k
<j
;k
++) {
238 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
239 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
240 v
[k
] -= 2.0*di
*(s
.parallel(k
, i
)?-1.0:1.0);
241 v
[k
] -= 2.0*dj
*(s
.parallel(k
, j
)?-1.0:1.0);
243 for (int k
=j
+1;k
<i
;k
++) {
244 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
245 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
246 v
[k
] -= 2.0*di
*(s
.parallel(k
, i
)?-1.0:1.0);
247 v
[k
] -= 2.0*dj
*(s
.parallel(k
, j
)?-1.0:1.0);
249 for (int k
=i
+1;k
<L
;k
++) {
250 double di
= _V_ij(double(k
)/L
, double(i
)/L
);
251 double dj
= _V_ij(double(k
)/L
, double(j
)/L
);
252 v
[k
] -= 2.0*di
*(s
.parallel(k
, i
)?-1.0:1.0);
253 v
[k
] -= 2.0*dj
*(s
.parallel(k
, j
)?-1.0:1.0);
255 double d
= _V_ij(double(c
.i
)/L
, double(c
.j
)/L
);
259 void computeHelper (const SpinChain
& s
, Helper
& h
) {
260 const int L
= s
.size();
261 vector
<double>& v
= h
;
262 if (v
.size()<L
) v
.resize(L
);
263 for (int i
=0;i
<L
;i
++) {
265 for (int j
=0;j
<i
;j
++) {
266 double d
= _V_ij(double(i
)/L
, double(j
)/L
);
267 x
+= d
*(s
.parallel(i
, j
)?1.0:-1.0);
269 for (int j
=i
+1;j
<L
;j
++) {
270 double d
= _V_ij(double(i
)/L
, double(j
)/L
);
271 x
+= d
*(s
.parallel(i
, j
)?1.0:-1.0);
283 double _H_i (const SpinChain
& s
, const VarProb
& p
, int i
) const {
286 const int L
= s
.size();
287 if (s
.parallel(i
, (i
+1)%L
)) {
290 SpinChain::Change flip
= { i
, (i
+1)%L
};
292 other
+= 0.5*J
*(p
.ratio(s
, flip
));
294 return (0.25*self
)+other
;
297 double _H_i (const SpinChain
& s
, const VarProb::Helper
& h
, const VarProb
& p
, int i
) const {
300 const int L
= h
.size();
301 if (s
.parallel(i
, (i
+1)%L
)) {
304 SpinChain::Change flip
= { i
, (i
+1)%L
};
306 other
+= 0.5*J
*(p
.ratioHelper(h
, flip
));
308 return (0.25*self
)+other
;
311 typedef double ValueType
;
313 Energy() : J(1.0), D(1.0) {}
314 Energy(double j
) : J(j
), D(1.0) {}
315 Energy(double j
, double d
) : J(j
), D(d
) {}
317 double compute (const SpinChain
& s
, const VarProb
& p
) const {
319 const int L
= s
.size();
320 for (int i
=0;i
<L
;i
++) {
321 ret
+= _H_i (s
, p
, i
);
326 double compute (const SpinChain
& s
, const VarProb::Helper
& h
, const VarProb
& p
) const {
328 const int L
= s
.size();
329 for (int i
=0;i
<L
;i
++) {
330 ret
+= _H_i (s
, h
, p
, i
);
340 template <typename Probability
, typename State
>
344 m_probability
.computeHelper(m_state
, m_helper
);
348 QMC (const Probability
& p
, const State
& s
) : m_probability(p
), m_state(s
) {
352 typedef typename
State::Change Change
;
353 typedef typename
Probability::Helper Helper
;
355 const State
& state () const { return m_state
; }
356 void setState (const State
& s
) { m_state
= s
; _recompute(); }
357 const Probability
& probability () const { return m_probability
; }
358 void setProbability (const Probability
& p
) { m_probability
= p
; _recompute(); }
359 const Change
& lastChange () const { return last_change
; }
360 const Helper
& helper () const { return m_helper
; }
363 bool ret
= false; // whether it's accepted
364 Change trial
= m_state
.trialChange(); // description of a trial step
365 double pchange_h
= m_probability
.ratioHelper(m_helper
, trial
);
366 double a
= pchange_h
*pchange_h
; // pchange is in fact related to an amplitude
367 if (a
>(rand()/(RAND_MAX
+1.0))) {
369 m_state
.applyChange(trial
);
370 m_probability
.applyChangeHelper(m_state
, m_helper
, trial
); // XXX: leave after applyChange()
381 Probability m_probability
;
389 void print_state (const SpinChain
& s
) { cout
<< s
<< endl
; }
391 void load_file (int& niter
, int& nspins
, double& alpha
, SpinChain
& init
, const char* fn
) {
392 lua_State
*L
= lua_open();
395 lua_setglobal(L
, "debug");
397 lua_setglobal(L
, "io");
399 lua_getglobal(L
, "qmc_result");
400 if (!lua_isnil(L
, -1)) {
401 lua_getfield(L
, -1, "iterations");
402 niter
= lua_tointeger(L
, -1);
404 lua_getfield(L
, -1, "alpha");
405 alpha
= lua_tonumber(L
, -1);
407 lua_getfield(L
, -1, "final_state");
408 init
= SpinChain::fromString(lua_tostring(L
, -1), lua_objlen(L
, -1));
409 nspins
= init
.size();
416 int main (int argc
, char **argv
) {
421 string
summaryname("");
425 SpinChain init
= SpinChain::neel(nspins
);
426 for (int i
=1;i
<argc
;i
++) {
427 if (argv
[i
][0]!='-') {
431 switch (argv
[i
][1]) {
435 filename
= argv
[++i
];
438 srand(atoi(argv
[++i
]));
441 niter
= atoi(argv
[++i
]);
444 alpha
= atof(argv
[++i
]);
447 nspins
= atoi(argv
[++i
]);
448 init
= SpinChain::half(nspins
);
451 summaryname
= argv
[++i
];
452 load_file(niter
, nspins
, alpha
, init
, argv
[i
]);
466 if (filename
!="") out
.open(filename
.c_str(), append
?ofstream::app
:ofstream::out
);
467 QMC
<VarProb
, SpinChain
> qmc(VarProb(alpha
), init
);
471 bool accepted
= true; // first value is always accepted
474 vector
<double> csum(nspins
/2, 0.0);
475 vector
<double> c(nspins
/2, 0.0);
476 for (int i
=1;i
<=niter
;i
++) {
478 // e still contains the correct value
480 const SpinChain
& s
= qmc
.state();
481 e
= en
.compute(s
, qmc
.helper(), qmc
.probability());
483 for (int j
=1;j
<nspins
/2;j
++) {
484 c
[j
] = s
.parallel(0, j
)?1.0:-1.0;
488 for (int j
=0;j
<nspins
/2;j
++) {
491 accepted
= qmc
.step();
492 nacc
+= accepted
?1:0;
493 if (out
.is_open()) out
<< i
<< " " << double(nacc
)/(i
) << " " << e
/nspins
<< " " << esum
/(i
*nspins
) << "\n";
496 if (summaryname
!="") sfile
.open(summaryname
.c_str(), ofstream::app
);
497 ostream
&summary
= (sfile
.is_open())?sfile
:cout
;
498 summary
<< "qmc_result = {\n";
499 summary
<< "\tinitial_state = \"" << init
<< "\",\n";
500 summary
<< "\tfinal_state = \"" << qmc
.state() << "\",\n";
501 summary
<< "\talpha = " << alpha
<< ",\n";
502 summary
<< "\tenergy_sum = " << esum
<< ", -- average per spin: " << (esum
/(niter
*nspins
)) << "\n";
503 summary
<< "\titerations = " << niter
<< ",\n";
504 summary
<< "\tacceptances = " << nacc
<< ",\n";
505 summary
<< "\tmagnetization_sum = " << csum
[0] << ",\n";
506 summary
<< "\tcorrelation_sum = { " << (niter
-csum
[0]*csum
[0]/niter
) << ", ";
507 for (int j
=1;j
<nspins
/2;j
++) {
508 summary
<< csum
[j
] << ", ";
512 summary
<< "qmcdata = qmcdata or {}\n";
513 summary
<< "table.insert(qmcdata, qmc_result)\n" << endl
;