-
Notifications
You must be signed in to change notification settings - Fork 1
/
SwendsenWangIsing.m
226 lines (186 loc) · 6.47 KB
/
SwendsenWangIsing.m
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
function [E, M, x, PRNGState, X] = SwendsenWangIsing( N, T, J, nIter, displayIter )
%SWENDSENWANGISING Ising model simulation using the Swendsen-Wang algorithm.
% This implementation uses MATLAB's sparse matrix API for maximum
% computational efficiency and flexibility when the interaction matrix is
% sparse.
%
% Syntaxes:
% [ E, M, x, PRNGState ] = SwendsenWangIsing( N, T, J, nIter )
% [ ... ] = SwendsenWangIsing( ..., displayIter )
% [ ..., X ] = SwendsenWangIsing( ... )
%
% Inputs:
% 'N' - An integer indicating the desired total dimensionality of the
% problem. For instance, if a 100 x 100 two-dimensional
% lattice is desired, N should be 10000.
%
% 'T' - The thermodynamic temperature at which the system is
% simulated. T must be nonzero.
%
% 'J' - The interaction matrix of the quadratic form defined by the
% Hamiltonian. J must be a symmetric, non-negative matrix of
% size NxN.
%
% 'nIter' - The number of iterations for which the simulation will be
% run.
%
% 'displayIter' - The interval, in iterations, at which a status
% update is printed to the terminal. If displayIter < 0, no
% updates are displayed. If this input is ommitted, it
% defaults to 0.
%
% Outputs:
% 'E' - An nIter by 1 vector of the energy at each iteration.
%
% 'M' - An nIter by 1 vector of the magnetization at each iteration.
%
% 'x' - An N by 1 vector of the final spin state.
%
% 'PRNGState' - The state of the MATLAB PRNG as initialized at the
% start of the simulation.
%
% 'X' - An nIter by N matrix containing the spin states at every
% iteration. If nargout = 4, only the current spin state is
% stored, increasing the speed and memory efficiency of the
% simulation.
%
% References:
% [1] Swendsen, Robert H., and Jian-Sheng Wang. "Nonuniversal
% critical dynamics in Monte Carlo simulations." Physical Review
% Letters 58, no. 2 (1987): 86.
%
% [2] Wang, Jian-Sheng, and Robert H. Swendsen. "Cluster Monte Carlo
% algorithms." Physica A: Statistical Mechanics and its
% Applications 167, no. 3 (1990): 565-579.
%
% [3] Gilbert, John R., Cleve Moler, and Robert Schreiber. "Sparse
% matrices in MATLAB: Design and implementation." SIAM Journal on
% Matrix Analysis and Applications 13, no. 1 (1992): 333-356.
%
%
%
% Copyright (c) 2018 Jacob Zavatone-Veth, MIT License
%% Validate inputs
% Call local input validation function
ValidateSWIsingInputs(N, T, J, nIter);
% Check whether displayIter has been specified
if nargin == 4
displayIter = 0;
end
% Check whether the full spin state history has been requested
if nargout > 4
saveSpins = true;
else
saveSpins = false;
end
%% Initialize the PRNG and spin state
% Initialize the MATLAB PRNG
% Note that MATLAB uses a global PRNG state. This call seeds the PRNG using
% the current time, and sets the PRNG to the Mersenne twister generator.
PRNGState = rng('shuffle', 'twister');
% Initialize the spin state
x = (-1).^round(rand(N,1));
%% Format the interaction matrix
% Make sure the interaction matrix is sparse
J = sparse(J);
% As the interactions are symmetric, take the lower trangular portion of J
J = tril(J, -1);
% Evaluate the link probabilities
prob = spfun(@(x) 1 - exp(-2 * x / T), J);
%% Run the simulation
% Allocate arrays to store the energy, magnetization, and (if desired) spin
% state at each iteration
E = zeros(nIter, 1);
M = zeros(nIter, 1);
if saveSpins
X = zeros(nIter, N);
end
% If desired, store the spin state
if saveSpins
X(1,:) = x;
end
% Compute the magnetization and energy
M(1) = mean(x);
E(1) = -(x' * J * x)/N;
% Print an update
if displayIter > 0
fprintf('temperature %f, iteration %05d, energy %+f\n', T, 1, E(1));
end
% Iterate
tic;
for iter = 2:nIter
% Find which spins are aligned
sameSpin = tril(x' .* J .* x, -1) > 0;
% Form the adjacency matrix of the graph
A = (sprand(prob) < prob) .* sameSpin;
A = A + speye(N);
% Form the graph
G = graph(A, 'lower');
% Find connected components in the graph
C = conncomp(G, 'OutputForm', 'cell');
% Flip each cluster with probability 1/2
for ind = 1:length(C)
if rand(1) < 0.5
x(C{ind}) = -x(C{ind});
end
end
% If desired, store the spin state
if saveSpins
X(iter,:) = x;
end
% Compute the magnetization and energy
M(iter) = mean(x);
E(iter) = -(x' * J * x)/N;
% Print an update
if displayIter > 0 && ~mod(iter, displayIter)
fprintf('temperature %f, iteration %05d, energy %+f\n', T, iter, E(iter));
end
end
% Print an update
if displayIter > 0
fprintf('Completed simulation in %f seconds.\n', toc);
end
end
function ValidateSWIsingInputs(N, T, J, nIter)
% Local utility function to check inputs
% Ensure that the dimensionality is a scalar
if numel(N) > 1
error('SwendsenWangIsing:Problem dimensionality must be a scalar.');
end
% Ensure that the dimensionality is at least one
if (rem(N, 1) > 0) || N < 1
error('SwendsenWangIsing:Problem dimensionality must an integer greater than or equal to one.');
end
% Ensure that the temperature is a scalar
if numel(T) > 1
error('SwendsenWangIsing:Temperature must be a scalar.');
end
% Ensure that the temperature is nonzero
if T==0
error('SwendsenWangIsing:Temperature must be non-zero.');
end
% Ensure that the interaction matrix is of the correct size
if ~isequal(size(J), [N, N])
error('SwendsenWangIsing:Interaction matrix must have size equal to the dimensionality of the problem.');
end
% Ensure that all interactions are non-negative
if any(J(:) < 0)
error('SwendsenWangIsing:Interaction strengths must be non-negative.');
end
% Ensure that some interactions are nonzero
if ~any(J(:))
error('SwendsenWangIsing:Some interaction strengths must be nonzero.')
end
% Ensure that the interaction matrix is symmetric
if ~issymmetric(J)
error('SwendsenWangIsing:Interactions must be symmetric.');
end
% Ensure that the number of iterations is a scalar
if numel(nIter) > 1
error('SwendsenWangIsing:Number of iterations must be a scalar.');
end
% Ensure that the number of iterations is at least one
if (rem(nIter, 1) > 0) || nIter < 1
error('SwendsenWangIsing:Number of iterations must an integer greater than or equal to one.');
end
end