From c219ebfbfc750e260e52c9b57984582b4e71dfcf Mon Sep 17 00:00:00 2001 From: Kai-Hsin Wu Date: Fri, 8 Sep 2023 16:03:59 -0400 Subject: [PATCH] implemented expm multiply (#585) * Refactor Expr 1) moving Hamiltonian/StepHamiltonian and ThreadedMatrix to Operator module 2) moving all linalg associate to 1) are moving to Operator module. * BloqadeExpr Change 1) move linalg related to elementary structs (PermMatrix,Diagonal,SparseMatrixCSR/CSC) to Lowlevel/backends/ 2) rename module Operator -> Lowlevel to avoid confusion with Yao 3) rename test/linalg.jl to test/linalg_mul.jl 4) [FIX] mul! testing case for ParallelMergeCSR is not properly dispatched. 5) add trace() and bind to LinearAlgebra.tr() for PermMatrix,Diagonal and SparseMatrixCSR/CSC 6) add test/linalg_tr.jl for testing tr() * Get types info on Hamiltonain 1) add precision_type() for Hamiltonian/StepHamiltonian 2) add highest_type() for Hamiltonian/StepHamiltonian * add overload for SparseMatrixCSR, and remove redundant print * Move ValHamiltionain from BloqadeKrylov to BloqadeExpr.Lowlevel * 1) Add more testing cases for ValHamiltonian 2) move linalg associate to Hamiltonian etc to linalg.jl * fix ASCII for '-' causing error on julia-v1.6 * Simplify Lowlevel data structure 1) Remove StepHamiltonian 2) Rename ValHamiltonian -> SumOfLinop * temp up * expm_multiply first version 1) Add expm_multiply, tested but this version consume more memory 2) Add get_optimal_sm() to get the optimal s and m_star. currently the one norm of power p is get exactly, not estimate (need to implement one norm est ! * Add onenormest 1) add onenormest() using block algorithm for 1 norm estimation * update onenorm for expm_multiply 1) swap out the onenorm in expm_multiply using onenormest() 2) reinstat all the testing cases. 3) checking testing of expm_multiply * fix bug in tA * 1) modify SumOfLinop to take tuple of static terms instead of Hamiltonian 2) change test, linalg, size, types related to accomadate change. * 1) modify onenormest and expm_multiply to accept generic type instead of AbstractMatrix. 2) modify parts to accompany change of SumOfLinop * refactor Expr 1) additional field types for SumOfLinop Hermitian, SkewHermitian and RegularLinop 2) adjoint, Base.:*, add_I for lazy evaluate in the case input is Hermitian/SkewHermitian * fix the bug in onenormest. 1) this is dirty version. need to be clean 2) fix the bug in calculating h in onenormest * clean up the code * integrated expm_multiply into integrators 1) fix bug in precision_type/highest_type/eltype for SumOfLinop by considering also dtype of fvals 2) add testing case for expm_multiply backend 3) add expmv_backend as additional options, and update docstring. 4) fix bug in get_optimal_sm when t is negative. * add AD for Hamiltonian 1) add FowardDiff in BloqadeExpr 2) add derivative(H,t) for calculating Hamiltonian H'(t) 3) add testing case * start developing of adaptive cft * Bump patch version * Refactor Expr (#572) * Refactor Expr 1) moving Hamiltonian/StepHamiltonian and ThreadedMatrix to Operator module 2) moving all linalg associate to 1) are moving to Operator module. * BloqadeExpr Change 1) move linalg related to elementary structs (PermMatrix,Diagonal,SparseMatrixCSR/CSC) to Lowlevel/backends/ 2) rename module Operator -> Lowlevel to avoid confusion with Yao 3) rename test/linalg.jl to test/linalg_mul.jl 4) [FIX] mul! testing case for ParallelMergeCSR is not properly dispatched. 5) add trace() and bind to LinearAlgebra.tr() for PermMatrix,Diagonal and SparseMatrixCSR/CSC 6) add test/linalg_tr.jl for testing tr() * Get types info on Hamiltonain 1) add precision_type() for Hamiltonian/StepHamiltonian 2) add highest_type() for Hamiltonian/StepHamiltonian * add overload for SparseMatrixCSR, and remove redundant print * Move ValHamiltionain from BloqadeKrylov to BloqadeExpr.Lowlevel * 1) Add more testing cases for ValHamiltonian 2) move linalg associate to Hamiltonian etc to linalg.jl * fix ASCII for '-' causing error on julia-v1.6 * Simplify Lowlevel data structure 1) Remove StepHamiltonian 2) Rename ValHamiltonian -> SumOfLinop * 1) remove BloqadeKrylov from toml 2) remove redundant comments --------- Co-authored-by: Kai-Hsin Wu Co-authored-by: Kai-Hsin Wu * remove redundant * fix missing end on runtest.jl after merge * add compat for ForwardDiff * add eltype() for threadedmatrix * remove hard constrain on fix-time check for CFET clocks * re-removing tests. --------- Co-authored-by: Kai-Hsin Wu Co-authored-by: Kai-Hsin Wu Co-authored-by: Phillip Weinberg --- lib/BloqadeExpr/Project.toml | 2 + lib/BloqadeExpr/src/BloqadeExpr.jl | 13 +- lib/BloqadeExpr/src/Lowlevel/Lowlevel.jl | 5 + lib/BloqadeExpr/src/Lowlevel/linalg.jl | 150 +++++++- lib/BloqadeExpr/src/Lowlevel/types.jl | 50 ++- lib/BloqadeExpr/test/linalg_addI.jl | 62 ++++ lib/BloqadeExpr/test/linalg_derivative.jl | 33 ++ lib/BloqadeExpr/test/linalg_mul.jl | 4 +- lib/BloqadeExpr/test/runtests.jl | 15 + lib/BloqadeExpr/test/types.jl | 65 +++- .../expmv/3-by-3.1000._3.0_.exm_mply.impl | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._3.0_.exm_mply.ovh | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._3.0_.exmp | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._3.0_.png | Bin 0 -> 39106 bytes .../compares/expmv/3-by-3.1000._3.0_.ts | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._4.0_.exm_mply.impl | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._4.0_.exm_mply.ovh | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._4.0_.exmp | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._4.0_.png | Bin 0 -> 40040 bytes .../compares/expmv/3-by-3.1000._4.0_.ts | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._5.0_.exm_mply.impl | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._5.0_.exm_mply.ovh | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._5.0_.exmp | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._5.0_.png | Bin 0 -> 36239 bytes .../compares/expmv/3-by-3.1000._5.0_.ts | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._6.0_.exm_mply.impl | Bin 0 -> 8000 bytes .../expmv/3-by-3.1000._6.0_.exm_mply.ovh | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._6.0_.exmp | Bin 0 -> 8000 bytes .../compares/expmv/3-by-3.1000._6.0_.png | Bin 0 -> 31432 bytes .../compares/expmv/3-by-3.1000._6.0_.ts | Bin 0 -> 8000 bytes lib/BloqadeKrylov/compares/expmv/3-by-3.jl | 64 ++++ lib/BloqadeKrylov/compares/expmv/Project.toml | 8 + .../compares/expmv/chain_sincos.jl | 31 ++ lib/BloqadeKrylov/compares/expmv/plot.jl | 34 ++ lib/BloqadeKrylov/compares/expmv/readfiles.py | 22 ++ lib/BloqadeKrylov/compares/expmv/tools.jl | 106 ++++++ lib/BloqadeKrylov/src/BloqadeKrylov.jl | 6 + lib/BloqadeKrylov/src/adapt_cfet.jl | 212 +++++++++++ lib/BloqadeKrylov/src/cfet.jl | 19 +- lib/BloqadeKrylov/src/common.jl | 20 +- lib/BloqadeKrylov/src/expm_multiply.jl | 269 ++++++++++++++ lib/BloqadeKrylov/src/krylov.jl | 3 +- lib/BloqadeKrylov/src/magnus.jl | 2 +- lib/BloqadeKrylov/src/onenormest.jl | 334 ++++++++++++++++++ lib/BloqadeKrylov/test/Project.toml | 1 + lib/BloqadeKrylov/test/cfet42_sinX.jl | 33 ++ lib/BloqadeKrylov/test/expm_multiply.jl | 132 +++++++ lib/BloqadeKrylov/test/onenormest.jl | 165 +++++++++ lib/BloqadeKrylov/test/runtests.jl | 12 +- 49 files changed, 1820 insertions(+), 52 deletions(-) create mode 100644 lib/BloqadeExpr/test/linalg_addI.jl create mode 100644 lib/BloqadeExpr/test/linalg_derivative.jl create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.impl create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.ovh create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exmp create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.png create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.ts create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.impl create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.ovh create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exmp create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.png create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.ts create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.impl create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.ovh create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exmp create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.png create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.ts create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exm_mply.impl create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exm_mply.ovh create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exmp create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.png create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.ts create mode 100644 lib/BloqadeKrylov/compares/expmv/3-by-3.jl create mode 100644 lib/BloqadeKrylov/compares/expmv/Project.toml create mode 100644 lib/BloqadeKrylov/compares/expmv/chain_sincos.jl create mode 100644 lib/BloqadeKrylov/compares/expmv/plot.jl create mode 100644 lib/BloqadeKrylov/compares/expmv/readfiles.py create mode 100644 lib/BloqadeKrylov/compares/expmv/tools.jl create mode 100644 lib/BloqadeKrylov/src/adapt_cfet.jl create mode 100644 lib/BloqadeKrylov/src/expm_multiply.jl create mode 100644 lib/BloqadeKrylov/src/onenormest.jl create mode 100644 lib/BloqadeKrylov/test/expm_multiply.jl create mode 100644 lib/BloqadeKrylov/test/onenormest.jl diff --git a/lib/BloqadeExpr/Project.toml b/lib/BloqadeExpr/Project.toml index 3bf76ed4e..826c1a3e0 100644 --- a/lib/BloqadeExpr/Project.toml +++ b/lib/BloqadeExpr/Project.toml @@ -6,6 +6,7 @@ version = "0.1.14" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" BitBasis = "50ba71b6-fa0f-514d-ae9a-0916efc90dcf" BloqadeLattices = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe4" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -28,6 +29,7 @@ LaTeXStrings = "1" LuxurySparse = "0.7" MLStyle = "0.4" ParallelMergeCSR = "1.0.2" +ForwardDiff="0.10" Polyester = "0.7.3" Preferences = "1.3" SparseMatricesCSR = "0.6.7" diff --git a/lib/BloqadeExpr/src/BloqadeExpr.jl b/lib/BloqadeExpr/src/BloqadeExpr.jl index 4ed26ba79..9175c0f01 100644 --- a/lib/BloqadeExpr/src/BloqadeExpr.jl +++ b/lib/BloqadeExpr/src/BloqadeExpr.jl @@ -19,7 +19,9 @@ using BloqadeLattices: BoundedLattice, rydberg_interaction_matrix include("Lowlevel/Lowlevel.jl") -using .Lowlevel: Hamiltonian, SumOfLinop, ThreadedMatrix, storage_size, to_matrix, precision_type, highest_type + +using .Lowlevel: Hamiltonian, SumOfLinop, ThreadedMatrix, storage_size, to_matrix, precision_type, highest_type, add_I, derivative, RegularLinop, isskewhermitian + export rydberg_h, rydberg_h_3, @@ -47,7 +49,14 @@ export rydberg_h, emulate!, precision_type, highest_type, - to_matrix + + to_matrix, + add_I, + derivative, + RegularLinop, # abstype + SkewHermitian, # abstype + isskewhermitian + include("assert.jl") include("space.jl") diff --git a/lib/BloqadeExpr/src/Lowlevel/Lowlevel.jl b/lib/BloqadeExpr/src/Lowlevel/Lowlevel.jl index 06dabdb1b..84f20c6e1 100644 --- a/lib/BloqadeExpr/src/Lowlevel/Lowlevel.jl +++ b/lib/BloqadeExpr/src/Lowlevel/Lowlevel.jl @@ -9,12 +9,17 @@ using Preferences using Adapt using LaTeXStrings using LinearAlgebra +using ForwardDiff +using Base.Threads: nthreads + export Hamiltonian, SumOfLinop export ThreadedMatrix export set_backend export storage_size, to_matrix export precision_type, highest_type +export add_I, isskewhermitian + #export ValH, get_f # convert StepHamiltonian to ValHamiltonian include("types.jl") diff --git a/lib/BloqadeExpr/src/Lowlevel/linalg.jl b/lib/BloqadeExpr/src/Lowlevel/linalg.jl index 85c7188e0..189b27b7e 100644 --- a/lib/BloqadeExpr/src/Lowlevel/linalg.jl +++ b/lib/BloqadeExpr/src/Lowlevel/linalg.jl @@ -1,6 +1,6 @@ #************************************************************** # Here, one can find the linalg API for -# 1. Hamiltonian/SumOfLinop +# 1. Hamiltonian/SumOfLinop # 2. Binding of standard LinearAlgebra functions # to the backend of choice for ThreadedMatrix #************************************************************** @@ -10,32 +10,50 @@ #-------------------------------- function LinearAlgebra.mul!(C::AbstractVecOrMat, A::SumOfLinop, B::AbstractVecOrMat) fill!(C, zero(eltype(C))) - for (f, term) in zip(A.fvals, A.h.ts) + for (f, term) in zip(A.fvals, A.ts) mul!(C, term, B, f, one(f)) end return C end ## additionals, maybe we don't need this. -function Base.:*(a::Number, b::SumOfLinop) - return SumOfLinop(b.fvals .* a, b.h) + +function Base.:*(a::Number,b::SumOfLinop) + return SumOfLinop{RegularLinop}(b.fvals .* a, b.ts) +end + +function Base.:*(a::Complex,b::SumOfLinop{T}) where {T} + if real(a) ≈ 0 + return SumOfLinop{anti_type(T)}(b.fvals .* a, b.ts) + elseif imag(a) ≈ 0 + return SumOfLinop{T}(b.fvals .* a, b.ts) + else + return SumOfLinop{RegularLinop}(b.fvals .* a, b.ts) + end end + +function Base.:*(a::Real,b::SumOfLinop{T}) where {T} + return SumOfLinop{T}(b.fvals .* a, b.ts) +end + Base.:*(n, m::T) where {T <: ThreadedMatrix} = n * m.matrix + +#= function Base.:+(a::SumOfLinop, b::SumOfLinop) - if !(a === b) + if !(a.ts === b.ts) error("two SumOfLinop must share the same static terms ") end - return SumOfLinop(a.fvals + b.fvals, a.h) + return SumOfLinop(a.fvals + b.fvals, a.ts) end function Base.:-(a::SumOfLinop, b::SumOfLinop) - if !(a === b) + if !(a.ts === b.ts) error("two SumOfLinop must share the same static terms ") end - return SumOfLinop(a.fvals - b.fvals, a.h) + return SumOfLinop(a.fvals - b.fvals, a.ts) end - +=# # if BloqadeExpr was the backend of choice, then ThreadedMatrix will have the SparseMatrixCSC type @@ -47,6 +65,7 @@ LinearAlgebra.mul!(C, A::ThreadedMatrix, B, α, β) = bmul!(C, A.matrix, B, α, ##-------------------------------- mul! + ## opnorm() # -------------------------------- function LinearAlgebra.opnorm(h::SumOfLinop, p = 2) @@ -59,7 +78,7 @@ end ## tr() # -------------------------------- function LinearAlgebra.tr(A::SumOfLinop) - return sum(zip(A.fvals, A.h.ts)) do (f, t) + return sum(zip(A.fvals, A.ts)) do (f, t) return f * tr(t) end end @@ -77,3 +96,114 @@ end LinearAlgebra.tr(A::ThreadedMatrix) = tr(A.matrix) ##-------------------------------- tr() + + +## check if is hermitian. +# -------------------------------- +LinearAlgebra.ishermitian(A::SumOfLinop{<: LinearAlgebra.Hermitian}) = true +LinearAlgebra.ishermitian(A::SumOfLinop) = false + +isskewhermitian(A::SumOfLinop{<: SkewHermitian}) = true +isskewhermitian(A::SumOfLinop) = false + + +## adjoint() +function LinearAlgebra.adjoint(A::SumOfLinop{<:LinearAlgebra.Hermitian}) + return A +end +function LinearAlgebra.adjoint(A::SumOfLinop{<:SkewHermitian}) + return SumOfLinop{SkewHermitian}(A.fvals.*(-1), A.ts) +end +function LinearAlgebra.adjoint(A::SumOfLinop{OPTYPE}) where {OPTYPE} + return SumOfLinop{OPTYPE}(conj.(A.fvals), map(adjoint,A.ts)) +end + +## add constant identity term into SumOfLinop +# [NOTE] this does not check the type consistency of c w.r.t. A.fvals. +function add_I(A,c::Number) + Iop = LinearAlgebra.I(size(A,1)) + return A + c*Iop +end + +function add_I(A::SumOfLinop, c::Number) + Iop = LinearAlgebra.I(size(A,1)) + + if nthreads() > 1 + return SumOfLinop{RegularLinop}((A.fvals...,c),(A.ts...,ThreadedMatrix(Iop))) + else + return SumOfLinop{RegularLinop}((A.fvals...,c),(A.ts...,Iop)) + end + +end + +function add_I(A::SumOfLinop{<:LinearAlgebra.Hermitian}, c::Real) + # check backend: + Iop = LinearAlgebra.I(size(A,1)) + + if nthreads() > 1 + return SumOfLinop{LinearAlgebra.Hermitian}((A.fvals...,c),(A.ts...,ThreadedMatrix(Iop))) + else + return SumOfLinop{LinearAlgebra.Hermitian}((A.fvals...,c),(A.ts...,Iop)) + end + +end +function add_I(A::SumOfLinop{<:LinearAlgebra.Hermitian}, c::Complex) + # check backend: + Iop = LinearAlgebra.I(size(A,1)) + + OPTYPE=RegularLinop + if imag(c) ≈ 0 + OPTYPE = LinearAlgebra.Hermitian + end + + if nthreads() > 1 + return SumOfLinop{OPTYPE}((A.fvals...,c),(A.ts...,ThreadedMatrix(Iop))) + else + return SumOfLinop{OPTYPE}((A.fvals...,c),(A.ts...,Iop)) + end + +end + +function add_I(A::SumOfLinop{<:SkewHermitian}, c::Real) + # check backend: + Iop = LinearAlgebra.I(size(A,1)) + + if nthreads() > 1 + return SumOfLinop{RegularLinop}((A.fvals...,c),(A.ts...,ThreadedMatrix(Iop))) + else + return SumOfLinop{RegularLinop}((A.fvals...,c),(A.ts...,Iop)) + end + +end +function add_I(A::SumOfLinop{<:SkewHermitian}, c::Complex) + # check backend: + Iop = LinearAlgebra.I(size(A,1)) + + OPTYPE=RegularLinop + if real(c) ≈ 0 + OPTYPE = SkewHermitian + end + + if nthreads() > 1 + return SumOfLinop{OPTYPE}((A.fvals...,c),(A.ts...,ThreadedMatrix(Iop))) + else + return SumOfLinop{OPTYPE}((A.fvals...,c),(A.ts...,Iop)) + end + +end + + + +## taking derivative of Hamiltonian and evaluate at time +## H'(t) +## this returns a SumOfLinop with fvals being the derivative +#function derivative(h::Hamiltonian, t::Real) +# return SumOfLinop{Hermitian}(ForwardDiff.derivative.(h.fs,t), h.ts) +#end + +function derivative(h::Hamiltonian, t::Real) + ## remove terms that are zero + fvals = ForwardDiff.derivative.(h.fs,t) + mask = collect(fvals .!= 0) + return SumOfLinop{Hermitian}(fvals[mask],h.ts[mask]) +end diff --git a/lib/BloqadeExpr/src/Lowlevel/types.jl b/lib/BloqadeExpr/src/Lowlevel/types.jl index 1e9efc50f..3aea05199 100644 --- a/lib/BloqadeExpr/src/Lowlevel/types.jl +++ b/lib/BloqadeExpr/src/Lowlevel/types.jl @@ -24,8 +24,11 @@ end Base.size(m::ThreadedMatrix) = size(m.matrix) Base.size(m::ThreadedMatrix, i) = size(m.matrix)[i] +Base.eltype(m::ThreadedMatrix) = eltype(m.matrix) Base.pointer(m::T) where {T <: Diagonal} = pointer(m.diag) + +precision_type(m::T) where {T <: Number} = real(typeof(m)) precision_type(m::T) where {T <: Diagonal} = real(eltype(m)) precision_type(m::T) where {T <: PermMatrix} = real(eltype(m)) precision_type(m::T) where {T <: SparseMatrixCSR} = real(eltype(m)) @@ -61,8 +64,23 @@ function highest_type(h::Hamiltonian) return promote_type(tp...) end + +Base.eltype(h::Hamiltonian) = highest_type(h) + + Adapt.@adapt_structure Hamiltonian + + + +abstract type RegularLinop end +abstract type SkewHermitian end + +anti_type(::Type{LinearAlgebra.Hermitian}) = SkewHermitian +anti_type(::Type{SkewHermitian}) = LinearAlgebra.Hermitian +anti_type(::Type{RegularLinop}) = RegularLinop + + """ struct SumOfLinop A low-level linear-map object that explicitly evaluate time dependent @@ -70,18 +88,32 @@ coefficients at given time `t` fvals = fs(t) of Hamiltonian. This object supports the linear map interface `mul!(Y, H, X)`. """ -struct SumOfLinop{VS,FS,TS} + +struct SumOfLinop{OPTYPE, VS,TS} fvals::VS - h::Hamiltonian{FS,TS} + ts::TS + function SumOfLinop{OPTYPE}(fvals::VS, ts::TS) where {OPTYPE, VS, TS} + return new{OPTYPE,VS,TS}(fvals, ts) + end end -Base.size(h::SumOfLinop, idx::Int) = size(h.h, idx) -Base.size(h::SumOfLinop) = size(h.h) -precision_type(h::SumOfLinop) = precision_type(h.h) -highest_type(h::SumOfLinop) = highest_type(h.h) +Base.size(h::SumOfLinop, idx::Int) = size(h.ts[1], idx) +Base.size(h::SumOfLinop) = size(h.ts[1]) +function precision_type(h::SumOfLinop) + tp = unique(precision_type.(h.ts)) + tp2 = unique(precision_type.(h.fvals)) + tp = unique((tp...,tp2...)) + return Union{tp...} +end +function highest_type(h::SumOfLinop) + tp = unique(eltype.(h.ts)) + tp2 = unique(typeof.(h.fvals)) + return promote_type(tp...,tp2...) +end +Base.eltype(h::SumOfLinop) = highest_type(h) function to_matrix(h::SumOfLinop) - return sum(zip(h.fvals, h.h.ts)) do (f, t) + return sum(zip(h.fvals, h.ts)) do (f, t) return f * t end end @@ -93,9 +125,9 @@ function _getf(h::Hamiltonian,t) ) end -(h::Hamiltonian)(t::Real) = SumOfLinop(_getf(h,t), h) - +## lowering by Hamiltonian, so its Hermitian type +(h::Hamiltonian)(t::Real) = SumOfLinop{LinearAlgebra.Hermitian}(_getf(h,t), h.ts) diff --git a/lib/BloqadeExpr/test/linalg_addI.jl b/lib/BloqadeExpr/test/linalg_addI.jl new file mode 100644 index 000000000..fae5f30b3 --- /dev/null +++ b/lib/BloqadeExpr/test/linalg_addI.jl @@ -0,0 +1,62 @@ +using Test +using BloqadeExpr +using LinearAlgebra +using Random +using LuxurySparse +using BloqadeExpr: Hamiltonian + +atoms = [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5)] +h = rydberg_h(atoms; Ω = 1.0, Δ = sin) + +hlist = Hamiltonian(Float64, h) + + +@testset "add_I for SumOfLinop" begin + + Ht = hlist(0.1) + + @test ishermitian(Ht) + # these values are not mutated and can be re-used throughout the unit tests + H1 = add_I(Ht, -0.5) + H2 = add_I(Ht, -0.5+1im) + H3 = add_I(Ht, 0.5im) + + @test ishermitian(H1) == true + @test isskewhermitian(H1) == false + + @test ishermitian(H2) == false + @test isskewhermitian(H2) == false + + @test ishermitian(H3) == false + @test isskewhermitian(H3) == false + + + Ha = 1.0im*Ht + + @test ishermitian(Ha) == false + @test isskewhermitian(Ha) == true + + H1a = add_I(Ha, -0.5) + H2a = add_I(Ha, -0.5+1im) + H3a = add_I(Ha, 0.5im) + + @test ishermitian(H1a) == false + @test isskewhermitian(H1a) == false + + @test ishermitian(H2a) == false + @test isskewhermitian(H2a) == false + + @test ishermitian(H3a) == false + @test isskewhermitian(H3a) == true + + + + + M = to_matrix(Ht) + S = add_I(M, 1+3.) + @test S == M + (1+3.)*LinearAlgebra.I(size(M,1)) + + + + +end \ No newline at end of file diff --git a/lib/BloqadeExpr/test/linalg_derivative.jl b/lib/BloqadeExpr/test/linalg_derivative.jl new file mode 100644 index 000000000..daee7ae31 --- /dev/null +++ b/lib/BloqadeExpr/test/linalg_derivative.jl @@ -0,0 +1,33 @@ +using Test +using BloqadeExpr +using LinearAlgebra +using Random +using LuxurySparse +using BloqadeExpr: Hamiltonian + + + + +@testset "derivative for Hamiltonain" begin + + atoms = [(1, 1)] + h = rydberg_h(atoms; Ω = 1.0, Δ = sin) + hlist = Hamiltonian(Float64, h) + + h2 = rydberg_h(atoms; Ω = 0.0, Δ = cos) + htar = Hamiltonian(Float64, h2) + + println(htar.ts) + println(hlist.ts) + + for t in 0:0.1:2 + src = derivative(hlist, t) + tar = htar(t) + + @test to_matrix(src) == to_matrix(tar) + + end + + + +end \ No newline at end of file diff --git a/lib/BloqadeExpr/test/linalg_mul.jl b/lib/BloqadeExpr/test/linalg_mul.jl index 2b0595ab1..18c32ad4f 100644 --- a/lib/BloqadeExpr/test/linalg_mul.jl +++ b/lib/BloqadeExpr/test/linalg_mul.jl @@ -21,7 +21,9 @@ end C = zeros(ComplexF64, 1 << 5) B = rand(ComplexF64, 1 << 5) -@test mul!(zeros(ComplexF64, 1 << 5), hlist(0.1), B) ≈ H * B +ot = zeros(ComplexF64, 1 << 5) +mul!(ot, hlist(0.1), B) +@test ot ≈ H * B # ThreadedMatrix unit tests # ThreadedMatrix with SparseMatrixCSC diff --git a/lib/BloqadeExpr/test/runtests.jl b/lib/BloqadeExpr/test/runtests.jl index 605abb46e..20fcfcf34 100644 --- a/lib/BloqadeExpr/test/runtests.jl +++ b/lib/BloqadeExpr/test/runtests.jl @@ -7,6 +7,12 @@ if "docstring" in ARGS exit() end + +@testset "linear algebra on derivative of H" begin + include("linalg_derivative.jl") +end + + @testset "linear algebra on linear map: mul!()" begin include("linalg_mul.jl") end @@ -16,6 +22,11 @@ end end +@testset "linear algebra add_I()" begin + include("linalg_addI.jl") +end + + @testset "assertions" begin include("assert.jl") end @@ -54,3 +65,7 @@ end include("printings.jl") end +# @testset "3-level supports" begin +# include("3-level_supports.jl") +# end + diff --git a/lib/BloqadeExpr/test/types.jl b/lib/BloqadeExpr/test/types.jl index 32b6ee7d9..c1bd9dc82 100644 --- a/lib/BloqadeExpr/test/types.jl +++ b/lib/BloqadeExpr/test/types.jl @@ -110,7 +110,9 @@ end @test LinearAlgebra.opnorm(step_hamiltonian,1) == 1.0 end -@testset "ValHamiltonian" begin + +@testset "SumOfLinop " begin + Ham = BloqadeExpr.Hamiltonian(Float64, SumOfX(1, sin) + SumOfZ(1,cos)) @@ -119,40 +121,79 @@ end StepHam = Ham(0.645) + @test ishermitian(StepHam) == true + + # check coefficents: - for (i,f) in enumerate(StepHam.h.fs) + for (i,f) in enumerate(Ham.fs) @test f(t) == StepHam.fvals[i] end - @test StepHam.h === Ham + @test StepHam.ts === Ham.ts + #= # check basic algos :+ AddOp = StepHam + StepHam - @test AddOp.h === StepHam.h - @test AddOp.h === Ham + @test AddOp.ts === StepHam.ts + @test AddOp.ts === Ham.ts - for (i,f) in enumerate(StepHam.h.fs) + for (i,f) in enumerate(Ham.fs) @test AddOp.fvals[i] == f(t) + f(t) end + @test LinearAlgebra.is_hermitian(AddOp) == true + # check basic algos :- SubVHam = StepHam - StepHam - @test SubVHam.h === StepHam.h - @test SubVHam.h === Ham + @test SubVHam.ts === StepHam.ts + @test SubVHam.ts === Ham.ts - for (i,f) in enumerate(StepHam.h.fs) + for (i,f) in enumerate(Ham.fs) @test SubVHam.fvals[i] == f(t) - f(t) end + @test LinearAlgebra.is_hermitian(SubVHam) == true + =# + # check basic algos :* MulVHam = 0.5*StepHam - @test MulVHam.h === StepHam.h - @test MulVHam.h === Ham + @test MulVHam.ts === StepHam.ts + @test MulVHam.ts === Ham.ts - for (i,f) in enumerate(StepHam.h.fs) + for (i,f) in enumerate(Ham.fs) @test MulVHam.fvals[i] == 0.5*f(t) end + @test ishermitian(MulVHam) == true + @test isskewhermitian(MulVHam) == false + + + # check basic algos :* + MulVHam2 = 0.5im*StepHam + @test MulVHam2.ts === StepHam.ts + @test MulVHam2.ts === Ham.ts + + for (i,f) in enumerate(Ham.fs) + @test MulVHam2.fvals[i] == 0.5im*f(t) + end + + @test ishermitian(MulVHam2) == false + @test isskewhermitian(MulVHam2) == true + + + # check basic algos :* + MulVHam3 = (2.3+0.1im)*StepHam + @test MulVHam3.ts === StepHam.ts + @test MulVHam3.ts === Ham.ts + + for (i,f) in enumerate(Ham.fs) + @test MulVHam3.fvals[i] == (2.3+0.1im)*f(t) + end + + @test ishermitian(MulVHam3) == false + @test isskewhermitian(MulVHam3) == false + + end diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.impl b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.impl new file mode 100644 index 0000000000000000000000000000000000000000..1b11b3cd68b2287a41c333fdcb43b5818eee7f55 GIT binary patch literal 8000 zcmeHLL2kn^4D0%VZfpDhZ}b^^(tyQ0gn&R=mc1fKFN7qLk`*J}`ue#1eSR8#UAOqr z@JTW9z_Y&J7xn_o?kB4o?K@k4)N@ts4L(4%FYti9eCS-9?XTvzi}#Vzt9q}$%dg@o zpQye%&;2;YbKv~D#O@rUyhxwTE1g@P#e*-9?*Z~h!|(Rq%ATuNulU(|wT}Hb#=bbu zvCCs!Rh;#4brBDFAn!rttLm-~c))00)Q^t%e@mTnH81Knns@cgQ!)0Zcy4_a4}E}q z4wbK}!v`46fqE}i`>Fn)?fX{oRK3?n@w4?vH=1|#%$pUvz7a2*SGuY?e1N!rh)>*p zPn)%eTYE25`H%Yjm%g{}yYSsPR`XOpRmXi)yr>@KM}3t(+c(nn=Ckwl_Hp?xuWD|$ vpUaEpVm-&MuA0YlaP0PDor-7qs=jA^|Mx-FKB|1qd$B#ARr_4kCwi{Gs7Xz* literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.ovh b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exm_mply.ovh new file mode 100644 index 0000000000000000000000000000000000000000..f061b359adc07ff64773dc5735aab006932d8cf1 GIT binary patch literal 8000 zcmeIyF%1Af2n0d=D?tDP2_S>{=KISs75B=&3)n#qvw#kCpaXZn0S<70103K02ROh1 c4sd`29N+*4IKTl8aDW3G-~b2yIFOfnH1pZNGXMYp literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exmp b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.exmp new file mode 100644 index 0000000000000000000000000000000000000000..83ab29e1f3b83289a2de4ef57eab35f26c0f8db7 GIT binary patch literal 8000 zcmeH~$qmCW3(IU0m&sTQ3venWq)o5?@c}qeYiJb z);>Isb^cenb*bi~d8#L_e(WlaPD!2;9e!+xUrF2%eHBLsNA;?!@;}vUJ~r=#&aZKF zT~f!fThHlT{mSp^{o2pCcn`Lt>aZbsYFB=ZyL_iZuS5?ut~NTT@ll)nQBt?7cX{}s z)^+|-9r=(vweiC$jt-(%5{FeB-C3yPb@o}tyV^Kdk5%W*{NZYS$b9GikIMRHeYXx| zA7me7ALJb59>_iL&3l0F=GoajH}pgE@Q3?3?Dir3e6MfaK1ZKEZym@!IM+US0U4MB A5C8xG literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.png b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.png new file mode 100644 index 0000000000000000000000000000000000000000..d7e61f8df9b87ee82562a9d741701894a09f35dc GIT binary patch literal 39106 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 literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.ts b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._3.0_.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ca9a907730543f3e6ea35a94dec8114f76f2273 GIT binary patch literal 8000 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 AF#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.impl b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.impl new file mode 100644 index 0000000000000000000000000000000000000000..b11fbb7b07cc09ed0d9c879b45a8f4f005132c3d GIT binary patch literal 8000 zcmeHHNe+WB4CImAdMNGxA5p1cE|x6s4nc6S;>>1Kx^Lszi|XstJ>80wc8JQj->AkdQ$cJS$SH#g!A5WyzV~rqi4J?+MjjS`f@m~ zPv_)t=%aEx?Y$M}#e;_`_PIJoc3!WZmnZGV ztJ}?^b5#3t`qsWSw^i4Qze)~kZs1W@nIk)|SI^7i_UzS@c+$N$&n#WZx9h&kM|wZn g99mqrpElQQT$R67_b&L==g@v9tIxT5e(QVs0d%)@y#N3J literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.ovh b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exm_mply.ovh new file mode 100644 index 0000000000000000000000000000000000000000..43392ce9501bd96e5463677355dc999e96fb44af GIT binary patch literal 8000 zcmeIyu@L|;2m>(+?>{pKjDgam_dQD8i+>legC1r99q2#@?tlXv-~b0WzyS_$fCC)h Y00%h00S<70103K02ROh14*YYV0gwz2p#T5? literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exmp b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.exmp new file mode 100644 index 0000000000000000000000000000000000000000..5427eea375f57a7e694b08898800549a354ebf18 GIT binary patch literal 8000 zcmeIyu@L|;2m>)D^ZsLTz!)e^df%hez4&(lJLq8+(18wg;0`#z0S<70103K02ROh1 Y4sd`29N+*4IKTl8aDW3G;J`lz8uRq>F#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.png b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._4.0_.png new file mode 100644 index 0000000000000000000000000000000000000000..45504c2059795e5727ae98fafe305c048958f8fd GIT binary patch literal 40040 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 AF#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.impl b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.impl new file mode 100644 index 0000000000000000000000000000000000000000..90935a44e900ea4cbd0dd194b8379cd4d75d1873 GIT binary patch literal 8000 zcmeHHTMEN449g+9$JZFW{~<@}go41>aUN?y{V{eW+fkM7NuHhYP=Gqn4_N{FfIhgg z55Dqw5~Bz~9jHTAfIgrP=!5efe8dikQG}ol)FCTCAJ7N%0q?=T{sWs_zZ8v+!he?d zg7_}E6)VreS?_!MMER?Dt#fAKy?u$33s8MKN)M}#_Fk)d_lxqQyxzT{b2Z-G>z1B) zKFnwFy>mw6wDUygAa8c=-5>Xe@@k(Ntv*ql)^}7L_tN?zt~K}e)o`tK+)v{p4s$QB Q7q^P(^b literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.ovh b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exm_mply.ovh new file mode 100644 index 0000000000000000000000000000000000000000..43392ce9501bd96e5463677355dc999e96fb44af GIT binary patch literal 8000 zcmeIyu@L|;2m>(+?>{pKjDgam_dQD8i+>legC1r99q2#@?tlXv-~b0WzyS_$fCC)h Y00%h00S<70103K02ROh14*YYV0gwz2p#T5? literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exmp b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.exmp new file mode 100644 index 0000000000000000000000000000000000000000..5427eea375f57a7e694b08898800549a354ebf18 GIT binary patch literal 8000 zcmeIyu@L|;2m>)D^ZsLTz!)e^df%hez4&(lJLq8+(18wg;0`#z0S<70103K02ROh1 Y4sd`29N+*4IKTl8aDW3G;J`lz8uRq>F#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.png b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.png new file mode 100644 index 0000000000000000000000000000000000000000..eb8b72ca7b3f46b2e07f3a1c46542d43405fba70 GIT binary patch literal 36239 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 NFp`Roip3xM{x5f?yeR+x literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.ts b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._5.0_.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ca9a907730543f3e6ea35a94dec8114f76f2273 GIT binary patch literal 8000 zcmXY$cf8K!AI87y`JPZI4Wpr?MTOEp{jN_b4bcxxBMA+Zq_ohlgqBfONk%d%3Ylf^ z?KsA94vw?;c=kNc^Zf4dIsf#k_@3|gzCZVMy|3%epLh9^EjwOEzWV0}Sbp!3ErbJ{_o%6(KknWCmxu||9=j~W&ZtAXwzK&b3Y^Znz4iKer_TE`9&D> z%=K3f>#>;s-mhpfVf(>Fk1gfDzYKq_fA!OxhkoPd{EqIGPRGmdTfxs;iL&dKl|OOU zU;Nxv*s=WAo^-`(e*S7q+Znp8|Fkvyd;Z3NbKUF@8?EKvw-#-~bI#A0ypDhGdc+!6 zZ1~IGz`uV3_TAq3`$L~@k$lh-#B zS7PtEbzfxiI%nd`iG5FOF3RNfK90np+5@{DInL{T93#~L9_RHxj=~q4Za8ja@jhhX z`2~NhJTowh_ah4jO7QE2ty#P;S$Ie;?{z15e@b*P;xRNpXWFqtN$zCIG^V^A628* zU6nYL&vTuR)@q>gdAFD8#43HorHcSs|Z?LTs8M2cnSAMIrpF$^`6z@s4$BJpoD|}< zNb#UWrwjSK6k=hEcIR8WMSO0Gkn_+-FD}2gh|fB zUiQMlyLT7yxhldA;U4P)MSQ-B5wEG*-sz@dK4--c=JDW`-oz^v&b6birqprCm|ISiAzoihv`{m#PrF@P{ zA>FC$+fqKyrMOAT{pM0W*QFSc>MB0Dl+Sk=X5TpV{ZZGH@i{L;=A&o4!KcdjyqBTj z8?8os_;DGZ`!YN#?d`WRKL2HqZt!VN8S6k9gcyo}DQ7(>hcEclOOqZbXI&^q+h(&) zHh80)^`RU}p68UaPLx9}-@bCzi*lU#Y;?Do;d0iE3N%p$P{I09f$nMnD_BP=FtMuF z#_K0mu%1+4+okjF`DJYd>q-S;QvQo8SYIk2%(KmJS5&gjR6>00k~_Lqvffl;sc^Sd z?^d$zR3d+?d|)N(PbHMR9?73)a53Wf zan-D6)#&%ge}u$Vv#wQRmK>LJ)vRyTkZzsdsD^c}1{bZkR#;{Y>s<{VQ371Ux>tj- z>HycU{?$Oe-hmp{!5Sz$iPf+k*5da5lCWx77i%$C(Aq~Y*0MguMc3 zNSruX$NE}_dzAosS!cb-8aXiIXmc;?tru#0I(S)ky|`GYf3GLKtiN9TCUJ6*mvz{S zZpx6ntjAsy?fc>1+0(tO%U-C@U+!gn_Tt*A!uwim_p(lVq3l1~%X;mFr01XOysX<^ z1cZ7F%(`!KzObO0agxDR)Bl~44sp8If6;#*H2>$(rGsUIKfyAJ|(g`)dd=Y5cF zRx!)Rdhdf&r$1KuSoeL%m3F?3|8 zq`j{3v!D3!!`l+r{Ol`!C^;|mv%mNu)wOHf&ps2t+l$T3o+bhIn*bWETPlbrz`hf} z^1bo^2iSiCcudOWO9A$w01D;jjta0J1@Nh$`=eh5*p~v3>OFm7fc+@|Ayz`M0_;-( zC^^auuwMlrU{(-NfPE`~X=3%}qyy|TCfkbN!)VSeHO1=;U{kh@W|B*?xO#26Lyg6w}mT%let$UYdvDj6qg zg6xMu^tehAdWd~7go;}_2#E=?KZY>r0eRv>?2{qL-EH@Di2X7Ig_nav?3*DBklXu7 zi2XB!xNx`kW`x*BLzpwY@yGZ55n?|Lq2n)W?~m>bv9E@p;%07${WS#jIDd$JHUx!N z4a4lWVaW8DzA?=kAo4rBav54`^9n_>3jFs_mK@>!UDIgE|; zdEvev!tBpsJgWdQ%sw54fZqY#_lMc9!;tQLNq(4pI}C*fkudvr1pB4DG>)*3M=SVS}tEK8i7y#PF;h;FQnRnt) zI6OPf+!Kd@T|vBY=ASsa3%WbKC(axcNBJ<>n8cZf;+QyAp13%3Q39>hKqr`w5>WQh zI>DTjK)==7L;_7PFC`G&IYdl!g1IRHNsp~YB$%HPxLe}fgamU`0>`9W{ghyyN??TA z-~@A30u2UcD%XYQ(ps$1IBGk?{ixhfp$nZxR_ z{tNlR^~_`S=%WC;p1G_ZUb!7#)ia;fL&f)n^~`DY5aB^=aXs@|y=o`MX4W&e)njmN zU-63d%y0ED)K8K*E{UII9oIC;JeNdgC8$Z}x+JnYNp?Wf^?6*LsHC-DI9Gs4_t~lGKJx)uuCydrf`u0 zm=tqm3QHue?Mg9UrtrusC7G?xrkFER5aq(uVte*Fy69Bh!{_16v3y@Ww(J>NA*bFo3H z{}^wO?%fPh>-)7qnv)Gud_UVD-D4P}*83NOG&dWh`rJPa(!HobYW@E)NOQD7YPq&eIql{aoSN%txysr_tklIC)gRKN3}NxD}wN$u|wCTUJLN#&DgP0~G#Nov1e zF-dc~Nva+p-GzKO;YvC7bfZ6#-vWNpqXZp=6aJvxapPqlS#VAH0iXo z$7LpI&NoSvm6y)@+a%rdm^50}liN(v+;5U>=LQ@yN%#CFT_$MjKiMYf9AJ{NpCXfV zFJ#h+Z^XdYnWS@pNuS8NByN)KO)Yv-7IdyfIwx4vOsK=+CKl-)$s#51*IT4>gGK8E z%?)W|k?y@MQr7|ZS)_A>MZM(%AF)XHP8QuD2fwF9I#*bvIF!@sgf-y2vIk@7UlBAr7l+A~cAvPBl@Udtj? zcdoQZ=MsxvU39u*-A0RaFKm%)A2N4aq;rZzX?grJEz&)hMe;V~yK@%l++xu@Sx1yx zq}+)58*1yV#_2k4=r`AAH;U zaBGcCI!D=bgEYvkHtF8ardnC=9kfa3Dw||G>72Gn_v|)(lN=f;F0e`GESnV0)YznZ zLYr=r9~`qu=PsMnb&$s)eNW`j9Hdcr0O_wNar+%jvN+0PdlW0NQYGXe$gSF+Z-Au1$Br+`X0w2nKnkg5$HK4ykxM(;#&mDfE1hxEOL zL(+X?DTj1U^w3&y8<^YBL%K)xsI>I&)gIEh(L=ptz1_+~`rgVzs_weWLpn!#sCKNd z!pLE4uKYB>_x*lpT>!~Fk(z(<_DREnI%W4nldl?TY zeBa_Bol`yZQ>nPH-0vaX1A9nam!9;H&aEDLKmu{Thx9$2hs17l{ifPOI>&nGl*Hqx zhjef3A=yUua9q;4)+JRRU*?j&2XaXX{URn{IVU_slMxUnhX}9+!0PbxG`Q zztwO_-^04}vAhoI?vl>IF3Ig3{enxnmv*VC9IU}E>0InmiD>sbj&w=iJGmsn+`6ki zaY^T7mp+$u?D=s6OIer9cS+w%x}@;wcb9aIc4@On!ym7AN%!6^ z$=lGrJ6+Pb+9h#$aHPvom-IcCOSej(%ymiUY?q|mCrez?J-JJ}1-<3@T++GQC3(BF zE$NcJ2hN~D@)tMAAf3ZANX7lDGD!F88I%(8GU&z((z!f?4$JGrJ2Ob%t7Xvt0a3FI AF#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exm_mply.impl b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exm_mply.impl new file mode 100644 index 0000000000000000000000000000000000000000..07e748fe10ad92848fdf34fcb54aa70b3445dfa4 GIT binary patch literal 8000 zcmeIy%ME}q3`9W}z_3+@4*Iw1BVuP+QAyWvVq{hp#^lHgFkk#(+?>{pKjDgam_dQD8i+>legC1r99q2#@?tlXv-~b0WzyS_$fCC)h Y00%h00S<70103K02ROh14*YYV0gwz2p#T5? literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exmp b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.exmp new file mode 100644 index 0000000000000000000000000000000000000000..3f433429ad15d0125f3a5238115cd6db78b7a38a GIT binary patch literal 8000 zcmeIyu?+wq3+00000 literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.png b/lib/BloqadeKrylov/compares/expmv/3-by-3.1000._6.0_.png new file mode 100644 index 0000000000000000000000000000000000000000..a8982fa3dccdfaea02576ad8770f5bef84e40aaa GIT binary patch literal 31432 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 AF#rGn literal 0 HcmV?d00001 diff --git a/lib/BloqadeKrylov/compares/expmv/3-by-3.jl b/lib/BloqadeKrylov/compares/expmv/3-by-3.jl new file mode 100644 index 000000000..a78b602b9 --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/3-by-3.jl @@ -0,0 +1,64 @@ +include("tools.jl") + +## define problem-1 +## 1) real time +prob_name = "3-by-3" + +function H2_Square(T,ascale) + nx, ny = 3, 3 + nsites = nx * ny + atoms = generate_sites(SquareLattice(), nx, ny, scale = ascale) + + Ω_max = 2π * 4.3 + Ω = piecewise_linear(clocks = [0.0/T, 0.3/T, 2.6/T, 1.0].*T, values = [0.0, Ω_max, Ω_max, 0]); + + U = 2π * 15.0 + Δ = piecewise_linear(clocks = [0.0/T, 0.3/T, 2.6/T, 1.0].*T, values = [-U, -U, U, U]); + + h = rydberg_h(atoms; Δ, Ω) + atoms, h +end + +nsites = 9 + +T = 2.9 +Nt = 1000 +scale = 2.0 + +atoms, h = H2_Square(T,scale) +dt = T/Nt +tspan = dt:dt:T + +H = BloqadeExpr.Hamiltonian(ComplexF64, h) + +# expmv +reg = zero_state(nsites) +nmul_old = testing_expmv!(H, tspan, reg) + +# expmv +reg1 = zero_state(nsites) +#tspan = dt:dt:2dt +nmul_overhead, nmul_impl = testing_expm_multiply!(H, tspan, reg1) + + +#checking +print(statevec(reg1)[1:10]) +print(statevec(reg)[1:10]) +println(statevec(reg) .≈ statevec(reg1)) + + + +open("$prob_name.$Nt._$(scale)_.exmp","w") do f + write(f,nmul_old) +end + +open("$prob_name.$Nt._$(scale)_.exm_mply.ovh","w") do f + write(f,nmul_overhead) +end +open("$prob_name.$Nt._$(scale)_.exm_mply.impl","w") do f + write(f,nmul_impl) +end + +open("$prob_name.$Nt._$(scale)_.ts","w") do f + write(f,collect(tspan)) +end \ No newline at end of file diff --git a/lib/BloqadeKrylov/compares/expmv/Project.toml b/lib/BloqadeKrylov/compares/expmv/Project.toml new file mode 100644 index 000000000..136139c9e --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/Project.toml @@ -0,0 +1,8 @@ +[deps] +Bloqade = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe1" +BloqadeExpr = "bd27d05e-4ce1-5e79-84dd-c5d7d508abe2" +BloqadeKrylov = "bd27d05e-4cd1-5e79-84dd-c5d7d508ade2" +BloqadeLattices = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe4" +LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" diff --git a/lib/BloqadeKrylov/compares/expmv/chain_sincos.jl b/lib/BloqadeKrylov/compares/expmv/chain_sincos.jl new file mode 100644 index 000000000..c90823c2a --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/chain_sincos.jl @@ -0,0 +1,31 @@ +include("tools.jl") + +## define problem-1 +## 1) real time +prob_name = "chain_sin_cos" + + +nsites = 10 +dt = 1e-3 +tspan = 0:dt:1.0 +atoms = generate_sites(ChainLattice(), nsites, scale = 6) +h = rydberg_h(atoms; Ω = sin, ϕ = cos) + +H = BloqadeExpr.Hamiltonian(ComplexF64, h) + +# expmv +reg = zero_state(nsites) +nmul_old = testing_expmv!(H, tspan, reg) + +# expmv +reg1 = zero_state(nsites) +nmul_overhead, nmul_impl = testing_expm_multiply!(H, tspan, reg1) + +#checking +println(statevec(reg) ≈ statevec(reg1)) + + +open("$prob_name.$nsite","w") do f + write(f,es) +end + diff --git a/lib/BloqadeKrylov/compares/expmv/plot.jl b/lib/BloqadeKrylov/compares/expmv/plot.jl new file mode 100644 index 000000000..7d0f5ac88 --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/plot.jl @@ -0,0 +1,34 @@ + +using Plots +using LaTeXStrings + +Nt = 1000 +scale = 6.0 + +f = open("3-by-3.$(Nt)._$(scale)_.ts","r") +ts = convert(Array{Float64,1}, collect(readeach(f,Float64))) +close(f) + + +f = open("3-by-3.$(Nt)._$(scale)_.exmp","r") +Ns = convert(Array{Int,1}, collect(readeach(f,Int))) +close(f) + + +f = open("3-by-3.$(Nt)._$(scale)_.exm_mply.ovh","r") +Nnew_ovhd = convert(Array{Int,1}, collect(readeach(f,Int))) +close(f) + + +f = open("3-by-3.$(Nt)._$(scale)_.exm_mply.impl","r") +Nnew_impl = convert(Array{Int,1}, collect(readeach(f,Int))) +close(f) + + +Plots.plot(ts, Ns,linestyle=:dash,label="expmv", ylabel = "# of mul!(::SumOfLinop,v)", xlabel=L"$t$") +Plots.plot!(ts, Nnew_ovhd,linestyle=:dash,label="expm_multiply, overhead (s,m)", ylabel = "# of mul!(::SumOfLinop,v)", xlabel=L"$t$") +Plots.plot!(ts, Nnew_impl,linestyle=:dash,label="expm_multiply, impl", ylabel = "# of mul!(::SumOfLinop,v)", xlabel=L"$t$") +Plots.plot!(ts, Nnew_impl.+Nnew_ovhd,linestyle=:dash,label="expm_multiply (total = overhead+impl)", ylabel = "# of mul!(::SumOfLinop,v)", xlabel=L"$t$") +Plots.title!("3-by-3, Nt = $Nt, scale = $scale") + +savefig("3-by-3.$(Nt)._$(scale)_.png") \ No newline at end of file diff --git a/lib/BloqadeKrylov/compares/expmv/readfiles.py b/lib/BloqadeKrylov/compares/expmv/readfiles.py new file mode 100644 index 000000000..4896ee056 --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/readfiles.py @@ -0,0 +1,22 @@ +import numpy as np +import scipy as sp + +def readCSC(fname,dtype): + m,n = np.fromfile(fname + ".size",np.int64) + data = np.fromfile(fname+".nzval",dtype) + indices = np.fromfile(fname+".rowval",np.int64) + indptr = np.fromfile(fname+".colptr",np.int64) + print(m," ",n) + print(indices) + print(indptr) + print(data) + return sp.sparse.csc_matrix((data,indices-1,indptr-1),shape = (m,n)) + + +O = readCSC("MHt",np.complex128) +#print(np.linalg.norm(O.todense(),ord=1)) +#print(sp.sparse.linalg.onenormest(O)) +#print(sp.sparse.linalg.norm(O,ord=1)) +v = np.arange(O.shape[0]) +sp.sparse.linalg.expm_multiply(0.0029j*O,v,traceA=(0.0029j*O).trace()) + diff --git a/lib/BloqadeKrylov/compares/expmv/tools.jl b/lib/BloqadeKrylov/compares/expmv/tools.jl new file mode 100644 index 000000000..75f825c49 --- /dev/null +++ b/lib/BloqadeKrylov/compares/expmv/tools.jl @@ -0,0 +1,106 @@ +using Revise +using BloqadeKrylov +using Bloqade +using LinearAlgebra +using BloqadeLattices + + +function writeSparseCSC(A,fname) + + open("$fname.size","w") do f + write(f,A.m) + write(f,A.n) + + end + + open("$fname.colptr","w") do f + write(f,A.colptr) + end + open("$fname.rowval","w") do f + write(f,A.rowval) + end + open("$fname.nzval","w") do f + write(f,A.nzval) + end + +end + +## wrapping Hamiltonian with counter that count the number of mul! calls +mutable struct WHam + h + counter::Vector{Int} + function WHam(h, counter= Vector{Int}([0])) + return new(h,counter) + end +end + +Base.size(M::WHam) = size(M.h) +Base.size(M::WHam,i::Int) = size(M.h,i) +#opnorm(M::WHam) = opnorm(M.h) +LinearAlgebra.opnorm(M::WHam,p=2) = opnorm(M.h,p) +Base.eltype(M::WHam) = eltype(M.h) + + +function count_mul!(a::AbstractVecOrMat, M::WHam, x::AbstractVecOrMat) + M.counter[1] += 1 + mul!(a, M.h, x) +end +LinearAlgebra.mul!(a::AbstractVecOrMat,M::WHam,x::AbstractVecOrMat) = count_mul!(a,M,x) +LinearAlgebra.tr(M::WHam) = tr(M.h) +BloqadeExpr.add_I(M::WHam, c::Number) = WHam(BloqadeExpr.add_I(M.h, c), M.counter) +Base.:*(c::Number, M::WHam) = WHam(c*M.h, M.counter) +LinearAlgebra.adjoint(M::WHam) = WHam(adjoint(M.h), M.counter) +##=================================== + + +# reg inplace modify +function testing_expmv!(H::BloqadeExpr.Hamiltonian, tspan, reg) + n_mul = Vector{Int}(undef,0) + for t in tspan + Ht = WHam(H(t)) + + BloqadeKrylov.expmv!((dt)*im, Ht, statevec(reg), tol=1.0e-7) + + #println(norm(statevec(reg))) + #println(Ht.counter[1]) + push!(n_mul, Ht.counter[1]) + end + return n_mul +end + +function testing_expm_multiply!(H::BloqadeExpr.Hamiltonian, tspan, reg) + n_mul_impl = Vector{Int}(undef,0) + n_mul_sm = Vector{Int}(undef,0) + print(tspan) + for t in tspan + Ht = H(t) + Ht = WHam(Ht) + + + #BloqadeKrylov.expm_multiply!((dt)*im, Ht, statevec(reg1)) + #^> unwrap it to get counting for mul from get optimal sm overhead + ti = (dt) + + + m_star, s, μ, A_1norm, As = BloqadeKrylov.get_optimal_sm(ti,im*Ht) + push!(n_mul_sm, Ht.counter[1]) + Ht.counter[1] = 0 + + v = statevec(reg) + w = similar(v) + + + #assuming its ComplexF64 + BloqadeKrylov._expm_multiply_impl!(w, ti, As, v, μ, s, m_star,1.0e-7) + + + + copyto!(v,w) + + + #println(norm(statevec(reg))) + #println(Ht.counter[1]) + push!(n_mul_impl, Ht.counter[1]) + end + return n_mul_sm, n_mul_impl +end diff --git a/lib/BloqadeKrylov/src/BloqadeKrylov.jl b/lib/BloqadeKrylov/src/BloqadeKrylov.jl index 43e6de060..d0b48c682 100644 --- a/lib/BloqadeKrylov/src/BloqadeKrylov.jl +++ b/lib/BloqadeKrylov/src/BloqadeKrylov.jl @@ -23,7 +23,12 @@ export CFET2_1, CFET4_2, CFET6_5, CFET8_11 # |-> BloqadeKrylov.ValHamiltonian (new) #include("utils.jl") +## following are expm_multiply +export onenormest, expm_multiply!, expmv! +include("onenormest.jl") +include("expm_multiply.jl") include("expmv.jl") + include("common.jl") include("krylov.jl") include("magnus.jl") @@ -33,6 +38,7 @@ include("cfet.jl") include("tables/cfet_tbl.jl") + if VERSION < v"1.7" include("patch.jl") end diff --git a/lib/BloqadeKrylov/src/adapt_cfet.jl b/lib/BloqadeKrylov/src/adapt_cfet.jl new file mode 100644 index 000000000..1a35204f4 --- /dev/null +++ b/lib/BloqadeKrylov/src/adapt_cfet.jl @@ -0,0 +1,212 @@ + +""" + struct ACFETEvolution + ACFETEvolution(reg::AbstractRegister, start_clock, end_clock, h, algo; step_size = 1e-7, kw...) + +Create a `ACFETEvolution` object that describes a time evolution +using commutation-free Magnus method with s exponentials with adaptive size +[1] https://arxiv.org/pdf/1102.5071.pdf (eq.58-61) +[2] SAIM: M2AN 53 (2019) 197–218 A posteriori error estimation for Magnus-type integrators W. Auzinger et.al. + +# Arguments + +- `reg`: a register, should be a subtype of `AbstractRegister`. +- `start_clock`: the start clock of time evolution. +- `end_clock`: the end clock of time evolution. +- `h`: a hamiltonian expression. +- `algo`: the algorithm (different orders to use), should be a subtype of `CFETTables`. default is `CFET2_1` + +# Keyword Arguments + +- `step_size`: intial step size, default is `1e-7`. +- `progress`: show progress bar, default is `false`. +- `progress_name`: progress bar name, default is `"emulating"`. +- `normalize_step`: normalize the state every `normalize_step`. +- `normalize_finally`: wether normalize the state in the end of evolution, default is `true`. +- `tol`: tolerance of the exponential time propogator evaluation method, default is `1e-7` +- `expmv_backend`: the backend for evaluate exponential time propogator, default is `expmv!` (other option: `expm_multiply!`). + +# Examples + +The following is the simplest way of using `ACFETEvolution` +via [`emulate!`](@ref). For more advanced usage, please refer +to documentation page [Emulation](@ref emulation). + +```jldoctest +julia> using Bloqade + +julia> r = zero_state(5) +ArrayReg{2, ComplexF64, Array...} + active qudits: 5/5 + nlevel: 2 + +julia> atoms = [(i, ) for i in 1:5] +5-element Vector{Tuple{Int64}}: + (1,) + (2,) + (3,) + (4,) + (5,) + +julia> h = rydberg_h(atoms; Ω=sin) +nqubits: 5 ++ +├─ [+] ∑ 5.42e6/|x_i-x_j|^6 n_i n_j +└─ [+] Ω(t) ⋅ ∑ σ^x_i + + +julia> prob = ACFETEvolution(r, 0.0, 0.1, h, CFET2_1()); + +julia> emulate!(prob); # run the emulation +``` +""" +mutable struct ACFETEvolution{Reg<:AbstractRegister,T<:Real,H<:Hamiltonian,ALGTBL<:CFETTables} <: ADEvolver + reg::Reg + start_clock::T + end_clock::T + step_size::T # this store the current step_size + hamiltonian::H + options::KrylovOptions + alg_table::ALGTBL + + function ACFETEvolution{Reg,T,H,ALGTBL}(reg, start_clock, end_clock, step_size,hamiltonian, options, algo) where {Reg,T,H,ALGTBL} + start_clock ≥ 0 || throw(ArgumentError("start clock must not be negative")) + end_clock ≥ 0 || throw(ArgumentError("end clock must not be negative")) + + end_clock ≥ start_clock || throw(ArgumentError("end clock must be larger than start clock")) + step_size ≤ end_clock-start_clock || throw(ArgumentError("initial step size cannot be larger than the whole evolution time")) + return new{Reg,T,H,ALGTBL}(reg, start_clock, end_clock, step_size, hamiltonian, options, algo) + end +end + +""" + ACFETEvolution(reg, start_clock, end_clock, hamiltonian, options) + +Create a `ACFETEvolution` object. + +# Arguments + +- `reg`: a register object. +- `start_clock`: start clock of the evolution. +- `end_clock`: end clock of the evolution. +- `hamiltonian`: low-level hamiltonian object of type [`Hamiltonian`](@ref). +- `options`: options of the evolution in type [`KrylovOptions`](@ref). +""" +function ACFETEvolution(reg, start_clock, end_clock, step_size,hamiltonian, options, algo) + return ACFETEvolution{typeof(reg),typeof(start_clock),typeof(hamiltonian),typeof(algo)}( + reg, + start_clock, + end_clock, + step_size, + hamiltonian, + options, + algo, + ) +end + +function Adapt.adapt_structure(to, x::ACFETEvolution) + return ACFETEvolution(adapt(to, x.reg), x.start_clock, x.end_clock, x.step_size, adapt(to, x.hamiltonian), x.options, x.alg_table) +end + +function ACFETEvolution(reg::AbstractRegister, start_clock, end_clock , h, algo::CFETTables = CFET2_1(); step_size=1e-7, kw...) + all(≥(0), clocks) || throw(ArgumentError("clocks must not be negative")) + options = from_kwargs(KrylovOptions; kw...) + P = real(eltype(statevec(reg))) + T = isreal(h) ? P : Complex{P} + + return ACFETEvolution(reg, start_clock, end_clock, step_size, Hamiltonian(T, h, space(reg)), options, algo) +end + +## given Hamiltonian, current time `t` and duration `dt`, plus a CFETTable, +# output generator Ω at certain ETstep (exponential time propogator) +## t + xs[i]dt +function __construct_Ω(h::Hamiltonian, t::Real, dt::Real, Tbl::CFETTables, ETStep::Int) + + gs = Tbl.Gs[ETStep] + xs = Tbl.xs + + fs = gs[1]*h(t + xs[1]*dt).fvals + + for i in 2:length(gs) + fs += gs[i]*h(t + xs[i]*dt).fvals + end + + return SumOfLinop{LinearAlgebra.Hermitian}(fs, h.ts) +end + +function __construct_dΩ(h::Hamiltonian, t::Real, dt::Real, Tbl::CFETTables, ETStep::Int) + + gs = Tbl.Gs[ETStep] + xs = Tbl.xs + + fs = gs[1]*xs[1]*derivative.(h.fs,t + xs[1]*dt) + + for i in 2:length(gs) + fs += gs[i]*xs[i]*derivative.(h.fs,t + xs[i]*dt) + end + + return SumOfLinop{LinearAlgebra.Hermitian}(fs, h.ts) +end + +@inline function scale_factor(αmin, αmax, α, ϵ, tol, p) + return min(αmax, max(αmin, α*(tol/ϵ)^(1/(p+1)))) +end + +## here, since generic algo for defect is unclear, we specialize it for each support types: +function emulate_step!(prob::ACFETEvolution{<:Any,<:Any,<:Any,ALGTBL<:CFET2_1}, step::Int, clock::Real, tol::Real) + state = statevec(prob.reg) + Ham = prob.hamiltonian + + duration = prob.step_size # get duration + + #construct Ωi: + Ω1 = -im*__construct_Ω(Ham, clock, duration, prob.alg_table, 1) + dΩ1 = -im*__construct_dΩ(Ham, clock, duration, prob.alg_table, 1) + + + # perform evolution: + prob.options.expmv_backend(duration, Ω1, state; prob.options.tol) + + + ## calculate defect operator + Bv = similar(state) + dBv = similar(state) + tmp = similar(state) + + mul!(Bv, Ω1, state) + mul!(dBv, dΩ1, state) + dest = Bv .+ duration*dBv + + mul!(tmp, Ω1, dBv) + mul!(dBv, dΩ1, Bv) + Bv = tmp + + ## [B,B']v + dest .+= (duration^2/2)*(Bv - dBv) + + ## -A(t+τ)v + mul!(tmp, Ham(clock+duration), state) + dest .-= tmp + + ϵ = norm(dest) + + ## calculate and update next step size: + prob.step_size = duration*scale_factor(0.25, 4.0 , 0.9, ϵ, tol, p) + + + # do we need this normalization? + if mod(step, prob.options.normalize_step) == 0 + normalize!(prob.reg) + end + + if prob.options.normalize_finally && step == length(prob.durations) + normalize!(prob.reg) + end + + return prob +end + +function emulate_step!(prob::ACFETEvolution, step::Int, clock::Real, duration::Real) + error("unsupported CFET algo for adaptive step-size") +end + diff --git a/lib/BloqadeKrylov/src/cfet.jl b/lib/BloqadeKrylov/src/cfet.jl index 3f37af16b..b4a0e2de2 100644 --- a/lib/BloqadeKrylov/src/cfet.jl +++ b/lib/BloqadeKrylov/src/cfet.jl @@ -14,7 +14,7 @@ https://arxiv.org/pdf/1102.5071.pdf (eq.58-61) - `reg`: a register, should be a subtype of `AbstractRegister`. - `clocks`: the clocks of this time evolution at each step. - `h`: a hamiltonian expression. -- `algo`: the algorithm (different orders to use), should be a subtype of `CFETTables`. default is `CFET42` +- `algo`: the algorithm (different orders to use), should be a subtype of `CFETTables`. default is `CFET4_2` # Keyword Arguments @@ -22,8 +22,8 @@ https://arxiv.org/pdf/1102.5071.pdf (eq.58-61) - `progress_name`: progress bar name, default is `"emulating"`. - `normalize_step`: normalize the state every `normalize_step`. - `normalize_finally`: wether normalize the state in the end of evolution, default is `true`. -- `tol`: tolerance of the Krylov-expmv evaluation method, default is `1e-7` - +- `tol`: tolerance of the exponential time propogator evaluation method, default is `1e-7` +- `expmv_backend`: the backend for evaluate exponential time propogator, default is `expmv!` (other option: `expm_multiply!`). # Examples @@ -102,18 +102,13 @@ function Adapt.adapt_structure(to, x::CFETEvolution) return CFETEvolution(adapt(to, x.reg), x.start_clock, x.durations, adapt(to, x.hamiltonian), x.options, x.alg_table) end -function CFETEvolution(reg::AbstractRegister, clocks, h, algo::CFETTables = CFET42(); kw...) +function CFETEvolution(reg::AbstractRegister, clocks, h, algo::CFETTables = CFET4_2(); kw...) all(≥(0), clocks) || throw(ArgumentError("clocks must not be negative")) options = from_kwargs(KrylovOptions; kw...) P = real(eltype(statevec(reg))) T = isreal(h) ? P : Complex{P} start_clock, durations = first(clocks), diff(clocks) - ## checking if it is equal time: - if length(unique(round.(durations,digits = 14) ) ) != 1 - throw(ArgumentError("durations must be equal (time slice must be equal)")) - end - return CFETEvolution(reg, start_clock, durations, Hamiltonian(T, h, space(reg)), options, algo) end @@ -131,7 +126,9 @@ function __construct_Ω(h::Hamiltonian, t::Real, dt::Real, Tbl::CFETTables, ETSt fs += gs[i]*h(t + xs[i]*dt).fvals end - return SumOfLinop(fs, h) + + return SumOfLinop{LinearAlgebra.Hermitian}(fs, h.ts) + end @@ -147,7 +144,7 @@ function emulate_step!(prob::CFETEvolution, step::Int, clock::Real, duration::Re Ωi = __construct_Ω(Ham, clock, duration, prob.alg_table, i) # perform evolution: - BloqadeKrylov.expmv!(-im*duration, Ωi, state; prob.options.tol) + prob.options.expmv_backend(-duration, im*Ωi, state; prob.options.tol) end diff --git a/lib/BloqadeKrylov/src/common.jl b/lib/BloqadeKrylov/src/common.jl index 3a010fad8..38524e5ec 100644 --- a/lib/BloqadeKrylov/src/common.jl +++ b/lib/BloqadeKrylov/src/common.jl @@ -10,20 +10,28 @@ Krylov evolution options. normalize_step::Int = 5 normalize_finally::Bool = true tol::Float64 = 1e-7 + expmv_backend = expmv! end ## this is the abstract type for all evolvers -## KrylovEvolution, Magnus4Evolution, CFET42Evolution +## KrylovEvolution, Magnus4Evolution, CFETEvolution abstract type Evolver end +## ACFET21Evolution, ACFET42Evolution, ACFET65Evolution +abstract type ADEvolver end ## adaptive # These are common parts shared by all the evolvers Base.length(prob::Evolver) = length(prob.durations) + 1 +#Base.length(prob::ADEvolver) = nothing function Base.iterate(prob::Evolver) info = (; step = 1, reg = prob.reg, clock = prob.start_clock, duration = zero(prob.start_clock)) return info, (2, prob.start_clock) end +#function Base.iterate(prob::ADEvolver) +# info = (; step = 1, reg = prob.reg, clock = prob.start_clock, duration = zero(prob.start_clock)) +# return info, (2, prob.start_clock) +#end Base.@propagate_inbounds function Base.iterate(prob::Evolver, (step, clock)) step > length(prob) && return @@ -35,6 +43,16 @@ Base.@propagate_inbounds function Base.iterate(prob::Evolver, (step, clock)) return info, (step + 1, clock + duration) end +Base.@propagate_inbounds function Base.iterate(prob::ADEvolver, (step, clock)) + clock >= prob.end_clock && return + + duration = prob.step_size + emulate_step!(prob, step, clock, duration) + + info = (; step, reg = prob.reg, clock = clock + duration, duration) + return info, (step + 1, clock + duration) +end + ## driver function, user entry point function BloqadeExpr.emulate!(prob::Evolver) niterations = length(prob) diff --git a/lib/BloqadeKrylov/src/expm_multiply.jl b/lib/BloqadeKrylov/src/expm_multiply.jl new file mode 100644 index 000000000..e0a14dd5b --- /dev/null +++ b/lib/BloqadeKrylov/src/expm_multiply.jl @@ -0,0 +1,269 @@ +## look up table for now +# [This table is calculated for Float64 precision 2^-53] +# App. Table A.3 +# Computing Matrix Functions +# Higham, Nicholas J. and Al-Mohy, Awad H. +# 2010 +struct θ_table + ms::Vector{Int} + θs::Vector{Float64} + max_m::Int + function θ_table() + ms = Vector{Int}([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, + 35,40,45,50,55]) + ts = Vector{Float64}([2.29e-16, + 2.58e-8, + 1.39e-5, + 3.40e-4, + 2.40e-3, + 9.07e-3, + 2.38e-2, + 5.00e-2, + 8.96e-2, + 1.44e-1, + 2.14e-1, + 3.00e-1, + 4.00e-1, + 5.14e-1, + 6.41e-1, + 7.81e-1, + 9.31e-1, + 1.09, + 1.26, + 1.44, + 1.62, + 1.82, + 2.01, + 2.22, + 2.43, + 2.64, + 2.86, + 3.08, + 3.31, + 3.54, + 4.7, + 6.0, + 7.2, + 8.5, + 9.9]) + + + return new(ms,ts,55) + end +end +function get_theta(θ_tbl::θ_table, m::Int) + if !(m in θ_tbl.ms) + error("m is not in the table") + end + return θ_tbl.θs[indexin(m, θ_tbl.ms)[1]] +end + +function get_optimal_sm(t::Real, A::T, m_max::Int=55, ell::Int=2) where {T} + """ + given an matrix A and t, find the optimal s and m_star for expm_multiply. + [return] m_star, s, μ, A_1norm, As + mu is the shifted constant μ + A_1norm is the 1-norm of A + As is the shifted A, As = A - mu*I + """ + + + # 1) shift the A: + traceA = LinearAlgebra.tr(A) + n = size(A,1) + μ = traceA/size(A,1) + + #As = A - μ*LinearAlgebra.I(n) + As = BloqadeExpr.add_I(A,-μ) + + #using onenormest to get 1-norm of As + A_1norm = onenormest(As,1) + + m_star::Int = 1 + s::Int = 1 + if t*A_1norm != 0 + m_star, s = _calc_optimal_sm(As, A_1norm, abs(t), m_max, ell) + end + + return m_star, s, μ, A_1norm, As +end + +function expm_multiply(t::Real, + A, + v::AbstractVector{T}; + tol = nothing) where {T} + v_prom = similar(v, promote_type(eltype(A), T, typeof(t))) + copyto!(v_prom, v) + + out = similar(v_prom) + expm_multiply!(out, t, A, v_prom; tol) + return out +end + +function expm_multiply!(t::Real, + A, + v::AbstractVector{T}; + tol = nothing) where {T} + + w = similar(v) + expm_multiply!(w, t, A, v; tol) + copyto!(v,w) +end + +function expm_multiply!(w::AbstractVector{T}, + t::Real, + A, + v::AbstractVector{T}; + tol = nothing + ) where {T} + if size(v, 1) != size(A, 2) + error("dimension mismatch") + end + + + if tol === nothing + # infer tol base on the size of T + size_T = sizeof(real(T)) + if size_T == 8 + tol = 2^(-53) + elseif size_T == 4 + tol = 2^(-24) + else + error("Unsupported type T of vec{T} for auto set tol") + end + end + + # 1) get the optimal s and m_star, and As--shifted A + # note that here we use abs(t) instead of t so the A_T on onenormest is lazy evaluated. + m_star, s, μ, A_1norm, As = get_optimal_sm(t,A) + + + # 3) here lies the impl call: + _expm_multiply_impl!(w, t, As, v, μ, s, m_star, tol) + return w +end + +# n0 = 1 +function _condition_3_13(θ_tbl, tA_1norm, m_max::Int, ell::Int) + ## compute p_max: + sqrt_m_max = sqrt(m_max) + p_low = Int(floor(sqrt_m_max)) + p_high = Int(ceil(sqrt_m_max+1)) + p_max = maximum([p for p in p_low:1:p_high if p*(p-1) <= m_max + 1]) + + a = 2*ell * p_max * (p_max+3) + b = get_theta(θ_tbl,m_max) / float(m_max) + + return tA_1norm <= a*b, p_max + +end + + +function calc_d(A,p::Int) + est = onenormest(A,p) + return est^(1.0/p) +end + +function _calc_optimal_sm(A, A_1norm, t::Real, m_max::Int=55, ell::Int=2) + + As = t*A + tA_1norm = t*A_1norm + + θ_tbl = θ_table() + if m_max > θ_tbl.max_m + error("m_max > ",θ_tbl.max_m, " is not supported") + end + + m_star = nothing + s_star = nothing + + flag, p_max = _condition_3_13(θ_tbl, tA_1norm, m_max, ell) + if flag + for (i, θ) in enumerate(θ_tbl.θs) + m = θ_tbl.ms[i] + s = Int(ceil(tA_1norm/θ)) + + if m_star === nothing + m_star = m + s_star = s + elseif m * s < m_star*s_star + m_star = m + s_star = s + end + end + else + # eq(3.11) + d = calc_d(As, 2) + for p in 2:p_max + # compute d_p+1 + d1 = calc_d(As, p+1) + αp = max(d,d1) + d = d1 + for m in p*(p-1):m_max + if m in θ_tbl.ms + s = Int(ceil(αp / get_theta(θ_tbl,m))) #compute_cost_div_m + if m_star === nothing + m_star = m + s_star = s + elseif m * s < m_star*s_star + m_star = m + s_star = s + end + end + end + end + s_star = max(s_star,1) + end + return m_star, s_star + +end + + +""" + _expm_multiply_impl!(w::AbstractVector{T} + t::Real, + As, + v::AbstractVector{T}, + mu::Real, #shift parameter + s::Int, + m_star::Int, + tol::Real, + ) where {T} + Calculate matrix exponential acting on some vector, ``w = e^{tA}v``, + using the Krylov subspace approximation. + + [Note] As is a sugeried matrix, i.e. As= A - mu*I + +""" +function _expm_multiply_impl!(w::AbstractVector{T}, + t::Real, + As, + v::AbstractVector{T}, + mu::Number, #shift parameter + s::Int, + m_star::Int, + tol::Real, + ) where {T} + #println(typeof(As)) + F = deepcopy(v) + vs = deepcopy(v) + η = exp(t*mu/s) + for i in 1:s + c1 = norm(vs,Inf) + for j in 1:m_star + coef = t / (s*j) + mul!(vs, As, coef*vs) + c2 = norm(vs,Inf) + F.+=vs + if c1+c2 <= tol*norm(F,Inf) + break + end + c1 = c2 + end + F.*=η + copyto!(vs,F) + end + copy!(w,F) + return w +end \ No newline at end of file diff --git a/lib/BloqadeKrylov/src/krylov.jl b/lib/BloqadeKrylov/src/krylov.jl index 506a4ea4c..ed394154d 100644 --- a/lib/BloqadeKrylov/src/krylov.jl +++ b/lib/BloqadeKrylov/src/krylov.jl @@ -107,7 +107,8 @@ function emulate_step!(prob::KrylovEvolution, step::Int, clock::Real, duration:: state = statevec(prob.reg) h = prob.hamiltonian - expmv!(-duration * im, h(clock), state; prob.options.tol) + prob.options.expmv_backend(-duration , im*h(clock), state; prob.options.tol) + if mod(step, prob.options.normalize_step) == 0 normalize!(prob.reg) end diff --git a/lib/BloqadeKrylov/src/magnus.jl b/lib/BloqadeKrylov/src/magnus.jl index 3ee665586..bc62d8f9c 100644 --- a/lib/BloqadeKrylov/src/magnus.jl +++ b/lib/BloqadeKrylov/src/magnus.jl @@ -127,7 +127,7 @@ function emulate_step!(prob::Magnus4Evolution, step::Int, clock::Real, duration: Ω4 = 0.5 * (A1 + A2) - duration*√3/12 * commutator(A1, A2) - expmv!(-im*duration, Ω4, state; prob.options.tol) + prob.options.expmv_backend(-duration, im*Ω4, state; prob.options.tol) # do we need this normalization? diff --git a/lib/BloqadeKrylov/src/onenormest.jl b/lib/BloqadeKrylov/src/onenormest.jl new file mode 100644 index 000000000..0625028f3 --- /dev/null +++ b/lib/BloqadeKrylov/src/onenormest.jl @@ -0,0 +1,334 @@ + +function onenormest_explicit(A, p::Int=1) + if p <=0 + error("p must be positive") + end + + if p == 1 + return opnorm(A,1) + else + D = similar(A) + mul!(D,A,A) + for i in 3:p + mul!(D,A,D) + end + end + + return opnorm(D,1) +end + +""" + Compute a lower bound of the 1-norm of a matrix to a power of p + + Parameters + ---------- + A : ndarray or other linear operator + A linear operator that can be transposed and that can + produce matrix products. + p : power of A, optional (default =1) + t : int, optional + A positive parameter controlling the tradeoff between + accuracy versus time and memory usage. + Larger values take longer and use more memory + but give more accurate output. + itmax : int, optional + Use at most this many iterations. + + Returns + ------- + est : float + An underestimate of the 1-norm of the sparse matrix. + + Notes + ----- + This is algorithm 2.4 of [1]. + + In [2] it is described as follows. + "This algorithm typically requires the evaluation of + about 4t matrix-vector products and almost invariably + produces a norm estimate (which is, in fact, a lower + bound on the norm) correct to within a factor 3." + + .. versionadded:: 0.13.0 + + References + ---------- + .. [1] Nicholas J. Higham and Francoise Tisseur (2000), + "A Block Algorithm for Matrix 1-Norm Estimation, + with an Application to 1-Norm Pseudospectra." + SIAM J. Matrix Anal. Appl. Vol. 21, No. 4, pp. 1185-1201. + + .. [2] Awad H. Al-Mohy and Nicholas J. Higham (2009), + "A new scaling and squaring algorithm for the matrix exponential." + SIAM J. Matrix Anal. Appl. Vol. 31, No. 3, pp. 970-989. + + +""" +function onenormest(A, p::Int=1, t::Int=2, itmax::Int=5) + if size(A,1) != size(A,2) + error("expect square matrix.") + end + + ## if t is larger than the order of A, then set it to the order of A-1 + t_in = min(t, size(A,1)-1) + t_in = t_in == 0 ? 1 : t_in + + + est, nmults, nresamples = _onenormest_impl(A, adjoint(A), p, t_in, itmax) + + return est +end + + + +## _mulp! +## Y = A^p * X +## p must be positive >=1 +function _mulp!(Y::AbstractVecOrMat, A, X::AbstractVecOrMat, p::Int) + + # allocate tempo space + w = similar(X) + + mul!(w,A,X) + copyto!(Y,w) + for i in 2:p + mul!(w,A,Y) + copyto!(Y,w) + end + Y +end + +""" + From Higham and Tisseur: + "Everything in this section remains valid for complex matrices + provided that sign(A) is redefined as the matrix (aij / |aij|) + (and sign(0) = 1) transposes are replaced by conjugate transposes." +""" +@inline function _sign_roundup(X::T) where {T <: Number} + X == 0 ? T(1) : X / abs(X) +end + + + +## note this does not check the size of A and B, they need to be the same +@inline function _check_vecs_parallel(a::AbstractVector{T}, b::AbstractVector{T}) where {T <: Number} + return abs(dot(a,b)) .≈ length(a) +end + + +@inline function _check_vec_parallel_in_mat(a::AbstractVector{T}, B::AbstractMatrix{T}) where {T <: Number} + return any(abs.(adjoint(a) * B) .≈ length(a)) +end + +## note this does not check the size of A and B. They need to be the same +## size(A) == (n,t) +## size(B) == (n,t) +function _check_cols_parallel(A::AbstractMatrix{T}, B::AbstractMatrix{T}) where {T <: Number} + n = size(A,1) + for j in 1:size(A,2) + if !_check_vec_parallel_in_mat(A[:,j],B) + return false + end + end + return true +end + + +function _check_need_resample(i, X::AbstractMatrix{T}, Y::AbstractMatrix{T}) where {T <: Number} + # i-th col of X need to resample if + # 1) its parallel for a previous col of X + # OR 2) its parallel to a col of Y + n, t = size(X) + v = X[:,i] + for j in 1:i-1 + if _check_vecs_parallel(v,X[:,j]) + return true + end + end + + for j in 1:t + if _check_vecs_parallel(v,Y[:,j]) + return true + end + end + + return false + +end + +@inline function _resample_col(i::Int, X::AbstractMatrix{T}) where {T <: Number} + X[:,i] = rand((1.,-1.),size(X,1)) +end + +""" + Compute a lower bound of the 1-norm of a sparse matrix, [implementation] + + Parameters + ---------- + A : AbstractMatrix + A linear operator that can produce matrix products, must be square matrix with (nxn) + AT : AbstractMatrix + The transpose of A. + p : int, optional (default =1) + The power of A + t : int, optional + A positive parameter controlling the tradeoff between + accuracy versus time and memory usage. + itmax : int, optional + Use at most this many iterations. + + Returns + ------- + est : float + An underestimate of the 1-norm of the sparse matrix. + + nmults : int, optional + The number of matrix products that were computed. + nresamples : int, optional + The number of times a parallel column was observed, + necessitating a re-randomization of the column. + + [Note] This is algorithm 2.4. + +""" +function _onenormest_impl(A, AT, p::Int=1, t::Int=2, itmax::Int=5) + if itmax < 2 + error("itmax must be at least 2") + end + + if t < 1 + error("must be at least one column, t>=1") + end + + n = size(A,1) + + if t >= n + error("t must be less than the order of A: t=$t n=$n") + end + + T = eltype(A) + + + nmults::Int = 0 + nresamples::Int = 0 + + X = ones(T,n,1) + if t > 1 + X = hcat(X,rand((1.,-1.),n,t-1)) + ## checking with previous col, to see if resample is needed + for i in 2:t + while _check_vecs_parallel(X[:,i],X[:,i-1]) + #need resample i-th column + X[:,i] = rand((1.,-1.),n) + nresamples += 1 + end + end + end + + # normalize for each column to be unit 1-norm + X ./= n + + est =0 + est_old = 0 + ind_hist = Vector{Int}(undef,0) + k::Int = 1 + S = zeros(T,n,t) + + ind = nothing + ind_best = nothing + + while true + + Y = similar(X) + _mulp!(Y,A,X,p) # mulp: Y = A^p * X + + + nmults += 1 + mags = collect( norm(Y[:,j],1) for j in 1:t ) + est, best_j = findmax(mags) + + if (est > est_old) || (k==2) + if k >= 2 + ind_best = ind[best_j] + end + w = Y[:,best_j] + end + + # (1) + if (k >= 2) && (est <= est_old) + est = est_old + break + end + est_old = est + S_old = S + if k > itmax + break + end + + S = _sign_roundup.(Y) + + #(2) + if _check_cols_parallel(S, S_old) + break + end + + if t > 1 + for i in 1:t + while _check_need_resample(i,S,S_old) + S[:,i] = rand((1.,-1.),n) + nresamples += 1 + end + end + end + S_old = nothing + + #(3), reuse Y: (note Y is the Z) + _mulp!(Y,AT,S,p) # mulp: Y = A^p * X + + + nmults += 1 + Y = abs.(Y) + + h = collect( maximum(Y[j,:]) for j in 1:n ) + + Y = nothing + + #(4) + if (k >= 2) + if(maximum(h) == h[ind_best]) + break + end + end + + ## sort h in descending order, and re-order ind correspondingly. + ind = reverse(sortperm(h))[1:t+length(ind_hist)] + + h = nothing + + if t > 1 + # (5) + + seen = collect(elem in ind_hist for elem in ind) + # break if the most promising t vec have been visited + if all(seen[1:t]) + break + end + + ind = vcat(ind[map(!,seen)], ind[seen]) + end + + fill!(X,0) + for j in 1:t + X[ind[j],j] = 1. + end + + seen = collect(elem in ind_hist for elem in ind[1:t]) + new_ind = (ind[1:t])[map(!,seen)] + ind_hist = vcat(ind_hist, new_ind) + k += 1 + + end + + return est, nmults, nresamples + +end \ No newline at end of file diff --git a/lib/BloqadeKrylov/test/Project.toml b/lib/BloqadeKrylov/test/Project.toml index 74bd0189a..4d1aa9aa9 100644 --- a/lib/BloqadeKrylov/test/Project.toml +++ b/lib/BloqadeKrylov/test/Project.toml @@ -5,6 +5,7 @@ BloqadeODE = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe5" BloqadeWaveforms = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe7" ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/lib/BloqadeKrylov/test/cfet42_sinX.jl b/lib/BloqadeKrylov/test/cfet42_sinX.jl index d91f5c2f8..79340d397 100644 --- a/lib/BloqadeKrylov/test/cfet42_sinX.jl +++ b/lib/BloqadeKrylov/test/cfet42_sinX.jl @@ -8,6 +8,7 @@ using BloqadeExpr: Hamiltonian using BloqadeODE using Yao + @testset "cfet42_sinX" begin atoms = generate_sites(ChainLattice(), 1, scale = 1) @@ -38,3 +39,35 @@ using Yao end + + +@testset "cfet42_sinX expm multiply backend" begin + + atoms = generate_sites(ChainLattice(), 1, scale = 1) + wf = Waveform(t->2.2*2π*sin(2π*t), duration = 1.3); + h = rydberg_h(atoms; Ω = wf) + + ## do magnus4 + reg = zero_state(length(atoms)) + clocks = collect(0:1e-3:1.3) + prob = CFETEvolution(reg, clocks, h, CFET4_2(), expmv_backend = expm_multiply!) + show(stdout, MIME"text/plain"(), prob) + #@test_throws ArgumentError KrylovEvolution(reg, [-0.1, 0.1], h) + emulate!(prob) + + + #benchmark against ODE solver: + odereg = zero_state(length(atoms)) + ODEprob = SchrodingerProblem(odereg,1.3,h) + show(stdout, MIME"text/plain"(), ODEprob) + emulate!(ODEprob) + + @test prob.reg.state ≈ ODEprob.reg.state + + prob = CFETEvolution(reg, clocks, h, CFET4_2()) + for info in prob + @test info.clock == clocks[info.step] + end + + +end diff --git a/lib/BloqadeKrylov/test/expm_multiply.jl b/lib/BloqadeKrylov/test/expm_multiply.jl new file mode 100644 index 000000000..373fb71e6 --- /dev/null +++ b/lib/BloqadeKrylov/test/expm_multiply.jl @@ -0,0 +1,132 @@ +using Test +using BloqadeKrylov +using SparseArrays +using BloqadeLattices +using BloqadeWaveforms +using BloqadeExpr: Hamiltonian +using BloqadeExpr +using Yao + +@testset "expm_multiply_impl Real, dense A" begin + + A = rand(10, 10) + st = rand(10) + + + vold = BloqadeKrylov.expmv(1, A, st) + + + vnew = similar(st) + st_before = deepcopy(st) + BloqadeKrylov._expm_multiply_impl!(vnew, 1, A, st, 0, 1, 40, 2^-53) + + # checking st is not modefied + @test st_before == st + + # checking results against expmv + @test vnew ≈ vold +end + +@testset "expm_multiply_impl complex, sparse A" begin + + A = sprand(ComplexF64,10, 10, 0.6) + st = rand(ComplexF64,10) + + + vold = BloqadeKrylov.expmv(1, A, st) + + + vnew = similar(st) + st_before = deepcopy(st) + BloqadeKrylov._expm_multiply_impl!(vnew, 1, A, st, 0, 1, 40, 2^-53) + + # checking st is not modefied + @test st_before == st + + # checking results against expmv + @test vnew ≈ vold + +end + + +@testset "expm_multiply Real, dense A" begin + + A = rand(10, 10) + st = rand(10) + + + vold = BloqadeKrylov.expmv(2.55, A, st) + + + vnew = similar(st) + st_before = deepcopy(st) + BloqadeKrylov.expm_multiply!(vnew, 2.55, A, st) + + # checking st is not modefied + @test st_before == st + + # checking results against expmv + @test vnew ≈ vold + +end + +@testset "expm_multiply complex, sparse A" begin + + A = sprand(ComplexF64,10, 10, 0.6) + st = rand(ComplexF64,10) + + + vold = BloqadeKrylov.expmv(2.55, A, st) + + + vnew = similar(st) + st_before = deepcopy(st) + BloqadeKrylov.expm_multiply!(vnew, 2.55, A, st) + + # checking st is not modefied + @test st_before == st + + # checking results against expmv + @test vnew ≈ vold + +end + +@testset "expm_multiply, Rydberg" begin + + atoms = generate_sites(ChainLattice(), 4, scale = 6.1) + clocks = [0.0, 0.5, 0.8, 1.1, 1.5, 1.6] + wf = piecewise_constant(clocks = clocks, values = [0.0, 2.1, 2.1, 1.5, 0.0]) + h = rydberg_h(atoms; Ω = wf) + + Ham = Hamiltonian(Float64, h) + #print(Ham) + Ht = Ham(0.6) + reg = zero_state(length(atoms)) + state = statevec(reg) + + + vold = BloqadeKrylov.expmv(0.05, to_matrix(Ht), state) + + println("main") + println(vold) + vs = similar(state) + BloqadeKrylov.expm_multiply!(vs, 0.05, to_matrix(Ht), state) + #println(vs) + #vnew = BloqadeKrylov.expm_multiply(2.55, to_matrix(Ht), state) + + #println(vnew) + @test vold ≈ vs + + +end + + +#= +@testset "develop, please remove before pub" begin + + A = rand(10, 10) + + println( BloqadeKrylov.get_optimal_sm(1, A) ) + +end +=# \ No newline at end of file diff --git a/lib/BloqadeKrylov/test/onenormest.jl b/lib/BloqadeKrylov/test/onenormest.jl new file mode 100644 index 000000000..96d5a45d2 --- /dev/null +++ b/lib/BloqadeKrylov/test/onenormest.jl @@ -0,0 +1,165 @@ +using Test +using BloqadeKrylov +using LinearAlgebra +using SparseArrays +using BloqadeExpr + + + +@testset "internal _mulp!" begin + + A = sprand(10, 10, 0.5) + st = rand(10) + + G = A + # testing p: + for p in 1:5 + tar = similar(st) + BloqadeKrylov._mulp!(tar, A, st, p) + + src = G*st + + @test tar ≈ src + G *= A + end + + +end + + +@testset "internal _sign_roundup(X::T)" begin + + a = 3.34 + b = -3.24 + c = 0.0 + d = -0.0 + e = 1+1im + f = -2+1im + + + @test BloqadeKrylov._sign_roundup(a) == 1 + @test BloqadeKrylov._sign_roundup(b) == -1 + @test BloqadeKrylov._sign_roundup(c) == 1 + @test BloqadeKrylov._sign_roundup(d) == 1 + @test BloqadeKrylov._sign_roundup(e) == (1+1im)/√2 + @test BloqadeKrylov._sign_roundup(f) == (-2+1im)/√5 + +end + + +@testset "internal _check_cols_parallel (REAL)" begin + + A = randn(10,10) + A = BloqadeKrylov._sign_roundup.(A) + + @test BloqadeKrylov._check_cols_parallel(A,A) == true + + + +end + +@testset "internal _check_cols_parallel (Complex)" begin + + A = randn(ComplexF64, 10,10) + A = BloqadeKrylov._sign_roundup.(A) + + + @test BloqadeKrylov._check_cols_parallel(A,A) == true + +end + + + +@testset "internal _check_vecs_parallel (Complex)" begin + + A = randn(ComplexF64, 10,10) + A = BloqadeKrylov._sign_roundup.(A) + + for i in 1:10 + for j in 1:10 + if i == j + @test BloqadeKrylov._check_vecs_parallel(A[:,i],A[:,j]) == true + end + end + end + + + +end + +@testset "onenormest impl" begin + + ## real + A = [1. 0. 0. ; 5. 8. 2. ; 0 -1 0] + + nrm = LinearAlgebra.opnorm(A,1) + nrmest,_,_ = BloqadeKrylov._onenormest_impl(A, transpose(A), 1) + + @test nrm ≈ nrmest + + + A = [1. 0. 0. ; 5. 8. 2. ; 0 -1 0] + + nrm = LinearAlgebra.opnorm(A*A,1) + nrmest,_,_ = BloqadeKrylov._onenormest_impl(A, transpose(A), 2) + + @test nrm ≈ nrmest + + ## complex + A = [1+1im 2+0.5im 3.; 0. 6.7im -3.2-1im; 3.14 0.7+0.55im 0.29im+3.2] + + nrm = LinearAlgebra.opnorm(A,1) + + nrmest, _ , _ = BloqadeKrylov._onenormest_impl(A, adjoint(A), 1) + + @test nrm ≈ nrmest + + A = [1+1im 2+0.5im 3.; 0. 6.7im -3.2-1im; 3.14 0.7+0.55im 0.29im+3.2] + + nrm = LinearAlgebra.opnorm(A*A,1) + + nrmest, _ , _ = BloqadeKrylov._onenormest_impl(A, adjoint(A), 2) + + @test nrm ≈ nrmest + + +end + + +@testset "onenormest, API" begin + + ## real + A = [1. 0. 0. ; 5. 8. 2. ; 0 -1 0] + + nrm = LinearAlgebra.opnorm(A,1) + nrmest = BloqadeKrylov.onenormest(A, 1) + + @test nrm ≈ nrmest + + + A = [1. 0. 0. ; 5. 8. 2. ; 0 -1 0] + + nrm = LinearAlgebra.opnorm(A*A,1) + nrmest = BloqadeKrylov.onenormest(A, 2) + + @test nrm ≈ nrmest + + ## complex + A = [1+1im 2+0.5im 3.; 0. 6.7im -3.2-1im; 3.14 0.7+0.55im 0.29im+3.2] + + nrm = LinearAlgebra.opnorm(A,1) + + nrmest = BloqadeKrylov.onenormest(A, 1) + + @test nrm ≈ nrmest + + A = [1+1im 2+0.5im 3.; 0. 6.7im -3.2-1im; 3.14 0.7+0.55im 0.29im+3.2] + + nrm = LinearAlgebra.opnorm(A*A,1) + + nrmest = BloqadeKrylov.onenormest(A, 2) + + @test nrm ≈ nrmest + + +end \ No newline at end of file diff --git a/lib/BloqadeKrylov/test/runtests.jl b/lib/BloqadeKrylov/test/runtests.jl index b0b436abe..0a2a1ba1d 100644 --- a/lib/BloqadeKrylov/test/runtests.jl +++ b/lib/BloqadeKrylov/test/runtests.jl @@ -9,11 +9,14 @@ end -#= -@testset "ValHamiltonian" begin - include("utils.jl") +@testset "expm_multiply" begin + include("expm_multiply.jl") +end + + +@testset "onenormest" begin + include("onenormest.jl") end -=# @testset "expmv" begin include("expmv.jl") @@ -28,6 +31,7 @@ end include("cfet42_sinX.jl") end + @testset "cfet65_sinX" begin include("cfet65_sinX.jl") end