Julia大型稀疏矩阵对角化
前言
对于julia同样是需要安装一个库才可以Arpack1
2import Pkg
Pkg.add("Arpack")
安装完成之后,就可以使用了
实例(Julia)
1 | using Arpack,LinearAlgebra,DelimitedFiles |
实例(Fortran)
1 | module param |
实例(Python)
1 | import numpy as np |
结果对比

从时间对比上来看,利用Julia的效率还是比较高的.
实际上为了节省计算内存和时间,可以将哈密顿量用稀疏存储并对角化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
227
228
229# 构建三角区域计算
using SharedArrays, LinearAlgebra,Distributed,DelimitedFiles,Printf,Arpack,SparseArrays
#------------------------------------------------------------------------------------------------------------------
function boundary(xn::Int64,yn::Int64)
# 构建在特定形状格点上的hopping位置
len2::Int64 = xn*yn
bry = zeros(Int64,4,len2)
# f1 = open("tri.dat","w")
for iy = 1:yn,ix in 1:iy
i = Int(iy*(iy - 1)/2) + ix
bry[1,i] = i + 1 # right hopping
if ix==iy
bry[1,i] = bry[1,i] - iy
end
bry[2,i] = i - 1 # left hopping
if ix==1
bry[2,i] = bry[2,i] + iy
end
bry[3,i] = i + iy # up hopping
if iy==yn
bry[3,i] = (ix + 1)*ix/2
end
bry[4,i]= i - (iy - 1) # down hopping
if iy==ix
bry[4,i] = yn*(yn - 1)/2 + ix
end
# writedlm(f1,[ix iy i bry[1,i] bry[2,i] bry[3,i] bry[4,i]])
end
# close(f1)
return bry
end
#------------------------------------------------------------------------------------------------------------------
function pauli()
s0 = zeros(ComplexF64,2,2)
s1 = zeros(ComplexF64,2,2)
s2 = zeros(ComplexF64,2,2)
s3 = zeros(ComplexF64,2,2)
#----
s0[1,1] = 1
s0[2,2] = 1
#----
s1[1,2] = 1
s1[2,1] = 1
#----
s2[1,2] = -im
s2[2,1] = im
#-----
s3[1,1] = 1
s3[2,2] = -1
#-----
return s0,s1,s2,s3
end
#------------------------------------------------------------------------------------------------------------------
function gamma()
s0,sx,sy,sz = pauli()
# Numbu * spin * orbit
g1 = kron(sz,s0,sz) # mass term
g2 = kron(sz,sy,sx) # sin_x
g3 = kron(s0,sx,sx) # sin_y
g4 = kron(sz,sx,s0) # S_x
g5 = kron(s0,sy,s0) # S_y
g6 = kron(sz,sz,s0) # S_z
g7 = kron(sz,s0,s0) # mu
g8 = kron(sy,sy,s0) # pairing
return g1,g2,g3,g4,g5,g6,g7,g8
end
#------------------------------------------------------------------------------------------------------------------
function matset(xn::Int64,yn::Int64,theta::Float64,phi::Float64)
# 稠密矩阵
t0::Float64 = 1.0
m0::Float64 = 3.0
mu::Float64 = 0.0
lx::Float64 = 1.0
ly::Float64 = -1.0
# phi::Float64 = pi/4
# theta::Float64 = pi/4
V0::Float64 = 0.5
V1::Float64 = 0.5
delta0::Float64 = 0.4
hn::Int64 = 8
len2::Int64 = Int(xn*(yn + 1)/2)
N::Int64 = len2*hn #通过格点确定哈密顿量的大小
ham = zeros(ComplexF64,N,N)
g1,g2,g3,g4,g5,g6,g7,g8 = gamma()
bry = boundary(xn,yn)
#-----------------------------
for iy in 1:yn,ix in 1:iy
i0 = Int(iy*(iy - 1)/2) + ix
for i1 in 0:hn -1,i2 in 0:hn - 1
ham[i0 + len2*i1,i0 + len2*i2] = m0 * g1[i1 + 1,i2 + 1] - mu * g7[i1 + 1,i2 + 1] + V0 * cos(theta) * g6[i1 + 1,i2 + 1] + V0 * sin(theta) * cos(phi) * g4[i1 + 1,i2 + 1] + V0 * sin(theta) * sin(phi) * g5[i1 + 1,i2 + 1] + delta0 * g8[i1 + 1,i2 + 1]
if ix != iy
ham[i0 + len2*i1,bry[1,i0] + len2*i2] = -t0 * g1[i1 + 1,i2 + 1] + lx/(2*im) * g2[i1 + 1,i2 + 1] + V1/2.0 * cos(theta) * g6[i1 + 1,i2 + 1] + V1/2.0 * sin(theta) * cos(phi) * g4[i1 + 1,i2 + 1] + V1/2.0 * sin(theta) * sin(phi) * g5[i1 + 1,i2 + 1]
end
if ix != 1
ham[i0 + len2*i1,bry[2,i0] + len2*i2] = -t0 * g1[i1 + 1,i2 + 1] - lx/(2*im) * g2[i1 + 1,i2 + 1] + V1/2.0 * cos(theta) * g6[i1 + 1,i2 + 1] + V1/2.0 * sin(theta) * cos(phi) * g4[i1 + 1,i2 + 1] + V1/2.0 * sin(theta) * sin(phi) * g5[i1 + 1,i2 + 1]
end
if iy != yn
ham[i0 + len2*i1,bry[3,i0] + len2*i2] = -t0 * g1[i1 + 1,i2 + 1] + ly/(2*im) * g3[i1 + 1,i2 + 1] - V1/2.0 * cos(theta) * g6[i1 + 1,i2 + 1] - V1/2.0 * sin(theta) * cos(phi) * g4[i1 + 1,i2 + 1] - V1/2.0 * sin(theta) * sin(phi) * g5[i1 + 1,i2 + 1]
end
if iy != ix
ham[i0 + len2*i1,bry[4,i0] + len2*i2] = -t0 * g1[i1 + 1,i2 + 1] - ly/(2*im) * g3[i1 + 1,i2 + 1] - V1/2.0 * cos(theta) * g6[i1 + 1,i2 + 1] - V1/2.0 * sin(theta) * cos(phi) * g4[i1 + 1,i2 + 1] - V1/2.0 * sin(theta) * sin(phi) * g5[i1 + 1,i2 + 1]
end
end
end
#------------------------------------
if ishermitian(ham)
val,vec = eigen(ham)
# val,vec = eigs(ham,nev = 100,maxiter = 30,which = :SM)
else
println("Hamiltonian is not hermitian")
# break
end
temp1 = (a->( "%3.1f" a)).(xn)
temp2 = (a->( "%3.2f" a)).(theta/pi)
temp3 = (a->( "%3.2f" a)).(phi/pi)
fx1 = "val-1.dat"
# fx1 = "val-" * temp1 * "-theta-" * temp2 * "-phi-" * temp3 * ".dat"
f1 = open(fx1,"w")
ind = (a->( "%5.2f" a)).(range(1,length(val),length = length(val)))
#val2 = (a->(@sprintf "%15.8f" a)).(map(real,val))
val2 = (a->( "%15.8f" a)).(sort(map(real,val)))
# # writedlm(f1,map(real,val),"\t")
writedlm(f1,[ind val2],"\t")
close(f1)
#return map(real,val),vec
return map(real,val),vec[:,sortperm(map(real,val))]
end
#------------------------------------------------------------------------------------------------------------------
function matset_sparse_block(xn::Int64, yn::Int64, theta::Float64 = 0.0, phi::Float64 = 0.0; nev::Int = 20)
# 稀疏矩阵
t0 = 1.0
m0 = 3.0
mu = 0.0
lx = 1.0
ly = -1.0
V0 = 0.5
V1 = 0.5
delta0 = 0.4
hn = 8
len2 = Int(xn*(yn+1)/2)
N = len2*hn
g1,g2,g3,g4,g5,g6,g7,g8 = gamma()
bry = boundary(xn,yn)
# 创建稀疏矩阵
ham = spzeros(ComplexF64, N, N)
# 直接用索引块构建稀疏矩阵
for iy in 1:yn, ix in 1:iy
i0 = Int(iy*(iy-1)/2) + ix
idx = (i0-1)*hn .+ (1:hn) # 当前格点对应 Hamiltonian 块索引
# 对角块
ham[idx, idx] .= m0*g1 - mu*g7 + V0*cos(theta)*g6 +
V0*sin(theta)*cos(phi)*g4 + V0*sin(theta)*sin(phi)*g5 +
delta0*g8
# 右
if ix != iy
jdx = (bry[1,i0]-1)*hn .+ (1:hn)
ham[idx, jdx] .= -t0*g1 + lx/(2im)*g2 +
V1/2*cos(theta)*g6 + V1/2*sin(theta)*cos(phi)*g4 +
V1/2*sin(theta)*sin(phi)*g5
end
# 左
if ix != 1
jdx = (bry[2,i0]-1)*hn .+ (1:hn)
ham[idx, jdx] .= -t0*g1 - lx/(2im)*g2 +
V1/2*cos(theta)*g6 + V1/2*sin(theta)*cos(phi)*g4 +
V1/2*sin(theta)*sin(phi)*g5
end
# 上
if iy != yn
jdx = (bry[3,i0]-1)*hn .+ (1:hn)
ham[idx, jdx] .= -t0*g1 + ly/(2im)*g3 -
V1/2*cos(theta)*g6 - V1/2*sin(theta)*cos(phi)*g4 -
V1/2*sin(theta)*sin(phi)*g5
end
# 下
if iy != ix
jdx = (bry[4,i0]-1)*hn .+ (1:hn)
ham[idx, jdx] .= -t0*g1 - ly/(2im)*g3 -
V1/2*cos(theta)*g6 - V1/2*sin(theta)*cos(phi)*g4 -
V1/2*sin(theta)*sin(phi)*g5
end
end
# 只求少量本征值
if ishermitian(ham)
nev = min(20, N-1) # 求 20 个特征值
ncv = min(2*nev+20, N) # Lanczos 基向量
v0 = rand(ComplexF64, N) # 随机初始向量
maxiter = 2000
# Shift-invert 模式,求最接近 0 的特征值
val, vec = eigs(ham; nev=nev, ncv=ncv, which=:SM, sigma=0.0, v0=v0, maxiter=maxiter)
else
println("Hamiltonian is not hermitian")
return
end
# 排序
idx_sort = sortperm(real(val))
val_sorted = real(val)[idx_sort]
vec_sorted = vec[:, idx_sort]
fx1 = "val-2.dat"
f1 = open(fx1,"w")
ind = (a->( "%5.2f" a)).(range(1,length(val_sorted),length = length(val_sorted)))
val2 = (a->( "%15.8f" a)).(val_sorted)
writedlm(f1,[ind val2],"\t")
close(f1)
return val_sorted, vec_sorted
end
#-------------------------------------------------------------------------------------------------
function main1()
xn = 80; yn = xn; theta = pi/2.0; phi = 0.0
matset_sparse_block(xn,yn,theta,phi)
# matset(xn,yn,theta,phi)
end
#-------------------------------------------------------------------------------------------------
# @time wave(10,1.0,0.5)
main1()
利用稀疏矩阵的存储方式可以计算更大的体系
总结
鉴于该网站分享的大都是学习笔记,作者水平有限,若发现有问题可以发邮件给我
- yxliphy@gmail.com
也非常欢迎喜欢分享的小伙伴投稿









