Skip to content

Commit b9ed54b

Browse files
dgan181Rogerluo
authored andcommitted
Added Higher-order linear multistep methods using HHL (#4)
Added Higher-order linear multistep
1 parent 6ff72ef commit b9ed54b

File tree

3 files changed

+173
-83
lines changed

3 files changed

+173
-83
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["Roger-luo <hiroger@qq.com>"]
44
version = "0.1.0"
55

66
[deps]
7+
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
78
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
89
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
910
LuxurySparse = "d05aeea4-b7d4-55ac-b691-9e7fabb07ba2"
@@ -12,8 +13,8 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1213
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
1314

1415
[extras]
15-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1616
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
17+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1718

1819
[targets]
1920
test = ["Test", "OrdinaryDiffEq"]

src/lin_diffEq_HHL.jl

Lines changed: 135 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
export Array_QuEuler, prepare_init_state, solve_QuEuler
1+
export array_qudiff, prepare_init_state, LDEMSAlgHHL, bval, aval
2+
export QuEuler, QuLeapfrog, QuAB2, QuAB3, QuAB4
3+
export QuLDEMSProblem
24

5+
using DiffEqBase
36
"""
47
Based on : arxiv.org/abs/1010.2745v2
58
6-
QuArray_Euler(N_t,N,h,A)
7-
prepare_init_state(b,x,h,N_t)
9+
* array_qudiff(N_t,N,h,A) - generates matrix for k-step solver
10+
* prepare_init_state(b,x,h,N_t) - generates inital states
11+
* solve_qudiff - solver
812
913
x' = Ax + b
1014
@@ -15,72 +19,139 @@ export Array_QuEuler, prepare_init_state, solve_QuEuler
1519
* h - step size.
1620
* tspan - time span.
1721
"""
18-
function prepare_init_state(tspan::Tuple,x::Vector,h::Float64,g::Function)
19-
init_state = x;
20-
N_t = round(2*(tspan[2] - tspan[1])/h + 3)
21-
b = similar(g(1))
22-
for i = 1:N_t
23-
if i < (N_t+1)/2
24-
b = g(h*i + tspan[1])
25-
init_state = [init_state;h*b]
26-
else
27-
init_state = [init_state;zero(b)]
28-
end
29-
30-
end
31-
init_state = [init_state;zero(init_state)]
32-
init_state
22+
23+
"""
24+
LDEMSAlgHHL
25+
* step - step for multistep method
26+
* α - coefficients for xₙ
27+
* β - coefficent for xₙ'
28+
"""
29+
abstract type QuODEAlgorithm <: DiffEqBase.AbstractODEAlgorithm end
30+
#abstract type QuODEProblem{uType,tType,isinplace} <: DiffEqBase.AbstractODEProblem{uType,tType,isinplace} end
31+
abstract type LDEMSAlgHHL <: QuODEAlgorithm end
32+
33+
struct QuLDEMSProblem{F,C,U,T} #<: QuODEProblem{uType,tType,isinplace}
34+
A::F
35+
b::C
36+
u0::U
37+
tspan::NTuple{2,T}
38+
39+
#function QuLDEMSProblem(A,b,u0,tspan)
40+
# new{typeof(u0),typeof(tspan),false,typeof(A),typeof(b)}(A,b,u0,tspan)
41+
#end
3342
end
3443

35-
function Array_QuEuler(tspan::Tuple,h::Float64,g::Function)
36-
N_t = round(2*(tspan[2] - tspan[1])/h + 3)
37-
I_mat = Matrix{Float64}(I, size(g(1)));
38-
A_ = I_mat;
39-
zero_mat = zero(I_mat);
40-
tmp_A = Array{Float64,2}(undef,size(g(1)))
41-
42-
for j = 2: N_t +1
43-
A_ = [A_ zero_mat]
44-
end
45-
46-
for i = 2 : N_t+1
47-
tmp_A = g(i*h + tspan[1])
48-
tmp_A = -1*(I_mat + h*tmp_A)
49-
tA_ = copy(zero_mat)
50-
if i<3
51-
tA_ = [tmp_A I_mat]
52-
else
53-
for j = 1:i-3
54-
tA_ = [tA_ zero_mat]
55-
end
56-
if i < (N_t + 1)/2 + 1
57-
tA_ = [tA_ tmp_A I_mat]
58-
else
59-
tA_ = [tA_ -1*I_mat I_mat]
60-
end
44+
"""
45+
Explicit Linear Multistep Methods
46+
"""
47+
struct QuEuler{T}<:LDEMSAlgHHL
48+
step::Int
49+
α::Vector{T}
50+
β::Vector{T}
51+
52+
QuEuler(::Type{T} = Float64) where {T} = new{T}(1,[1.0,],[1.0,])
53+
end
54+
55+
struct QuLeapfrog{T}<:LDEMSAlgHHL
56+
step::Int
57+
α::Vector{T}
58+
β::Vector{T}
59+
60+
QuLeapfrog(::Type{T} = Float64) where {T} = new{T}(2,[0, 1.0],[2.0, 0])
61+
end
62+
struct QuAB2{T}<:LDEMSAlgHHL
63+
step::Int
64+
α::Vector{T}
65+
β::Vector{T}
66+
67+
QuAB2(::Type{T} = Float64) where {T} = new{T}(2,[1.0, 0], [1.5, -0.5])
68+
end
69+
struct QuAB3{T}<:LDEMSAlgHHL
70+
step::Int
71+
α::Vector{T}
72+
β::Vector{T}
73+
QuAB3(::Type{T} = Float64) where {T} = new{T}(3,[1.0, 0, 0], [23/12, -16/12, 5/12])
74+
end
75+
struct QuAB4{T}<:LDEMSAlgHHL
76+
step::Int
77+
α::Vector{T}
78+
β::Vector{T}
79+
80+
QuAB4(::Type{T} = Float64) where {T} = new{T}(4,[1.0, 0, 0, 0], [55/24, -59/24, 37/24, -9/24])
81+
end
82+
83+
function bval(alg::LDEMSAlgHHL,t,h,g::Function)
84+
b = zero(g(1))
85+
for i in 1:(alg.step)
86+
b += alg.β[i]*g(t-(i-1)*h)
6187
end
62-
if i< N_t+1
63-
for j = i+1: N_t+1
64-
tA_ = [tA_ zero_mat]
65-
end
88+
return b
89+
end
90+
91+
function aval(alg::LDEMSAlgHHL,t,h,g::Function)
92+
sz, = size(g(1))
93+
A = Array{ComplexF64}(undef,sz,(alg.step + 1)*sz)
94+
i_mat = Matrix{Float64}(I, size(g(1)))
95+
A[1:sz,sz*(alg.step) + 1:sz*(alg.step + 1)] = i_mat
96+
for i in 1:alg.step
97+
A[1:sz,sz*(i - 1) + 1: sz*i] = -1*(alg.α[alg.step - i + 1]*i_mat + h*alg.β[alg.step - i + 1]*g(t - (alg.step - i)*h))
6698
end
67-
A_ = [A_;tA_]
99+
return A
100+
end
68101

69-
end
70-
A_ = [zero(A_) A_;A_' zero(A_)]
71-
A_
102+
function prepare_init_state(tspan::NTuple{2, Float64},x::Vector,h::Float64,g::Function,alg::LDEMSAlgHHL)
103+
N_t = round(Int, (tspan[2] - tspan[1])/h + 1) #number of time steps
104+
N = nextpow(2,2*N_t + 1) # To ensure we have a power of 2 dimension for matrix
105+
sz, = size(g(1))
106+
init_state = zeros(ComplexF64,2*(N)*sz)
107+
#inital value
108+
init_state[1:sz] = x
109+
for i in 2:N_t
110+
b = bval(alg,h*(i - 1) + tspan[1],h,g)
111+
init_state[Int(sz*(i - 1) + 1):Int(sz*(i))] = h*b
112+
end
113+
return init_state
72114
end
73115

74-
function solve_QuEuler(A::Function, b::Function, x::Vector,tspan::Tuple, h::Float64)
75-
76-
mat = Array_QuEuler(tspan,h,A)
77-
state = prepare_init_state(tspan,x,h,b)
78-
λ = maximum(eigvals(mat))
79-
C_value = minimum(eigvals(mat) .|> abs)*0.1;
80-
n_reg = 12;
81-
mat = 1/*2)*mat
82-
state = state*1/(2*λ) |> normalize!
83-
res = hhlsolve(mat,state, n_reg, C_value)
84-
res = res/λ
85-
res
116+
function array_qudiff(tspan::NTuple{2, Float64},h::Float64,g::Function,alg::LDEMSAlgHHL)
117+
sz, = size(g(1))
118+
i_mat = Matrix{Float64}(I, size(g(1)))
119+
N_t = round(Int, (tspan[2] - tspan[1])/h + 1) #number of time steps
120+
N = nextpow(2,2*N_t + 1) # To ensure we have a power of 2 dimension for matrix
121+
A_ = zeros(ComplexF64, N*sz, N*sz)
122+
# Generates First two rows
123+
@inbounds A_[1:sz, 1:sz] = i_mat
124+
@inbounds A_[sz + 1:2*sz, 1:sz] = -1*(i_mat + h*g(tspan[1]))
125+
@inbounds A_[sz + 1:2*sz,sz+1:sz*2] = i_mat
126+
#Generates additional rows based on k - step
127+
for i in 3:alg.step
128+
@inbounds A_[sz*(i - 1) + 1:sz*i, sz*(i - 3) + 1:sz*i] = aval(QuAB2(),(i-2)*h + tspan[1],h,g)
129+
end
130+
for i in alg.step + 1:N_t
131+
@inbounds A_[sz*(i - 1) + 1:sz*(i), sz*(i - alg.step - 1) + 1:sz*i] = aval(alg,(i - 2)*h + tspan[1],h,g)
132+
end
133+
#Generates half mirroring matrix
134+
for i in N_t + 1:N
135+
@inbounds A_[sz*(i - 1) + 1:sz*(i), sz*(i - 2) + 1:sz*(i - 1)] = -1*i_mat
136+
@inbounds A_[sz*(i - 1) + 1:sz*(i), sz*(i - 1) + 1:sz*i] = i_mat
137+
end
138+
A_ = [zero(A_) A_;A_' zero(A_)]
139+
return A_
86140
end
141+
142+
function DiffEqBase.solve(prob::QuLDEMSProblem{F,C,U,T}, alg::LDEMSAlgHHL, dt = (prob.tspan[2]-prob.tspan[1])/100, n_reg::Int = 12) where {F,C,U,T}
143+
A = prob.A
144+
b = prob.b
145+
tspan = prob.tspan
146+
x = prob.u0
147+
148+
mat = array_qudiff(tspan, dt, A, alg)
149+
state = prepare_init_state(tspan, x, dt, b, alg)
150+
λ = maximum(eigvals(mat))
151+
C_value = minimum(eigvals(mat) .|> abs)*0.01;
152+
mat = 1/*2)*mat
153+
state = state*1/(2*λ) |> normalize!
154+
res = hhlsolve(mat,state, n_reg, C_value)
155+
res = res/λ
156+
return res
157+
end;

test/lin_diffEq_test.jl

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,47 @@ using QuAlgorithmZoo
44
using Test, LinearAlgebra
55
using OrdinaryDiffEq
66

7-
function diffEq_problem(nbit::Int)
7+
function diffeq_problem(nbit::Int)
88
siz = 1<<nbit
99
A = (rand(ComplexF64, siz,siz))
10-
A = (A+A')/2
10+
A = (A + A')/2
1111
b = normalize!(rand(ComplexF64, siz))
1212
x = normalize!(rand(ComplexF64, siz))
1313
A, b, x
1414
end
1515

16-
@testset "Linear_differential_equation_Euler_HHL" begin
17-
N = 1
18-
h = 0.02
19-
tspan = (0.0,0.6)
20-
M, v, x = diffEq_problem(N)
21-
A(t) = M
22-
b(t) = v
23-
res = solve_QuEuler(A, b, x, tspan, h)
16+
@testset "Linear_differential_equations_HHL" begin
17+
N = 1
18+
h = 0.1
19+
tspan = (0.0,0.6)
20+
N_t = round(Int, 2*(tspan[2] - tspan[1])/h + 3)
21+
M, v, x = diffeq_problem(N)
22+
A(t) = M
23+
b(t) = v
24+
n_reg = 12
25+
f(u,p,t) = M*u + v;
26+
prob = ODEProblem(f, x, tspan)
27+
qprob = QuLDEMSProblem(A, b, x, tspan)
28+
sol = solve(prob, Tsit5(), dt = h, adaptive = :false)
29+
s = vcat(sol.u...)
2430

25-
f(u,p,t) = M*u + v;
26-
prob = ODEProblem(f,x,tspan)
27-
sol = solve(prob,Euler(),dt = 0.02,adaptive = :false)
28-
s = vcat(sol.u...)
29-
N_t = round(2*(tspan[2] - tspan[1])/h + 3);
30-
r = res[Int((N_t+1)*2+2^N+1): Int((N_t+1)*2+2^N + N_t - 1)] # range of relevant values in the obtained state.
31-
@test isapprox.(s,r,atol = 0.05) |> all
32-
end
31+
res = solve(qprob, QuEuler(), h, n_reg)
32+
r = res[(N_t + 1)*2 + 2^N - 1: (N_t + 1)*2 + 2^N + N_t - 3] # range of relevant values in the obtained state.
33+
@test isapprox.(s, r, atol = 0.5) |> all
34+
35+
res = solve(qprob, QuLeapfrog(), h, n_reg)
36+
r = res[(N_t + 1)*2 + 2^N - 1: (N_t + 1)*2 + 2^N + N_t - 3] # range of relevant values in the obtained state.
37+
@test isapprox.(s, r, atol = 0.3) |> all
38+
39+
res = solve(qprob, QuAB2(), h,n_reg)
40+
r = res[(N_t + 1)*2 + 2^N - 1: (N_t + 1)*2 + 2^N + N_t - 3] # range of relevant values in the obtained state.
41+
@test isapprox.(s, r, atol = 0.3) |> all
42+
43+
res = solve(qprob, QuAB3(), h,n_reg)
44+
r = res[(N_t + 1)*2 + 2^N - 1: (N_t + 1)*2 + 2^N + N_t - 3] # range of relevant values in the obtained state.
45+
@test isapprox.(s, r, atol = 0.3) |> all
46+
47+
res = solve(qprob, QuAB4(), h ,n_reg)
48+
r = res[(N_t + 1)*2 + 2^N - 1: (N_t + 1)*2 + 2^N + N_t - 3] # range of relevant values in the obtained state.
49+
@test isapprox.(s, r, atol = 0.3) |> all
50+
end;

0 commit comments

Comments
 (0)