Skip to content

Commit 3695c88

Browse files
authored
Merge pull request #86 from QuanEstimation/unit-test
Add PythonCall extension & Unit test
2 parents 3f2478c + 0715974 commit 3695c88

37 files changed

+2032
-34
lines changed

.github/workflows/CI.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- unit-test
6+
tags: '*'
7+
pull_request:
8+
concurrency:
9+
# Skip intermediate builds: always.
10+
# Cancel intermediate builds: only if it is a pull request build.
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
13+
jobs:
14+
test:
15+
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
version:
21+
# - '1.8'
22+
- '1.9'
23+
os:
24+
- ubuntu-latest
25+
arch:
26+
- x64
27+
# include:
28+
# - os: windows-latest
29+
# version: '1'
30+
# arch: x64
31+
# - os: macOS-latest
32+
# version: '1'
33+
# arch: x64
34+
steps:
35+
- uses: actions/checkout@v2
36+
- uses: julia-actions/setup-julia@v1
37+
with:
38+
version: ${{ matrix.version }}
39+
arch: ${{ matrix.arch }}
40+
- uses: julia-actions/cache@v1
41+
- uses: julia-actions/julia-buildpkg@v1
42+
- uses: julia-actions/julia-runtest@v1
43+
- uses: julia-actions/julia-processcoverage@v1
44+
- uses: codecov/codecov-action@v2
45+
with:
46+
files: lcov.info

Project.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,24 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1818
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1919
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2020
ReinforcementLearning = "158674fc-8238-5cab-b5ba-03dfc80d1318"
21+
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
2122
SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13"
2223
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2324
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
2425
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
2526
Trapz = "592b5752-818d-11e9-1e9a-2b8ca4a44cd1"
2627
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
2728

29+
[weakdeps]
30+
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
31+
32+
[extensions]
33+
QuanEstimationPyExt = "PythonCall"
34+
2835
[compat]
2936
BoundaryValueDiffEq = "2"
30-
Convex = "0.15"
3137
Distributions = "0.25"
32-
Flux = "0.12, 0.13"
38+
Flux = "0.12, 0.13, 0.14"
3339
Interpolations = "0.13, 0.14"
3440
IntervalSets = "0.5, 0.7"
3541
JLD2 = "0.4"
@@ -41,7 +47,6 @@ StableRNGs = "1"
4147
StatsBase = "0.33"
4248
Trapz = "2"
4349
Zygote = "0.6"
44-
julia = "1.7"
4550

4651
[extras]
4752
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# QuanEstimation.jl
22

3-
[![Dev](https://img.shields.io/badge/docs-stable-blue.svg)](https://quanestimation.github.io/QuanEstimation/)
3+
[![][docs-img]][docs-url]
4+
[![][action-img]][action-url]
5+
[![][codecov-img]][codecov-url]
6+
47

58
QuanEstimation is a Python-Julia based open-source toolkit for quantum parameter estimation, which consist in the calculation of the quantum metrological tools and quantum resources, and the optimizations with respect to probe states, controls or measurements, as well as comprehensive optimizations in quantum metrology. Futhermore, QuanEstimation can generate not only optimal quantum parameter estimation schemes, but also adaptive measurement schemes.
69

@@ -19,3 +22,12 @@ If you use QuanEstimation in your research, please cite the following paper:
1922
[1] M. Zhang, H.-M. Yu, H. Yuan, X. Wang, R. Demkowicz-Dobrzański, and J. Liu,
2023
QuanEstimation: An open-source toolkit for quantum parameter estimation,
2124
[Phys. Rev. Research **4**, 043057 (2022).](https://doi.org/10.1103/PhysRevResearch.4.043057)
25+
26+
27+
28+
[action-img]: https://github.com/QuanEstimation/QuanEstimation.jl/actions/workflows/CI.yml/badge.svg
29+
[action-url]: https://github.com/QuanEstimation/QuanEstimation.jl/actions
30+
[codecov-img]: https://codecov.io/gh/QuanEstimation/QuanEstimation.jl/branch/master/graph/badge.svg
31+
[codecov-url]: https://codecov.io/gh/QuanEstimation/QuanEstimation.jl?branch=test-codecov
32+
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
33+
[docs-url]: https://quanestimation.github.io/QuanEstimation/

examples/CramerRao_bounds.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ M = [M1, M2]
2121
# time length for the evolution
2222
tspan = range(0., 50., length=2000)
2323
# dynamics
24-
rho, drho = QuanEstimation.expm(tspan, rho0, H0, dH, decay)
24+
rho, drho = QuanEstimation.expm(tspan, rho0, H0, dH, decay=decay)
2525
# calculation of the CFI and QFI
2626
Im, F = Float64[], Float64[]
2727
for ti in 2:length(tspan)

ext/QuanEstimationPyExt.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module QuanEstimationPyExt
2+
using PythonCall
3+
using QuanEstimation
4+
np = pyimport("numpy")
5+
# QuanEstimation.Htot(H0::PyArray, Hc::PyList, ctrl) = QuanEstimation.Htot(Matrix(H0), [Matrix(hc) for hc in Hc], ctrl)
6+
QuanEstimation.ControlOpt(ctrl::PyList, ctrl_bound::PyList, seed::Py) = QuanEstimation.ControlOpt(pyconvert(Vector{Vector{Float64}}, ctrl), pyconvert(Vector{Float64}, ctrl_bound), seed)
7+
QuanEstimation.Lindblad(
8+
H0::PyArray,
9+
dH::PyList,
10+
Hc::PyList,
11+
ctrl::PyList,
12+
ρ0::PyArray,
13+
tspan::PyArray,
14+
decay_opt::PyList,
15+
γ::PyList;
16+
kwargs...,
17+
) = QuanEstimation.Lindblad(
18+
pyconvert(Matrix{ComplexF64}, H0),
19+
pyconvert(Vector{Matrix}, dH),
20+
pyconvert(Vector{Matrix}, Hc),
21+
pyconvert(Vector{Vector{Float64}}, ctrl),
22+
pyconvert(Matrix{ComplexF64}, ρ0),
23+
pyconvert(Vector, tspan),
24+
pyconvert(Vector{Matrix}, decay_opt),
25+
pyconvert(Vector, γ);
26+
kwargs...,
27+
)
28+
QuanEstimation.Lindblad(
29+
H0::PyArray,
30+
dH::PyList,
31+
ψ0::PyList,
32+
tspan::PyArray,
33+
decay_opt::PyList,
34+
γ::PyList;
35+
kwargs...,
36+
) = QuanEstimation.Lindblad(
37+
pyconvert(Matrix{ComplexF64}, H0),
38+
pyconvert(Vector{Matrix}, dH),
39+
pyconvert(Vector{ComplexF64}, ψ0),
40+
pyconvert(Vector, tspan),
41+
pyconvert(Vector{Matrix}, decay_opt),
42+
pyconvert(Vector, γ);
43+
kwargs...,
44+
)
45+
end

src/Algorithm/DDPG.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ using Flux: glorot_normal, glorot_uniform
33
using StableRNGs
44
using IntervalSets
55

6-
Base.copyto!(dest::ReinforcementLearning.NeuralNetworkApproximator, src::ReinforcementLearning.NeuralNetworkApproximator) =
7-
Flux.loadparams!(dest.model, Flux.params(src))
86

97
function Base.rsplit( v, l::Int)
108
u = reshape(v,l,length(v)÷l)

src/ObjectiveFunc/AsymptoticBound/AnalogCramerRao.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Convex
12
function decomposition(A)
23
C = bunchkaufman(A; check = false)
34
R = sqrt(Array(C.D)) * C.U'C.P

src/Parameterization/Lindblad/LindbladDynamics.jl

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ function liouville_dissip_py(A::Array{T}) where {T<:Complex}
5151
end
5252

5353
function dissipation(
54-
Γ::AbstractVector,
54+
Γ::V,
5555
γ::Vector{R},
5656
t::Int = 1,
57-
) where {T<:Complex,R<:Real}
57+
) where {V<:AbstractVector,R<:Real}
5858
[γ[i] * liouville_dissip(Γ[i]) for i = 1:length(Γ)] |> sum
5959
end
6060

6161
function dissipation(
62-
Γ::AbstractVector,
62+
Γ::V,
6363
γ::Vector{Vector{R}},
6464
t::Int = 1,
65-
) where {T<:Complex,R<:Real}
65+
) where {V<:AbstractVector,R<:Real}
6666
[γ[i][t] * liouville_dissip(Γ[i]) for i = 1:length(Γ)] |> sum
6767
end
6868

@@ -81,20 +81,21 @@ function liouvillian(
8181
-1.0im * freepart + dissp
8282
end
8383

84-
function Htot(H0::Matrix{T}, Hc::Vector{Matrix{T}}, ctrl) where {T<:Complex,R}
84+
function Htot(H0::T, Hc::V, ctrl) where {T<:AbstractArray, V<:AbstractVector}
8585
[H0] .+ ([ctrl[i] .* [Hc[i]] for i = 1:length(ctrl)] |> sum)
8686
end
8787

8888
function Htot(
89-
H0::Matrix{T},
90-
Hc::Vector{Matrix{T}},
89+
H0::T,
90+
Hc::V,
9191
ctrl::Vector{R},
92-
) where {T<:Complex,R<:Real}
93-
H0 + ([ctrl[i] * Hc[i] for i = 1:length(ctrl)] |> sum)
92+
) where {T<:AbstractArray,V<:AbstractVector, R<:Real}
93+
H0 + ([ctrl[i] .* [Hc[i]] for i = 1:length(ctrl)] |> sum)
9494
end
9595

96-
function Htot(H0::Vector{Matrix{T}}, Hc::Vector{Matrix{T}}, ctrl) where {T<:Complex}
97-
H0 + ([ctrl[i] .* [Hc[i]] for i = 1:length(ctrl)] |> sum)
96+
97+
function Htot(H0::V1, Hc::V2, ctrl) where {V1,V2<:AbstractVector}
98+
H0 + ([ctrl[i] * Hc[i] for i = 1:length(ctrl)] |> sum)
9899
end
99100

100101
function expL(H, decay_opt, γ, dt, tj = 1)
@@ -118,7 +119,7 @@ When applied to the case of single parameter.
118119
function expm(
119120
tspan::AbstractVector,
120121
ρ0::AbstractMatrix,
121-
H0::AbstractMatrix,
122+
H0::AbstractVecOrMat,
122123
dH::AbstractMatrix;
123124
decay::Union{AbstractVector, Missing}=missing,
124125
Hc::Union{AbstractVector, Missing}=missing,
@@ -197,7 +198,7 @@ The dynamics of a density matrix is of the form ``\partial_t\rho=-i[H,\rho]+\su
197198
function expm(
198199
tspan::AbstractVector,
199200
ρ0::AbstractMatrix,
200-
H0::AbstractMatrix,
201+
H0::AbstractVecOrMat,
201202
dH::AbstractVector;
202203
decay::Union{AbstractVector, Missing}=missing,
203204
Hc::Union{AbstractVector, Missing}=missing,
@@ -241,7 +242,8 @@ function expm(
241242
para_num = length(dH)
242243
ctrl_num = length(Hc)
243244
ctrl_interval = ((length(tspan) - 1) / length(ctrl0[1])) |> Int
244-
ctrl = [repeat(ctrl0[i], 1, ctrl_interval) |> transpose |> vec for i = 1:ctrl_num]
245+
## TODO reconstruct repeat feature
246+
ctrl = [repeat(ctrl0[i], outer=ctrl_interval) for i = 1:ctrl_num]
245247

246248
H = Htot(H0, Hc, ctrl)
247249
dH_L = [liouville_commu(dH[i]) for i = 1:para_num]
@@ -271,7 +273,7 @@ end
271273
function expm_py(
272274
tspan,
273275
ρ0::AbstractMatrix,
274-
H0::AbstractMatrix,
276+
H0::AbstractVecOrMat,
275277
dH::AbstractMatrix,
276278
Hc::AbstractVector,
277279
decay_opt::AbstractVector,
@@ -304,7 +306,7 @@ end
304306
function expm_py(
305307
tspan,
306308
ρ0::AbstractMatrix,
307-
H0::AbstractMatrix,
309+
H0::AbstractVecOrMat,
308310
dH::AbstractVector,
309311
decay_opt::AbstractVector,
310312
γ,
@@ -353,7 +355,7 @@ expm(tspan, ρ0, H0, dH, decay, Hc, ctrl) =
353355
function secondorder_derivative(
354356
tspan::AbstractVector,
355357
ρ0::AbstractMatrix,
356-
H0::AbstractMatrix,
358+
H0::AbstractVecOrMat,
357359
dH::AbstractVector,
358360
dH_∂x::AbstractVector,
359361
decay_opt::Vector{Matrix{T}},
@@ -399,7 +401,7 @@ When applied to the case of single parameter.
399401
function ode(
400402
tspan::AbstractVector,
401403
ρ0::AbstractMatrix,
402-
H0::AbstractMatrix,
404+
H0::AbstractVecOrMat,
403405
dH::AbstractMatrix;
404406
decay::Union{AbstractVector, Missing}=missing,
405407
Hc::Union{AbstractVector, Missing}=missing,
@@ -480,7 +482,7 @@ The dynamics of a density matrix is of the form ``\partial_t\rho=-i[H,\rho]+\su
480482
function ode(
481483
tspan::AbstractVector,
482484
ρ0::AbstractMatrix,
483-
H0::AbstractMatrix,
485+
H0::AbstractVecOrMat,
484486
dH::AbstractVector;
485487
decay::Union{AbstractVector, Missing}=missing,
486488
Hc::Union{AbstractVector, Missing}=missing,
@@ -559,7 +561,7 @@ ode(tspan, ρ0, H0, dH, decay, Hc, ctrl) =
559561
function ode_py(
560562
tspan,
561563
ρ0::AbstractMatrix,
562-
H0::AbstractMatrix,
564+
H0::AbstractVecOrMat,
563565
dH::AbstractMatrix,
564566
Hc::AbstractVector,
565567
Γ::AbstractVector,
@@ -589,7 +591,7 @@ end
589591
function ode_py(
590592
tspan,
591593
ρ0::AbstractMatrix,
592-
H0::AbstractMatrix,
594+
H0::AbstractVecOrMat,
593595
dH::AbstractVector,
594596
Γ::AbstractVector,
595597
γ,

src/Parameterization/Lindblad/LindbladWrapper.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ function _ini_measurement!(opt::Mopt_LinearComb, dim::Int; eps=GLOBAL_EPS)
175175
end
176176

177177
if ismissing(B)
178-
opt.B = [rand(opt.rng, length(POVM_basis)) for _ in 1:M_num]
178+
opt.B = [rand(opt.rng, length(opt.POVM_basis)) for _ in 1:M_num]
179179
end
180180
end
181181

src/Parameterization/Parameterization.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ abstract type Ode <: AbstractDynamicsProblemType end
2121
# check if the dynamics are with noise
2222
isNoisy(::noiseless) = false
2323
isNoisy(::noisy) = true
24-
isNoisy(dynamics::AbstractDynamics) = dynamics.noise_type |> eval |> isNoisy
24+
isNoisy(dynamics::AbstractDynamics) = dynamics.noise_type |> isNoisy
2525

2626
# check if the dynamics are in control
2727
isCtrl(::free) = false
2828
isCtrl(::controlled) = true
29-
isCtrl(dynamics::AbstractDynamics) = dynamics.ctrl_type |> eval |> isCtrl
29+
isCtrl(dynamics::AbstractDynamics) = dynamics.ctrl_type |> isCtrl
3030

3131
include("Lindblad/Lindblad.jl")
3232
include("Kraus/Kraus.jl")

src/QuanEstimation.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
module QuanEstimation
2+
export ControlOpt, ControlMeasurementOpt, CMopt, StateMeasurementOpt, SMopt, StateControlMeasurementOpt, SCMopt, opt_target, Htot
3+
export isCtrl, isNoisy
4+
export Lindblad
5+
export Output
6+
export autoGRAPE
7+
export QFIM_obj
8+
export QuanEstSystem
9+
export solve
210
using Random
311
using LinearAlgebra
412
using Zygote
@@ -7,7 +15,6 @@ using DelimitedFiles
715
using StatsBase
816
using Flux
917
using ReinforcementLearning
10-
using Convex
1118
using SCS
1219
using BoundaryValueDiffEq
1320
using Trapz

0 commit comments

Comments
 (0)