From 7da53abcebfb2510a843e6284265101553c35c1a Mon Sep 17 00:00:00 2001 From: HuaiMing Date: Tue, 31 May 2022 16:51:04 +0800 Subject: [PATCH] regist --- LICENSE | 21 - Project.toml | 4 +- README.md | 18 +- examples/Bayesian_CramerRao_bounds.jl | 58 ++ examples/Bayesian_estimation.jl | 51 + examples/CMopt_NV.jl | 63 ++ examples/CMopt_qubit.jl | 48 + examples/CramerRao_bounds.jl | 34 + examples/Holevo_CramerRao_bound.jl | 40 + examples/SCMopt_NV.jl | 61 ++ examples/SCMopt_qubit.jl | 46 + examples/SCopt_NV.jl | 70 ++ examples/SCopt_qubit.jl | 55 + examples/SMopt_NV.jl | 61 ++ examples/SMopt_qubit.jl | 46 + examples/adaptMZI.jl | 29 + examples/adaptive.jl | 50 + examples/control_optimization_NV.jl | 97 ++ examples/control_optimization_qubit.jl | 72 ++ examples/measurement_optimization_LC_NV.jl | 73 ++ examples/measurement_optimization_LC_qubit.jl | 58 ++ .../measurement_optimization_projection_NV.jl | 63 ++ ...asurement_optimization_projection_qubit.jl | 48 + .../measurement_optimization_rotation_NV.jl | 73 ++ ...measurement_optimization_rotation_qubit.jl | 58 ++ examples/state_optimization_LMG1.jl | 67 ++ examples/state_optimization_LMG2.jl | 75 ++ src/Algorithm/AD.jl | 227 +++++ src/Algorithm/Algorithm.jl | 213 ++++ src/Algorithm/DDPG.jl | 388 +++++++ src/Algorithm/DE.jl | 847 +++++++++++++++ src/Algorithm/GRAPE.jl | 493 +++++++++ src/Algorithm/Iterative.jl | 43 + src/Algorithm/NM.jl | 152 +++ src/Algorithm/PSO.jl | 964 ++++++++++++++++++ .../adaptive.jl => Common/AdaptiveScheme.jl} | 215 ++-- src/Common/BayesEstimation.jl | 461 +++++++++ src/Common/Common.jl | 368 +++++++ src/Common/mintime.jl | 74 ++ src/IO.jl | 1 + .../AsymptoticBound/AsymptoticBound.jl | 52 +- .../AsymptoticBound/AsymptoticBoundWrapper.jl | 2 +- .../AsymptoticBound/CramerRao.jl | 329 +++--- .../AsymptoticBound/Holevo.jl | 45 +- .../BayesianBound/BayesianBound.jl | 0 .../BayesianBound/BayesianCramerRao.jl | 470 +++++++++ .../BayesianBound/ZivZakai.jl | 12 +- .../ObjectiveFunc.jl} | 0 src/OptScenario/OptScenario.jl | 215 ++++ .../kraus => Parameterization/Kraus}/Kraus.jl | 0 src/Parameterization/Kraus/KrausData.jl | 48 + .../Kraus}/KrausDynamics.jl | 16 +- src/Parameterization/Kraus/KrausWrapper.jl | 63 ++ .../Lindblad}/Lindblad.jl | 0 .../Lindblad}/LindbladData.jl | 1 - .../Lindblad}/LindbladDynamics.jl | 87 +- .../Lindblad}/LindbladWrapper.jl | 142 ++- .../Parameterization.jl} | 4 +- src/QuanEstimation.jl | 16 +- .../resources.jl => Resource/Resource.jl} | 17 +- src/algorithm/AD.jl | 35 +- src/algorithm/DDPG.jl | 8 - src/algorithm/DE.jl | 159 ++- src/algorithm/GRAPE.jl | 10 - src/algorithm/NM.jl | 26 +- src/algorithm/PSO.jl | 128 +-- src/algorithm/algorithm.jl | 231 +++-- src/common/BayesEstimation.jl | 403 +++++++- src/common/common.jl | 43 +- src/common/mintime.jl | 21 +- src/dynamics/kraus/KrausData.jl | 30 - src/dynamics/kraus/KrausWrapper.jl | 46 - src/io.jl | 224 ++++ .../BayesianBound/BayesianCramerRao.jl | 352 ------- src/optim/optim.jl | 121 --- src/run.jl | 54 +- 76 files changed, 7967 insertions(+), 1328 deletions(-) delete mode 100644 LICENSE create mode 100644 examples/Bayesian_CramerRao_bounds.jl create mode 100644 examples/Bayesian_estimation.jl create mode 100644 examples/CMopt_NV.jl create mode 100644 examples/CMopt_qubit.jl create mode 100644 examples/CramerRao_bounds.jl create mode 100644 examples/Holevo_CramerRao_bound.jl create mode 100644 examples/SCMopt_NV.jl create mode 100644 examples/SCMopt_qubit.jl create mode 100644 examples/SCopt_NV.jl create mode 100644 examples/SCopt_qubit.jl create mode 100644 examples/SMopt_NV.jl create mode 100644 examples/SMopt_qubit.jl create mode 100644 examples/adaptMZI.jl create mode 100644 examples/adaptive.jl create mode 100644 examples/control_optimization_NV.jl create mode 100644 examples/control_optimization_qubit.jl create mode 100644 examples/measurement_optimization_LC_NV.jl create mode 100644 examples/measurement_optimization_LC_qubit.jl create mode 100644 examples/measurement_optimization_projection_NV.jl create mode 100644 examples/measurement_optimization_projection_qubit.jl create mode 100644 examples/measurement_optimization_rotation_NV.jl create mode 100644 examples/measurement_optimization_rotation_qubit.jl create mode 100644 examples/state_optimization_LMG1.jl create mode 100644 examples/state_optimization_LMG2.jl create mode 100644 src/Algorithm/AD.jl create mode 100644 src/Algorithm/Algorithm.jl create mode 100644 src/Algorithm/DDPG.jl create mode 100644 src/Algorithm/DE.jl create mode 100644 src/Algorithm/GRAPE.jl create mode 100644 src/Algorithm/Iterative.jl create mode 100644 src/Algorithm/NM.jl create mode 100644 src/Algorithm/PSO.jl rename src/{common/adaptive.jl => Common/AdaptiveScheme.jl} (73%) create mode 100644 src/Common/BayesEstimation.jl create mode 100644 src/Common/Common.jl create mode 100644 src/Common/mintime.jl rename src/{objective => ObjectiveFunc}/AsymptoticBound/AsymptoticBound.jl (86%) rename src/{objective => ObjectiveFunc}/AsymptoticBound/AsymptoticBoundWrapper.jl (96%) rename src/{objective => ObjectiveFunc}/AsymptoticBound/CramerRao.jl (56%) rename src/{objective => ObjectiveFunc}/AsymptoticBound/Holevo.jl (77%) rename src/{objective => ObjectiveFunc}/BayesianBound/BayesianBound.jl (100%) create mode 100644 src/ObjectiveFunc/BayesianBound/BayesianCramerRao.jl rename src/{objective => ObjectiveFunc}/BayesianBound/ZivZakai.jl (81%) rename src/{objective/objective.jl => ObjectiveFunc/ObjectiveFunc.jl} (100%) create mode 100644 src/OptScenario/OptScenario.jl rename src/{dynamics/kraus => Parameterization/Kraus}/Kraus.jl (100%) create mode 100644 src/Parameterization/Kraus/KrausData.jl rename src/{dynamics/kraus => Parameterization/Kraus}/KrausDynamics.jl (69%) create mode 100644 src/Parameterization/Kraus/KrausWrapper.jl rename src/{dynamics/lindblad => Parameterization/Lindblad}/Lindblad.jl (100%) rename src/{dynamics/lindblad => Parameterization/Lindblad}/LindbladData.jl (99%) rename src/{dynamics/lindblad => Parameterization/Lindblad}/LindbladDynamics.jl (90%) rename src/{dynamics/lindblad => Parameterization/Lindblad}/LindbladWrapper.jl (77%) rename src/{dynamics/dynamics.jl => Parameterization/Parameterization.jl} (93%) rename src/{resources/resources.jl => Resource/Resource.jl} (72%) delete mode 100644 src/dynamics/kraus/KrausData.jl delete mode 100644 src/dynamics/kraus/KrausWrapper.jl create mode 100644 src/io.jl delete mode 100644 src/objective/BayesianBound/BayesianCramerRao.jl delete mode 100644 src/optim/optim.jl diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 92d9e90..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Hauiming Yu and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Project.toml b/Project.toml index 1157fef..7aab659 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "QuanEstimation" uuid = "088c8dff-a786-4a66-974c-03d3f6773f87" -authors = ["Hauiming Yu and contributors"] +authors = ["Jing Liu ", "Hauiming Yu ", "Mao Zhang "] version = "0.1.0" [deps] @@ -24,7 +24,7 @@ Trapz = "592b5752-818d-11e9-1e9a-2b8ca4a44cd1" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] -julia = "1.6.2" +julia = "1.7.2" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/README.md b/README.md index 6af71d0..bcf72c6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,22 @@ -# QuanEstimation +# QuanEstimation.jl + [![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://HuaimingYuuu.github.io/QuanEstimation.jl/stable) [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://HuaimingYuuu.github.io/QuanEstimation.jl/dev) [![Build Status](https://github.com/HuaimingYuuu/QuanEstimation.jl/workflows/CI/badge.svg)](https://github.com/HuaimingYuuu/QuanEstimation.jl/actions) [![Coverage](https://codecov.io/gh/HuaimingYuuu/QuanEstimation.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/HuaimingYuuu/QuanEstimation.jl) + +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, the optimization of the probe state, control and measurement in quantum metrology. Futhermore, QuanEstimation can also perform comprehensive optimization with respect to the probe state, control and measurement to generate not only optimal quantum parameter estimation schemes, but also adaptive measurement schemes. + +This package is a fully Julia implementation of [QuanEstimation](https://github.com/QuanEstimation/QuanEstimation). + +## Installation + +Run the command in the terminal to install QuanEstimation: + +~~~ +pkg> add QuanEstimation +~~~ + +## License +Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. \ No newline at end of file diff --git a/examples/Bayesian_CramerRao_bounds.jl b/examples/Bayesian_CramerRao_bounds.jl new file mode 100644 index 0000000..7e2c211 --- /dev/null +++ b/examples/Bayesian_CramerRao_bounds.jl @@ -0,0 +1,58 @@ +using QuanEstimation +using Trapz + +# free Hamiltonian +function H0_func(x) + return 0.5*B*omega0*(sx*cos(x)+sz*sin(x)) +end +# derivative of the free Hamiltonian on x +function dH_func(x) + return [0.5*B*omega0*(-sx*sin(x)+sz*cos(x))] +end +# prior distribution +function p_func(x, mu, eta) + return exp(-(x-mu)^2/(2*eta^2))/(eta*sqrt(2*pi)) +end +function dp_func(x, mu, eta) + return -(x-mu)*exp(-(x-mu)^2/(2*eta^2))/(eta^3*sqrt(2*pi)) +end + +B, omega0 = 0.5*pi, 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +# initial state +rho0 = 0.5*ones(2, 2) +# prior distribution +x = range(-0.5*pi, stop=0.5*pi, length=100) |>Vector +mu, eta = 0.0, 0.2 +p_tp = [p_func(x[i], mu, eta) for i in 1:length(x)] +dp_tp = [dp_func(x[i], mu, eta) for i in 1:length(x)] +# normalization of the distribution +c = trapz(x, p_tp) +p = p_tp/c +dp = dp_tp/c +# time length for the evolution +tspan = range(0., stop=1., length=1000) +# dynamics +rho = Vector{Matrix{ComplexF64}}(undef, length(x)) +drho = Vector{Vector{Matrix{ComplexF64}}}(undef, length(x)) +for i = 1:length(x) + H0_tp = H0_func(x[i]) + dH_tp = dH_func(x[i]) + rho_tp, drho_tp = QuanEstimation.expm(tspan, rho0, H0_tp, dH_tp) + rho[i], drho[i] = rho_tp[end], drho_tp[end] +end + +# Classical Bayesian bounds +f_BCRB1 = QuanEstimation.BCRB([x], p, [], rho, drho, btype=1) +f_BCRB2 = QuanEstimation.BCRB([x], p, [], rho, drho, btype=2) +f_BCRB3 = QuanEstimation.BCRB([x], p, dp, rho, drho, btype=3) +f_VTB = QuanEstimation.VTB([x], p, dp, rho, drho) + +# Quantum Bayesian bounds +f_BQCRB1 = QuanEstimation.BQCRB([x], p, [], rho, drho, btype=1) +f_BQCRB2 = QuanEstimation.BQCRB([x], p, [], rho, drho, btype=2) +f_BQCRB3 = QuanEstimation.BQCRB([x], p, dp, rho, drho, btype=3) +f_QVTB = QuanEstimation.QVTB([x], p, dp, rho, drho) +f_QZZB = QuanEstimation.QZZB([x], p, rho) diff --git a/examples/Bayesian_estimation.jl b/examples/Bayesian_estimation.jl new file mode 100644 index 0000000..08d3c21 --- /dev/null +++ b/examples/Bayesian_estimation.jl @@ -0,0 +1,51 @@ +using QuanEstimation +using Random +using StatsBase + +# free Hamiltonian +function H0_func(x) + return 0.5*B*omega0*(sx*cos(x)+sz*sin(x)) +end +# derivative of the free Hamiltonian on x +function dH_func(x) + return [0.5*B*omega0*(-sx*sin(x)+sz*cos(x))] +end + +B, omega0 = pi/2.0, 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +# initial state +rho0 = 0.5*ones(2, 2) +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# prior distribution +x = range(0., stop=0.5*pi, length=100) |>Vector +p = (1.0/(x[end]-x[1]))*ones(length(x)) +# time length for the evolution +tspan = range(0., stop=1., length=1000) +# dynamics +rho = Vector{Matrix{ComplexF64}}(undef, length(x)) +for i = 1:length(x) + H0_tp = H0_func(x[i]) + dH_tp = dH_func(x[i]) + rho_tp, drho_tp = QuanEstimation.expm(tspan, rho0, H0_tp, dH_tp) + rho[i] = rho_tp[end] +end + +# Generation of the experimental results +Random.seed!(1234) +y = [0 for i in 1:500] +res_rand = sample(1:length(y), 125, replace=false) +for i in 1:length(res_rand) + y[res_rand[i]] = 1 +end + +#===============Maximum a posteriori estimation===============# +pout, xout = QuanEstimation.Bayes([x], p, rho, y; M=M, estimator="MAP", + savefile=false) + +#===============Maximum likelihood estimation===============# +Lout, xout = QuanEstimation.MLE([x], rho, y, M=M; savefile=false) diff --git a/examples/CMopt_NV.jl b/examples/CMopt_NV.jl new file mode 100644 index 0000000..98f26fb --- /dev/null +++ b/examples/CMopt_NV.jl @@ -0,0 +1,63 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# control and measurement optimization +opt = QuanEstimation.CMopt(ctrl_bound=[-0.2,0.2], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, + decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, +# decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/CMopt_qubit.jl b/examples/CMopt_qubit.jl new file mode 100644 index 0000000..1776824 --- /dev/null +++ b/examples/CMopt_qubit.jl @@ -0,0 +1,48 @@ +using QuanEstimation + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# control Hamiltonians +Hc = [sx, sy, sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.0], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 10., length=2500) +# control and measurement optimization +opt = QuanEstimation.CMopt(ctrl_bound=[-2.0,2.0], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, + decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, +# decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/CramerRao_bounds.jl b/examples/CramerRao_bounds.jl new file mode 100644 index 0000000..4aac298 --- /dev/null +++ b/examples/CramerRao_bounds.jl @@ -0,0 +1,34 @@ +using QuanEstimation + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.0], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 50., length=2000) +# dynamics +rho, drho = QuanEstimation.expm(tspan, rho0, H0, dH, decay) +# calculation of the CFI and QFI +Im, F = Float64[], Float64[] +for ti in 2:length(tspan) + # CFI + I_tp = QuanEstimation.CFIM(rho[ti], drho[ti], M) + append!(Im, I_tp) + # QFI + F_tp = QuanEstimation.QFIM(rho[ti], drho[ti]) + append!(F, F_tp) +end diff --git a/examples/Holevo_CramerRao_bound.jl b/examples/Holevo_CramerRao_bound.jl new file mode 100644 index 0000000..759f29d --- /dev/null +++ b/examples/Holevo_CramerRao_bound.jl @@ -0,0 +1,40 @@ +using QuanEstimation +using LinearAlgebra + +# initial state +psi0 = [1., 0., 0., 1.]/sqrt(2) +rho0 = psi0*psi0' +# free Hamiltonian +omega1, omega2, g = 1.0, 1.0, 0.1 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = omega1*kron(sz, I(2)) + omega2*kron(I(2), sz) + g*kron(sx, sx) +# derivatives of the free Hamiltonian with respect to omega2 and g +dH = [kron(I(2), sz), kron(sx, sx)] +# dissipation +decay = [[kron(sz, I(2)), 0.05], [kron(I(2), sz), 0.05]] +# measurement +m1 = [1., 0., 0., 0.] +M1 = 0.85*m1*m1' +M2 = 0.1*ones(4, 4) +M = [M1, M2, I(4)-M1-M2] +# time length for the evolution +tspan = range(0., 10., length=1000) +# dynamics +rho, drho = QuanEstimation.expm(tspan, rho0, H0, dH, decay) +# weight matrix +W = one(zeros(2, 2)) +# calculation of the CFIM, QFIM and HCRB +Im, F, f = [], [], Float64[] +for ti in 2:length(tspan) + #CFIM + I_tp = QuanEstimation.CFIM(rho[ti], drho[ti], M) + append!(Im, [I_tp]) + #QFIM + F_tp = QuanEstimation.QFIM(rho[ti], drho[ti]) + append!(F, [F_tp]) + #HCRB + f_tp = QuanEstimation.HCRB(rho[ti], drho[ti], W) + append!(f, f_tp) +end diff --git a/examples/SCMopt_NV.jl b/examples/SCMopt_NV.jl new file mode 100644 index 0000000..8f601f5 --- /dev/null +++ b/examples/SCMopt_NV.jl @@ -0,0 +1,61 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# choose the optimization type +opt = QuanEstimation.SCMopt(ctrl_bound=[-0.2,0.2], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/SCMopt_qubit.jl b/examples/SCMopt_qubit.jl new file mode 100644 index 0000000..a3bb46f --- /dev/null +++ b/examples/SCMopt_qubit.jl @@ -0,0 +1,46 @@ +using QuanEstimation + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# control Hamiltonians +Hc = [sx, sy, sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.0], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 10., length=2500) +# choose the optimization type +opt = QuanEstimation.SCMopt(ctrl_bound=[-2.0,2.0], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/SCopt_NV.jl b/examples/SCopt_NV.jl new file mode 100644 index 0000000..1261d78 --- /dev/null +++ b/examples/SCopt_NV.jl @@ -0,0 +1,70 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# choose the optimization type +opt = QuanEstimation.SCopt(ctrl_bound=[-0.2,0.2], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=true, max_episode=1000, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##===================choose objective function===================## +##-------------objective function: tr(WF^{-1})---------------------## +obj = QuanEstimation.QFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: tr(WI^{-1})---------------------## +# obj = QuanEstimation.CFIM_obj(M=M) +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/SCopt_qubit.jl b/examples/SCopt_qubit.jl new file mode 100644 index 0000000..d244653 --- /dev/null +++ b/examples/SCopt_qubit.jl @@ -0,0 +1,55 @@ +using QuanEstimation + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# control Hamiltonians +Hc = [sx, sy, sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.0], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 10., length=2500) +# choose the optimization type +opt = QuanEstimation.SCopt(ctrl_bound=[-2.0,2.0], seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=true, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, Hc, decay=decay) + +##===================choose objective function===================## +##-------------objective function: QFI---------------------## +obj = QuanEstimation.QFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: CFI---------------------## +# obj = QuanEstimation.CFIM_obj(M=M) +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/SMopt_NV.jl b/examples/SMopt_NV.jl new file mode 100644 index 0000000..7d0c76f --- /dev/null +++ b/examples/SMopt_NV.jl @@ -0,0 +1,61 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# choose the optimization type +opt = QuanEstimation.SMopt(seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=100, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj(M=M) +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[100,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj(M=M) +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/SMopt_qubit.jl b/examples/SMopt_qubit.jl new file mode 100644 index 0000000..3862be6 --- /dev/null +++ b/examples/SMopt_qubit.jl @@ -0,0 +1,46 @@ +using QuanEstimation + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# control Hamiltonians +Hc = [sx, sy, sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.0], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 10., length=2500) +# choose the optimization type +opt = QuanEstimation.SMopt(seed=1234) + +##==========choose comprehensive optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the comprehensive optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the comprehensive optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/adaptMZI.jl b/examples/adaptMZI.jl new file mode 100644 index 0000000..3f972a8 --- /dev/null +++ b/examples/adaptMZI.jl @@ -0,0 +1,29 @@ +using QuanEstimation +using SparseArrays + +# the number of photons +N = 8 +# probe state +psi = sum([sin(k*pi/(N+2))*kron(QuanEstimation.basis(N+1,k), + QuanEstimation.basis(N+1, N-k+2)) for k in 1:(N+1)]) |> sparse +psi = psi*sqrt(2/(2+N)) +rho0 = psi*psi' +# prior distribution +x = range(-pi, pi, length=100) +p = (1.0/(x[end]-x[1]))*ones(length(x)) +apt = QuanEstimation.Adapt_MZI(x, p, rho0) + +#================online strategy=========================# +QuanEstimation.online(apt, output="phi") + +#================offline strategy=========================# +# # algorithm: DE +# alg = QuanEstimation.DE(p_num=10, ini_population=missing, +# max_episode=1000, c=1.0, cr=0.5) +# QuanEstimation.offline(apt, alg, seed=1234) + +# # algorithm: PSO +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) +# QuanEstimation.offline(apt, alg, seed=1234) \ No newline at end of file diff --git a/examples/adaptive.jl b/examples/adaptive.jl new file mode 100644 index 0000000..cede4be --- /dev/null +++ b/examples/adaptive.jl @@ -0,0 +1,50 @@ +using QuanEstimation +using Random +using StatsBase + +# free Hamiltonian +function H0_func(x) + return 0.5*B*omega0*(sx*cos(x[1])+sz*sin(x[1])) +end +# derivative of free Hamiltonian in x +function dH_func(x) + return [0.5*B*omega0*(-sx*sin(x[1])+sz*cos(x[1]))] +end + +B, omega0 = pi/2.0, 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +# initial state +rho0 = 0.5*ones(2, 2) +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., stop=1., length=1000) |>Vector +# prior distribution +x = range(-0.25*pi+0.1, stop=3.0*pi/4.0-0.1, length=100) |>Vector +p = (1.0/(x[end]-x[1]))*ones(length(x)) +# dynamics +rho = Vector{Matrix{ComplexF64}}(undef, length(x)) +for i = 1:length(x) + H0_tp = H0_func(x[i]) + dH_tp = dH_func(x[i]) + rho_tp, drho_tp = QuanEstimation.expm(tspan, rho0, H0_tp, dH_tp) + rho[i] = rho_tp[end] +end +# Bayesian estimation +Random.seed!(1234) +y = [0 for i in 1:500] +res_rand = sample(1:length(y), 125, replace=false) +for i in 1:length(res_rand) + y[res_rand[i]] = 1 +end +pout, xout = QuanEstimation.Bayes([x], p, rho, y, M=M, savefile=false) +# generation of H and dH +H, dH = QuanEstimation.BayesInput([x], H0_func, dH_func; + channel="dynamics") +# adaptive measurement +QuanEstimation.Adaptive([x], pout, rho0, tspan, H, dH; M=M, + max_episode=100) diff --git a/examples/control_optimization_NV.jl b/examples/control_optimization_NV.jl new file mode 100644 index 0000000..f566799 --- /dev/null +++ b/examples/control_optimization_NV.jl @@ -0,0 +1,97 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +dim = size(rho0, 1) +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2*pi/cons]] +# measurement +M = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# guessed control coefficients +cnum = 10 +rng = MersenneTwister(1234) +ini_1 = [zeros(cnum) for _ in 1:length(Hc)] +ini_2 = 0.2.*[ones(cnum) for _ in 1:length(Hc)] +ini_3 = -0.2.*[ones(cnum) for _ in 1:length(Hc)] +ini_4 = [[range(-0.2, 0.2, length=cnum)...] for _ in 1:length(Hc)] +ini_5 = [[range(-0.2, 0., length=cnum)...] for _ in 1:length(Hc)] +ini_6 = [[range(0., 0.2, length=cnum)...] for _ in 1:length(Hc)] +ini_7 = [-0.2*ones(cnum)+0.01*rand(rng,cnum) for _ in 1:length(Hc)] +ini_8 = [-0.2*ones(cnum)+0.01*rand(rng,cnum) for _ in 1:length(Hc)] +ini_9 = [-0.2*ones(cnum)+0.05*rand(rng,cnum) for _ in 1:length(Hc)] +ini_10 = [-0.2*ones(cnum)+0.05*rand(rng,cnum) for _ in 1:length(Hc)] +ctrl0 = [Symbol("ini_", i)|>eval for i in 1:10] +# choose the optimization type +opt = QuanEstimation.ControlOpt(ctrl=ini_1, ctrl_bound=[-0.2, 0.2], seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: auto-GRAPE---------------------## +alg = QuanEstimation.autoGRAPE(Adam=true, max_episode=10, epsilon=0.01, + beta1=0.90, beta2=0.99) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=(ctrl0,), +# max_episode=[10,10], c0=1.0, +# c1=2.0, c2=2.0) + +##-------------algorithm: DE---------------------## +# alg = QuanEstimation.DE(p_num=10, ini_population=(ctrl0,), +# max_episode=1000, c=1.0, cr=0.5) + +##-------------algorithm: DDPG---------------------## +# alg = QuanEstimation.DDPG(max_episode=50, layer_num=4, layer_dim=220) + +##===================choose objective function===================## +##-------------objective function: QFI---------------------## +# # objective function: tr(WF^{-1}) +# obj = QuanEstimation.QFIM_obj() +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, decay) +# # run the control optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: CFI---------------------## +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj(M=M) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, decay) +# run the control optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: HCRB---------------------## +# # objective function: HCRB +# obj = QuanEstimation.HCRB_obj() +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, decay) +# # run the control optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/control_optimization_qubit.jl b/examples/control_optimization_qubit.jl new file mode 100644 index 0000000..a03eb6a --- /dev/null +++ b/examples/control_optimization_qubit.jl @@ -0,0 +1,72 @@ +using QuanEstimation +using Random + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# control Hamiltonians +Hc = [sx, sy, sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.], [sm, 0.1]] +# measurement +M1 = 0.5*[1.0+0.0im 1.; 1. 1.] +M2 = 0.5*[1.0+0.0im -1.; -1. 1.] +M = [M1, M2] +# time length for the evolution +tspan = range(0., 10., length=2500) +# guessed control coefficients +cnum = length(tspan)-1 +ctrl = [zeros(cnum) for _ in 1:length(Hc)] +ctrl_bound = [-2., 2.] +# choose the optimization type +opt = QuanEstimation.ControlOpt(ctrl=ctrl, ctrl_bound=ctrl_bound, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: auto-GRAPE---------------------## +alg = QuanEstimation.autoGRAPE(Adam=true, max_episode=300, epsilon=0.01, + beta1=0.90, beta2=0.99) + +##-------------algorithm: GRAPE---------------------## +# alg = QuanEstimation.GRAPE(Adam=true, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=([ctrl],), +# max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) + +##-------------algorithm: DE---------------------## +# alg = QuanEstimation.DE(p_num=10, ini_population=([ctrl],), +# max_episode=1000, c=1.0, cr=0.5) + +##-------------algorithm: DDPG---------------------## +# alg = QuanEstimation.DDPG(max_episode=500, layer_num=4, layer_dim=220) + +##===================choose objective function===================## +##-------------objective function: QFI---------------------## +# objective function: QFI +obj = QuanEstimation.QFIM_obj() +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, decay) +# run the control optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: CFI---------------------## +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj(M=M) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, rho0, H0, dH, Hc, decay) +# # run the control optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + + + diff --git a/examples/measurement_optimization_LC_NV.jl b/examples/measurement_optimization_LC_NV.jl new file mode 100644 index 0000000..68c7484 --- /dev/null +++ b/examples/measurement_optimization_LC_NV.jl @@ -0,0 +1,73 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# find the optimal linear combination of an input measurement +opt = QuanEstimation.MeasurementOpt(mtype=:LC, POVM_basis=POVM_basis, M_num=4, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/measurement_optimization_LC_qubit.jl b/examples/measurement_optimization_LC_qubit.jl new file mode 100644 index 0000000..69868b5 --- /dev/null +++ b/examples/measurement_optimization_LC_qubit.jl @@ -0,0 +1,58 @@ +using QuanEstimation +using Random +using StableRNGs +using LinearAlgebra + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.], [sm, 0.1]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = QuanEstimation.SIC(dim) +# time length for the evolution +tspan = range(0., 10., length=2500) +# find the optimal linear combination of an input measurement +opt = QuanEstimation.MeasurementOpt(mtype=:LC, POVM_basis=POVM_basis, M_num=2, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/measurement_optimization_projection_NV.jl b/examples/measurement_optimization_projection_NV.jl new file mode 100644 index 0000000..4cdcd4e --- /dev/null +++ b/examples/measurement_optimization_projection_NV.jl @@ -0,0 +1,63 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# projective measurement optimization +opt = QuanEstimation.MeasurementOpt(mtype=:Projection, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/measurement_optimization_projection_qubit.jl b/examples/measurement_optimization_projection_qubit.jl new file mode 100644 index 0000000..fe4fa0d --- /dev/null +++ b/examples/measurement_optimization_projection_qubit.jl @@ -0,0 +1,48 @@ +using QuanEstimation +using Random +using StableRNGs +using LinearAlgebra + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.], [sm, 0.1]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = QuanEstimation.SIC(dim) +# time length for the evolution +tspan = range(0., 10., length=2500) +# projective measurement optimization +opt = QuanEstimation.MeasurementOpt(mtype=:Projection, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/measurement_optimization_rotation_NV.jl b/examples/measurement_optimization_rotation_NV.jl new file mode 100644 index 0000000..24f1346 --- /dev/null +++ b/examples/measurement_optimization_rotation_NV.jl @@ -0,0 +1,73 @@ +using QuanEstimation +using Random +using LinearAlgebra + +# initial state +rho0 = zeros(ComplexF64, 6, 6) +rho0[1:4:5, 1:4:5] .= 0.5 +# Hamiltonian +sx = [0. 1.; 1. 0.] +sy = [0. -im; im 0.] +sz = [1. 0.; 0. -1.] +s1 = [0. 1. 0.; 1. 0. 1.; 0. 1. 0.]/sqrt(2) +s2 = [0. -im 0.; im 0. -im; 0. im 0.]/sqrt(2) +s3 = [1. 0. 0.; 0. 0. 0.; 0. 0. -1.] +Is = I1, I2, I3 = [kron(I(3), sx), kron(I(3), sy), kron(I(3), sz)] +S = S1, S2, S3 = [kron(s1, I(2)), kron(s2, I(2)), kron(s3, I(2))] +B = B1, B2, B3 = [5.0e-4, 5.0e-4, 5.0e-4] +# All numbers are divided by 100 in this example +# for better calculation accurancy +cons = 100 +D = (2pi*2.87*1000)/cons +gS = (2pi*28.03*1000)/cons +gI = (2pi*4.32)/cons +A1 = (2pi*3.65)/cons +A2 = (2pi*3.03)/cons +H0 = sum([D*kron(s3^2, I(2)), sum(gS*B.*S), sum(gI*B.*Is), + A1*(kron(s1, sx) + kron(s2, sy)), A2*kron(s3, sz)]) +# derivatives of the free Hamiltonian on B1, B2 and B3 +dH = gS*S+gI*Is +# control Hamiltonians +Hc = [S1, S2, S3] +# dissipation +decay = [[S3, 2pi/cons]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = [QuanEstimation.basis(dim, i)*QuanEstimation.basis(dim, i)' + for i in 1:dim] +# time length for the evolution +tspan = range(0., 2., length=4000) +# find the optimal rotated measurement of an input measurement +opt = QuanEstimation.MeasurementOpt(mtype=:Rotation, POVM_basis=POVM_basis, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: tr(WI^{-1}) +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/measurement_optimization_rotation_qubit.jl b/examples/measurement_optimization_rotation_qubit.jl new file mode 100644 index 0000000..c36c5b9 --- /dev/null +++ b/examples/measurement_optimization_rotation_qubit.jl @@ -0,0 +1,58 @@ +using QuanEstimation +using Random +using StableRNGs +using LinearAlgebra + +# initial state +rho0 = 0.5*ones(2, 2) +# free Hamiltonian +omega = 1.0 +sx = [0. 1.; 1. 0.0im] +sy = [0. -im; im 0.] +sz = [1. 0.0im; 0. -1.] +H0 = 0.5*omega*sz +# derivative of the free Hamiltonian on omega +dH = [0.5*sz] +# dissipation +sp = [0. 1.; 0. 0.0im] +sm = [0. 0.; 1. 0.0im] +decay = [[sp, 0.], [sm, 0.1]] +# generation of a set of POVM basis +dim = size(rho0, 1) +POVM_basis = QuanEstimation.SIC(dim) +# time length for the evolution +tspan = range(0., 10., length=2500) +# find the optimal rotated measurement of an input measurement +opt = QuanEstimation.MeasurementOpt(mtype=:Rotation, POVM_basis=POVM_basis, seed=1234) + +##==========choose measurement optimization algorithm==========## +##-------------algorithm: DE---------------------## +alg = QuanEstimation.DE(p_num=10, ini_population=missing, + max_episode=1000, c=1.0, cr=0.5) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# objective function: CFI +obj = QuanEstimation.CFIM_obj() +# run the measurement optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: PSO---------------------## +# alg = QuanEstimation.PSO(p_num=10, ini_particle=missing, +# max_episode=[1000,100], c0=1.0, c1=2.0, +# c2=2.0) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------algorithm: AD---------------------## +# alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, +# beta1=0.90, beta2=0.99) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan ,rho0, H0, dH, decay=decay) +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # run the measurement optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/examples/state_optimization_LMG1.jl b/examples/state_optimization_LMG1.jl new file mode 100644 index 0000000..6b14b9c --- /dev/null +++ b/examples/state_optimization_LMG1.jl @@ -0,0 +1,67 @@ +using QuanEstimation +using Random +using StableRNGs +using LinearAlgebra +using SparseArrays + +# dimensions of the system +N = 8 +# generation of the coherent spin state +j, theta, phi = N÷2, 0.5pi, 0.5pi +Jp = Matrix(spdiagm(1=>[sqrt(j*(j+1)-m*(m+1)) for m in j:-1:-j][2:end])) +Jm = Jp' +psi0 = exp(0.5*theta*exp(im*phi)*Jm - 0.5*theta*exp(-im*phi)*Jp)* + QuanEstimation.basis(Int(2*j+1), 1) +dim = length(psi0) +# free Hamiltonian +lambda, g, h = 1.0, 0.5, 0.1 +Jx = 0.5*(Jp + Jm) +Jy = -0.5im*(Jp - Jm) +Jz = spdiagm(j:-1:-j) +H0 = -lambda*(Jx*Jx + g*Jy*Jy) / N - h*Jz +# derivative of the free Hamiltonian on g +dH = [-lambda*Jy*Jy/N] +# dissipation +decay = [[Jz, 0.1]] +# time length for the evolution +tspan = range(0., 10., length=2500) +# set the optimization type +opt = QuanEstimation.StateOpt(psi=psi0, seed=1234) + +##================choose the state optimization algorithm===============## +# state optimization algorithm: AD +alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, + beta1=0.90, beta2=0.99) + +# # state optimization algorithm: PSO +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) + +# # state optimization algorithm: DE +# alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) + +# # state optimization algorithm: NM +# alg = QuanEstimation.NM(p_num=10, max_episode=1000, ar=1.0, +# ae=2.0, ac=0.5, as0=0.5) + +# # state optimization algorithm: DDPG +# alg = QuanEstimation.DDPG(max_episode=500, layer_num=3, layer_dim=200) + + +##====================choose the objective function==================## +##-------------objective function: QFI---------------------## +# objective function: QFI +obj = QuanEstimation.QFIM_obj() +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# run the state optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: CFI---------------------## +# # objective function: CFI +# obj = QuanEstimation.CFIM_obj() +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# # run the state optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + diff --git a/examples/state_optimization_LMG2.jl b/examples/state_optimization_LMG2.jl new file mode 100644 index 0000000..0f6886c --- /dev/null +++ b/examples/state_optimization_LMG2.jl @@ -0,0 +1,75 @@ +using QuanEstimation +using Random +using StableRNGs +using LinearAlgebra +using SparseArrays + +# dimensions of the system +N = 8 +# generation of the coherent spin state +j, theta, phi = N÷2, 0.5pi, 0.5pi +Jp = Matrix(spdiagm(1=>[sqrt(j*(j+1)-m*(m+1)) for m in j:-1:-j][2:end])) +Jm = Jp' +psi0 = exp(0.5*theta*exp(im*phi)*Jm - 0.5*theta*exp(-im*phi)*Jp)* + QuanEstimation.basis(Int(2*j+1), 1) +dim = length(psi0) +# free Hamiltonian +lambda, g, h = 1.0, 0.5, 0.1 +Jx = 0.5*(Jp + Jm) +Jy = -0.5im*(Jp - Jm) +Jz = spdiagm(j:-1:-j) +H0 = -lambda*(Jx*Jx + g*Jy*Jy) / N + g * Jy^2 / N - h*Jz +# derivative of the free Hamiltonian on g +dH = [-lambda*Jy*Jy/N, -Jz] +# dissipation +decay = [[Jz, 0.1]] +# time length for the evolution +tspan = range(0., 10., length=2500) +# weight matrix +W = [1/3 0.; 0. 2/3] +# set the optimization type +opt = QuanEstimation.StateOpt(psi=psi0, seed=1234) + +##====================choose the state optimization algorithm====================## +# state optimization algorithm: AD +alg = QuanEstimation.AD(Adam=false, max_episode=300, epsilon=0.01, + beta1=0.90, beta2=0.99) + +# # state optimization algorithm: PSO +# alg = QuanEstimation.PSO(p_num=10, max_episode=[1000,100], c0=1.0, +# c1=2.0, c2=2.0) + +# # state optimization algorithm: DE +# alg = QuanEstimation.DE(p_num=10, max_episode=1000, c=1.0, cr=0.5) + +# # state optimization algorithm: NM +# alg = QuanEstimation.NM(p_num=10, max_episode=1000, ar=1.0, +# ae=2.0, ac=0.5, as0=0.5) + +# # state optimization algorithm: DDPG +# alg = QuanEstimation.DDPG(max_episode=500, layer_num=3, layer_dim=200) + +##====================choose the objective function====================## +##-------------objective function: QFI---------------------## +# objective function: tr(WF^{-1}) +obj = QuanEstimation.QFIM_obj(W=W) +# input the dynamics data +dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# run the state optimization problem +QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: CFI---------------------## +# # objective function: tr(WI^{-1}) +# obj = QuanEstimation.CFIM_obj(W=W) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# # run the state optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) + +##-------------objective function: HCRB---------------------## +# # objective function: HCRB +# obj = QuanEstimation.HCRB_obj(W=W) +# # input the dynamics data +# dynamics = QuanEstimation.Lindblad(opt, tspan, H0, dH, decay=decay) +# # run the state optimization problem +# QuanEstimation.run(opt, alg, obj, dynamics; savefile=false) diff --git a/src/Algorithm/AD.jl b/src/Algorithm/AD.jl new file mode 100644 index 0000000..d825d73 --- /dev/null +++ b/src/Algorithm/AD.jl @@ -0,0 +1,227 @@ +#### control optimization #### +function update!(opt::ControlOpt, alg::AbstractautoGRAPE, obj, dynamics, output) + (; max_episode) = alg + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + + for ei = 1:(max_episode-1) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ctrl])) + update_ctrl!(alg, obj, dynamics, δ[dynamics.data.ctrl]) + bound!(dynamics.data.ctrl, opt.ctrl_bound) + f_out, f_now = objective(obj, dynamics) + + set_f!(output, f_out) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update_ctrl!(alg::autoGRAPE_Adam, obj, dynamics, δ) + (; epsilon, beta1, beta2) = alg + for ci in 1:length(δ) + mt, vt = 0.0, 0.0 + for ti in 1:length(δ[1]) + dynamics.data.ctrl[ci][ti], mt, vt = Adam(δ[ci][ti], ti, + dynamics.data.ctrl[ci][ti], mt, vt, epsilon, beta1, beta2, obj.eps) + end + end +end + +function update_ctrl!(alg::autoGRAPE, obj, dynamics, δ) + dynamics.data.ctrl += alg.epsilon*δ +end + +#### state optimization #### +function update!(opt::StateOpt, alg::AbstractAD, obj, dynamics, output) + (; max_episode) = alg + f_ini, f_comp = objective(obj, dynamics) + set_f!(output, f_ini) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f_ini) + show(opt, output, obj) + for ei in 1:(max_episode-1) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0])) + update_state!(alg, obj, dynamics, δ[dynamics.data.ψ0]) + dynamics.data.ψ0 = dynamics.data.ψ0/norm(dynamics.data.ψ0) + f_out, f_now = objective(obj, dynamics) + set_f!(output, f_out) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update_state!(alg::AD_Adam, obj, dynamics, δ) + (; epsilon, beta1, beta2) = alg + mt, vt = 0.0, 0.0 + for ti in 1:length(δ) + dynamics.data.ψ0[ti], mt, vt = Adam(δ[ti], ti, dynamics.data.ψ0[ti], mt, vt, epsilon, beta1, beta2, obj.eps) + end +end + +function update_state!(alg::AD, obj, dynamics, δ) + dynamics.data.ψ0 += alg.epsilon*δ +end + +#### find the optimal linear combination of a given set of POVM #### +function update!(opt::Mopt_LinearComb, alg::AbstractAD, obj, dynamics, output) + (; max_episode) = alg + (; POVM_basis, M_num) = opt + rng = MersenneTwister(1234) + basis_num = length(POVM_basis) + + bound_LC_coeff!(opt.B, rng) + M = [sum([opt.B[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + set_f!(output, f_ini) + set_buffer!(output, M) + set_io!(output, f_ini, f_povm, f_opt) + show(opt, output, obj) + for ei in 1:(max_episode-1) + δ = Flux.gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.B])) + update_M!(opt, alg, obj, δ[opt.B]) + bound_LC_coeff!(opt.B, rng) + M = [sum([opt.B[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, dynamics) + set_f!(output, f_out) + set_buffer!(output, M) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update_M!(opt::Mopt_LinearComb, alg::AD_Adam, obj, δ) + (; epsilon, beta1, beta2) = alg + for ci in 1:length(δ) + mt, vt = 0.0, 0.0 + for ti in 1:length(δ[1]) + opt.B[ci][ti], mt, vt = Adam(δ[ci][ti], ti, opt.B[ci][ti], mt, vt, epsilon, beta1, beta2, obj.eps) + end + end +end + +function update_M!(opt::Mopt_LinearComb, alg::AD, obj, δ) + opt.B += alg.epsilon*δ +end + +#### find the optimal rotated measurement of a given set of POVM #### +function update!(opt::Mopt_Rotation, alg::AbstractAD, obj, dynamics, output) + (; max_episode) = alg + (; POVM_basis) = opt + dim = size(dynamics.data.ρ0)[1] + M_num = length(POVM_basis) + suN = suN_generator(dim) + opt.Lambda = Matrix{ComplexF64}[] + append!(opt.Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + append!(opt.Lambda, [suN[i] for i in 1:length(suN)]) + + # if ismissing(Lambda) + # opt.Lambda = Matrix{ComplexF64}[] + # append!(opt.Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + # append!(opt.Lambda, [suN[i] for i in 1:length(suN)]) + # end + + U = rotation_matrix(opt.s, opt.Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + set_f!(output, f_ini) + set_buffer!(output, M) + set_io!(output, f_ini, f_povm, f_opt) + show(opt, output, obj) + for ei in 1:(max_episode-1) + δ = Flux.gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.s])) + update_M!(opt, alg, obj, δ[opt.s]) + bound_rot_coeff!(opt.s) + U = rotation_matrix(opt.s, opt.Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, dynamics) + set_f!(output, f_out) + set_buffer!(output, M) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update_M!(opt::Mopt_Rotation, alg::AD_Adam, obj, δ) + (; epsilon, beta1, beta2) = alg + mt, vt = 0.0, 0.0 + for ti in 1:length(δ) + opt.s[ti], mt, vt = Adam(δ[ti], ti, opt.s[ti], mt, vt, epsilon, beta1, beta2, obj.eps) + end +end + +function update_M!(opt::Mopt_Rotation, alg::AD, obj, δ) + opt.s += alg.epsilon*δ +end + +#### state abd control optimization #### +function update!(opt::StateControlOpt, alg::AbstractAD, obj, dynamics, output) + (; max_episode) = alg + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, transpose(dynamics.data.ψ0), dynamics.data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + + for ei = 1:(max_episode-1) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0, dynamics.data.ctrl])) + update_state!(alg, obj, dynamics, δ[dynamics.data.ψ0]) + update_ctrl!(alg, obj, dynamics, δ[dynamics.data.ctrl]) + bound!(dynamics.data.ctrl, opt.ctrl_bound) + dynamics.data.ψ0 = dynamics.data.ψ0/norm(dynamics.data.ψ0) + f_out, f_now = objective(obj, dynamics) + + set_f!(output, f_out) + set_buffer!(output, transpose(dynamics.data.ψ0), dynamics.data.ctrl) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update_ctrl!(alg::AD_Adam, obj, dynamics, δ) + (; epsilon, beta1, beta2) = alg + for ci in 1:length(δ) + mt, vt = 0.0, 0.0 + for ti in 1:length(δ[1]) + dynamics.data.ctrl[ci][ti], mt, vt = Adam(δ[ci][ti], ti, + dynamics.data.ctrl[ci][ti], mt, vt, epsilon, beta1, beta2, obj.eps) + end + end +end + +function update_ctrl!(alg::AD, obj, dynamics, δ) + dynamics.data.ctrl += alg.epsilon*δ +end diff --git a/src/Algorithm/Algorithm.jl b/src/Algorithm/Algorithm.jl new file mode 100644 index 0000000..5c66970 --- /dev/null +++ b/src/Algorithm/Algorithm.jl @@ -0,0 +1,213 @@ +abstract type AbstractAlgorithm end + +abstract type AbstractGRAPE <: AbstractAlgorithm end + +struct GRAPE <: AbstractGRAPE + max_episode::Int + epsilon::Number +end + +struct GRAPE_Adam <: AbstractGRAPE + max_episode::Int + epsilon::Number + beta1::Number + beta2::Number +end + + +GRAPE(max_episode, epsilon, beta1, beta2) = GRAPE_Adam(max_episode, epsilon, beta1, beta2) + +""" + + GRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Control optimization algorithm: GRAPE. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" +GRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? GRAPE_Adam(max_episode, epsilon, beta1, beta2) : GRAPE(max_episode, epsilon) + +abstract type AbstractautoGRAPE <: AbstractAlgorithm end +struct autoGRAPE <: AbstractautoGRAPE + max_episode::Int + epsilon::Number +end + +struct autoGRAPE_Adam <: AbstractautoGRAPE + max_episode::Int + epsilon::Number + beta1::Number + beta2::Number +end + +autoGRAPE(max_episode, epsilon, beta1, beta2) = autoGRAPE_Adam(max_episode, epsilon, beta1, beta2) + +""" + + autoGRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Control optimization algorithm: auto-GRAPE. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" +autoGRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? autoGRAPE_Adam(max_episode, epsilon, beta1, beta2) : autoGRAPE(max_episode, epsilon) + +abstract type AbstractAD <: AbstractAlgorithm end +struct AD <: AbstractAD + max_episode::Number + epsilon::Number +end + +struct AD_Adam <: AbstractAD + max_episode::Number + epsilon::Number + beta1::Number + beta2::Number +end + +AD(max_episode, epsilon, beta1, beta2) = AD_Adam(max_episode=max_episode, epsilon=epsilon, beta1=beta1, beta2=beta2) +""" + + AD(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Optimization algorithm: AD. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" +AD(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? AD_Adam(max_episode, epsilon, beta1, beta2) : AD(max_episode, epsilon) + +mutable struct PSO <: AbstractAlgorithm + max_episode::Union{T,Vector{T}} where {T<:Int} + p_num::Int + ini_particle::Union{Tuple, Missing} + c0::Number + c1::Number + c2::Number +end + +""" + + PSO(;max_episode::Union{T,Vector{T}} where {T<:Int}=[1000, 100], p_num::Number=10, ini_particle=missing, c0::Number=1.0, c1::Number=2.0, c2::Number=2.0, seed::Number=1234) + +Optimization algorithm: PSO. +- `max_episode`: The number of episodes, it accepts both integer and array with two elements. +- `p_num`: The number of particles. +- `ini_particle`: Initial guesses of the optimization variables. +- `c0`: The damping factor that assists convergence, also known as inertia weight. +- `c1`: The exploitation weight that attracts the particle to its best previous position, also known as cognitive learning factor. +- `c2`: The exploitation weight that attracts the particle to the best position in the neighborhood, also known as social learning factor. +""" +PSO(;max_episode::Union{T,Vector{T}} where {T<:Int}=[1000, 100], p_num::Number=10, ini_particle=missing, c0::Number=1.0, c1::Number=2.0, c2::Number=2.0) = + PSO(max_episode, p_num, ini_particle, c0, c1, c2) + +mutable struct DE <: AbstractAlgorithm + max_episode::Number + p_num::Number + ini_population::Union{Tuple, Missing} + c::Number + cr::Number +end + +""" + + DE(;max_episode::Number=1000, p_num::Number=10, ini_population=missing, c::Number=1.0, cr::Number=0.5, seed::Number=1234) + +Optimization algorithm: DE. +- `max_episode`: The number of populations. +- `p_num`: The number of particles. +- `ini_population`: Initial guesses of the optimization variables. +- `c`: Mutation constant. +- `cr`: Crossover constant. +""" +DE(;max_episode::Number=1000, p_num::Number=10, ini_population=missing, c::Number=1.0,cr::Number=0.5) = DE(max_episode, p_num, ini_population, c, cr) + +struct DDPG <: AbstractAlgorithm + max_episode::Int + layer_num::Int + layer_dim::Int + rng::AbstractRNG +end + +DDPG(max_episode, layer_num, layer_dim) = + DDPG(max_episode, layer_num, layer_dim, StableRNG(1234)) +DDPG(max_episode, layer_num, layer_dim, seed::Number) = + DDPG(max_episode, layer_num, layer_dim, StableRNG(seed)) +""" + + DDPG(;max_episode::Int=500, layer_num::Int=3, layer_dim::Int=200, seed::Number=1234) + +Optimization algorithm: DE. +- `max_episode`: The number of populations. +- `layer_num`: The number of layers (include the input and output layer). +- `layer_dim`: The number of neurons in the hidden layer. +- `seed`: Random seed. +""" +DDPG(;max_episode::Int=500, layer_num::Int=3, layer_dim::Int=200, seed::Number=1234) = + DDPG(max_episode, layer_num, layer_dim, StableRNG(seed)) + +struct NM <: AbstractAlgorithm + max_episode::Int + p_num::Int + ini_state::Union{AbstractVector, Missing} + ar::Number + ae::Number + ac::Number + as0::Number +end + +""" + + NM(;max_episode::Int=1000, p_num::Int=10, nelder_mead=missing, ar::Number=1.0, ae::Number=2.0, ac::Number=0.5, as0::Number=0.5, seed::Number=1234) + +State optimization algorithm: NM. +- `max_episode`: The number of populations. +- `p_num`: The number of the input states. +- `nelder_mead`: Initial guesses of the optimization variables. +- `ar`: Reflection constant. +- `ae`: Expansion constant. +- `ac`: Constraction constant. +- `as0`: Shrink constant. +""" +NM(;max_episode::Int=1000, p_num::Int=10, nelder_mead=missing, ar::Number=1.0, ae::Number=2.0, ac::Number=0.5, as0::Number=0.5) = NM(max_episode, p_num, nelder_mead, ar, ae, ac, as0) + +struct Iterative <: AbstractAlgorithm + max_episode::Int +end + +""" + + Iterative(;max_episode::Int=300, seed::Number=1234) + +State optimization algorithm: Iterative. +- `max_episode`: The number of episodes. +""" +Iterative(;max_episode::Int=300) = Iterative(max_episode) + +alg_type(::AD) = :AD +alg_type(::AD_Adam) = :AD +alg_type(::GRAPE) = :GRAPE +alg_type(::GRAPE_Adam) = :GRAPE +alg_type(::autoGRAPE) = :autoGRAPE +alg_type(::autoGRAPE_Adam) = :autoGRAPE +alg_type(::PSO) = :PSO +alg_type(::DDPG) = :DDPG +alg_type(::DE) = :DE +alg_type(::NM) = :NM +alg_type(::Iterative) = :Iterative + +include("AD.jl") +include("DDPG.jl") +include("DE.jl") +include("GRAPE.jl") +include("NM.jl") +include("Iterative.jl") +include("PSO.jl") diff --git a/src/Algorithm/DDPG.jl b/src/Algorithm/DDPG.jl new file mode 100644 index 0000000..5f353f2 --- /dev/null +++ b/src/Algorithm/DDPG.jl @@ -0,0 +1,388 @@ +## TODO: Need reconstruct !!! +using Flux: glorot_normal, glorot_uniform +using StableRNGs +using Flux.Losses +using IntervalSets + +function Base.rsplit( v, l::Int) + u = reshape(v,l,length(v)÷l) + [u[:,i] for i=1:size(u,2)] +end + +state_flatten(s) = vcat((s|>reim.|>vec)...) +rsplit_half(v) = Base.rsplit(v, length(v)÷2) +to_psi(s) = complex.(rsplit_half(s)...) +density_matrix(s) = complex.(rsplit_half(s)...)|>vec2mat + +mutable struct ControlEnv <: AbstractEnv + obj::AbstractObj + dynamics::AbstractDynamics + output::AbstractOutput + action_space::Space + state_space::Space + state::AbstractVector + dstate::AbstractVector + done::Bool + rng::AbstractRNG + reward::Float64 + total_reward::Float64 + t::Int + tspan::AbstractVector + tnum::Int + ctrl_length::Int + ctrl_num::Int + para_num::Int + f_noctrl::AbstractVector + f_final::AbstractVector + ctrl_list::AbstractVector + ctrl_bound::AbstractVector + total_reward_all::AbstractVector + episode::Int +end + +#### control optimization #### +function update!(opt::ControlOpt, alg::DDPG, obj, dynamics, output) + (; max_episode, layer_num, layer_dim, rng) = alg + #### environment of DDPG #### + para_num = length(dynamics.data.dH) + ctrl_num = length(dynamics.data.ctrl) + tnum = length(dynamics.data.tspan) + ctrl_length = length(dynamics.data.ctrl[1]) + dim = size(dynamics.data.ρ0)[1] + state = dynamics.data.ρ0 + dstate = [state |> zero for _ = 1:para_num] + state = state |> state_flatten + action_space = Space([opt.ctrl_bound[1] .. opt.ctrl_bound[2] for _ = 1:ctrl_num]) + state_space = Space(fill(-1.0e35 .. 1.0e35, length(state))) + + # dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) + # f_noctrl = objective(Val{:expm}, obj, dynamics_copy) + + #### the objective function for non controlled scenario #### + f_noctrl = zeros(ctrl_length+1) + f_noctrl_out = 0.0 + ρₜₙ, ∂ₓρₜₙ = state |> density_matrix, dstate + for ti in 2:ctrl_length+1 + ρₜₙ, ∂ₓρₜₙ = propagate(dynamics, ρₜₙ, ∂ₓρₜₙ, [0.0 for i in 1:ctrl_num], ti) + f_noctrl_out, f_noctrl[ti] = objective(obj, ρₜₙ, ∂ₓρₜₙ) + end + + f_ini, f_comp = objective(obj, dynamics) + + ctrl_list = [Vector{Float64}() for _ = 1:ctrl_num] + + set_f!(output, f_ini) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl_out, f_ini) + show(opt, output, obj) + + total_reward_all = [0.0] + episode = 1 + env = ControlEnv( + obj, + dynamics, + output, + action_space, + state_space, + state, + dstate, + true, + rng, + 0.0, + 0.0, + 0, + dynamics.data.tspan, + tnum, + ctrl_length, + ctrl_num, + para_num, + f_noctrl, + output.f_list, + ctrl_list, + opt.ctrl_bound, + total_reward_all, + episode, + ) + reset!(env) + SaveReward(env.output, 0.0) + + ns, na = 2 * dim^2, ctrl_num + init = glorot_uniform(rng) + + create_actor() = Chain( + Dense(ns, layer_dim, relu; init = init), + [Dense(layer_dim, layer_dim, relu; init = init) for _ = 1:layer_num]..., + Dense(layer_dim, na, tanh; init = init), + ) + + create_critic() = Chain( + Dense(ns + na, layer_dim, relu; init = init), + [Dense(layer_dim, layer_dim, relu; init = init) for _ = 1:layer_num]..., + Dense(layer_dim, 1; init = init), + ) + + agent = Agent( + policy = DDPGPolicy( + behavior_actor = NeuralNetworkApproximator( + model = create_actor(), + optimizer = ADAM(), + ), + behavior_critic = NeuralNetworkApproximator( + model = create_critic(), + optimizer = ADAM(), + ), + target_actor = NeuralNetworkApproximator( + model = create_actor(), + optimizer = ADAM(), + ), + target_critic = NeuralNetworkApproximator( + model = create_critic(), + optimizer = ADAM(), + ), + γ = 0.99f0, + ρ = 0.995f0, + na = ctrl_num, + batch_size = 128, + start_steps = 100 * ctrl_length, + start_policy = RandomPolicy( + Space([-10.0 .. 10.0 for _ = 1:ctrl_num]); + rng = rng, + ), + update_after = 100 * ctrl_length, + update_freq = 1 * ctrl_length, + act_limit = opt.ctrl_bound[end], + act_noise = 0.01, + rng = rng, + ), + trajectory = CircularArraySARTTrajectory( + capacity = 400 * ctrl_length, + state = Vector{Float64} => (ns,), + action = Vector{Float64} => (na,), + ), + ) + stop_condition = StopAfterStep(max_episode * ctrl_length, is_show_progress = false) + hook = TotalRewardPerEpisode(is_display_on_exit = false) + RLBase.run(agent, env, stop_condition, hook) + + set_io!(output, output.f_list[end]) + if save_type(output) == :no_save + SaveReward(env.total_reward_all) + end +end + +RLBase.action_space(env::ControlEnv) = env.action_space +RLBase.state_space(env::ControlEnv) = env.state_space +RLBase.reward(env::ControlEnv) = env.reward +RLBase.is_terminated(env::ControlEnv) = env.done +RLBase.state(env::ControlEnv) = env.state + +function RLBase.reset!(env::ControlEnv) + state = env.dynamics.data.ρ0 + env.dstate = [state |> zero for _ = 1:(env.para_num)] + env.state = state |> state_flatten + env.t = 1 + env.done = false + env.reward = 0.0 + env.total_reward = 0.0 + env.ctrl_list = [Float64[] for _ = 1:env.ctrl_num] + nothing +end + +function (env::ControlEnv)(a) + bound!(a, env.ctrl_bound) + _step!(env, a) +end + +function _step!(env::ControlEnv, a) + env.t += 1 + ρₜ, ∂ₓρₜ = env.state |> density_matrix, env.dstate + ρₜₙ, ∂ₓρₜₙ = propagate(env.dynamics, ρₜ, ∂ₓρₜ, a, env.t) + env.state = ρₜₙ |> state_flatten + env.dstate = ∂ₓρₜₙ + env.done = env.t >= env.ctrl_length + f_out, f_current = objective(env.obj, ρₜₙ, ∂ₓρₜₙ) + reward_current = log(f_current / env.f_noctrl[env.t]) + env.reward = reward_current + env.total_reward += reward_current + [append!(env.ctrl_list[i], a[i]) for i = 1:length(a)] + if env.done + set_f!(env.output, f_out) + set_buffer!(env.output, env.ctrl_list) + set_io!(env.output, f_out, env.episode) + show(env.output, env.obj) + append!(env.total_reward_all, env.total_reward) + + env.episode += 1 + SaveReward(env.output, env.total_reward) + end +end + +#### state optimization #### +mutable struct StateEnv <: AbstractEnv + obj::AbstractObj + dynamics::AbstractDynamics + output::AbstractOutput + action_space::Space + state_space::Space + state::AbstractVector + done::Bool + rng::AbstractRNG + reward::Float64 + total_reward::Float64 + ctrl_num::Int + para_num::Int + f_ini::Float64 + f_list::AbstractVector + reward_all::AbstractVector + episode::Int +end + +RLBase.action_space(env::StateEnv) = env.action_space +RLBase.state_space(env::StateEnv) = env.state_space +RLBase.reward(env::StateEnv) = env.reward +RLBase.is_terminated(env::StateEnv) = env.done +RLBase.state(env::StateEnv) = env.state + +function update!(Sopt::StateOpt, alg::DDPG, obj, dynamics::Lindblad, output) + (; max_episode, layer_num, layer_dim, rng) = alg + episode = 1 + + para_num = length(dynamics.data.dH) + state = dynamics.data.ψ0 + state = state |> state_flatten + ctrl_num = length(state) + action_space = Space(fill(-1.0e35..1.0e35, length(state))) + state_space = Space(fill(-1.0e35..1.0e35, length(state))) + f_list = Vector{Float64}() + reward_all = [0.0] + f_ini, f_comp = objective(obj, dynamics) + + env = StateEnv(obj, dynamics, output, action_space, state_space, state, true, rng, 0.0, 0.0, ctrl_num, + para_num, f_ini, f_list, reward_all, episode) + reset!(env) + SaveReward(env.output, 0.0) + + ns = 2*length(dynamics.data.ψ0) + na = env.ctrl_num + init = glorot_uniform(rng) + + create_actor() = Chain(Dense(ns, layer_dim, relu; init=init), + [Dense(layer_dim, layer_dim, relu; init=init) for _ in 1:layer_num]..., + Dense(layer_dim, na, tanh; init=init),) + + create_critic() = Chain(Dense(ns+na, layer_dim, relu; init=init), + [Dense(layer_dim, layer_dim, relu; init=init) for _ in 1:layer_num]..., + Dense(layer_dim, 1; init=init),) + + agent = Agent(policy=DDPGPolicy(behavior_actor=NeuralNetworkApproximator(model=create_actor(), optimizer=ADAM(),), + behavior_critic=NeuralNetworkApproximator(model=create_critic(), optimizer=ADAM(),), + target_actor=NeuralNetworkApproximator(model=create_actor(), optimizer=ADAM(),), + target_critic=NeuralNetworkApproximator(model=create_critic(), optimizer=ADAM(),), + γ=0.99f0, ρ=0.995f0, na=env.ctrl_num, batch_size=64, start_steps=100, + start_policy=RandomPolicy(Space([-1.0..1.0 for _ in 1:env.ctrl_num]); rng=rng), + update_after=50, update_freq=1, act_limit=1.0e35, + act_noise=0.01, rng=rng,), + trajectory=CircularArraySARTTrajectory(capacity=400, state=Vector{Float64} => (ns,), action=Vector{Float64} => (na,),),) + + set_f!(output, f_ini) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f_ini) + show(Sopt, output, obj) + + stop_condition = StopAfterStep(max_episode, is_show_progress=false) + hook = TotalRewardPerEpisode(is_display_on_exit=false) + RLBase.run(agent, env, stop_condition, hook) + + set_io!(output, output.f_list[end]) + if save_type(output) == :no_save + SaveReward(env.reward_all) + end +end + +function update!(Sopt::StateOpt, alg::DDPG, obj, dynamics::Kraus, output) + (; max_episode, layer_num, layer_dim, rng) = alg + episode = 1 + + para_num = length(dynamics.data.dK) + state = dynamics.data.ψ0 + state = state |> state_flatten + ctrl_num = length(state) + action_space = Space(fill(-1.0e35..1.0e35, length(state))) + state_space = Space(fill(-1.0e35..1.0e35, length(state))) + f_list = Vector{Float64}() + reward_all = [0.0] + f_ini, f_comp = objective(obj, dynamics) + + env = StateEnv(obj, dynamics, output, action_space, state_space, state, true, rng, 0.0, 0.0, ctrl_num, + para_num, f_ini, f_list, reward_all, episode) + reset!(env) + SaveReward(env.output, 0.0) + + ns = 2*length(dynamics.data.ψ0) + na = env.ctrl_num + init = glorot_uniform(rng) + + create_actor() = Chain(Dense(ns, layer_dim, relu; init=init), + [Dense(layer_dim, layer_dim, relu; init=init) for _ in 1:layer_num]..., + Dense(layer_dim, na, tanh; init=init),) + + create_critic() = Chain(Dense(ns+na, layer_dim, relu; init=init), + [Dense(layer_dim, layer_dim, relu; init=init) for _ in 1:layer_num]..., + Dense(layer_dim, 1; init=init),) + + agent = Agent(policy=DDPGPolicy(behavior_actor=NeuralNetworkApproximator(model=create_actor(), optimizer=ADAM(),), + behavior_critic=NeuralNetworkApproximator(model=create_critic(), optimizer=ADAM(),), + target_actor=NeuralNetworkApproximator(model=create_actor(), optimizer=ADAM(),), + target_critic=NeuralNetworkApproximator(model=create_critic(), optimizer=ADAM(),), + γ=0.99f0, ρ=0.995f0, na=env.ctrl_num, batch_size=64, start_steps=100, + start_policy=RandomPolicy(Space([-1.0..1.0 for _ in 1:env.ctrl_num]); rng=rng), + update_after=50, update_freq=1, act_limit=1.0e35, + act_noise=0.01, rng=rng,), + trajectory=CircularArraySARTTrajectory(capacity=400, state=Vector{Float64} => (ns,), action=Vector{Float64} => (na,),),) + + set_f!(output, f_ini) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f_ini) + show(Sopt, output, obj) + + stop_condition = StopAfterStep(max_episode, is_show_progress=false) + hook = TotalRewardPerEpisode(is_display_on_exit=false) + RLBase.run(agent, env, stop_condition, hook) + + set_io!(output, output.f_list[end]) + if save_type(output) == :no_save + SaveReward(env.reward_all) + end +end + +function RLBase.reset!(env::StateEnv) + state = env.dynamics.data.ψ0 + env.state = state |> state_flatten + env.done = false + nothing +end + +function (env::StateEnv)(a) + _step!(env, a) +end + +function _step!(env::StateEnv, a) + state_new = (env.state + a) |> to_psi + env.dynamics.data.ψ0 = state_new/norm(state_new) + + f_out, f_current = objective(env.obj, env.dynamics) + + env.reward = log(f_current/env.f_ini) + env.total_reward = env.reward + env.done = true + + append!(env.f_list, f_out) + append!(env.reward_all, env.reward) + env.episode += 1 + + set_f!(env.output, f_out) + set_buffer!(env.output, transpose(env.dynamics.data.ψ0)) + set_io!(env.output, f_out, env.episode) + show(env.output, env.obj) + SaveReward(env.output, env.total_reward) +end diff --git a/src/Algorithm/DE.jl b/src/Algorithm/DE.jl new file mode 100644 index 0000000..fabe12a --- /dev/null +++ b/src/Algorithm/DE.jl @@ -0,0 +1,847 @@ +#### control optimization #### +function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.ctrl,],) + end + ini_population = ini_population[1] + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + populations = repeat(dynamics, p_num) + + # initialization + initial_ctrl!(opt, ini_population, populations, p_num, opt.rng) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + p_fit, p_out = zeros(p_num), zeros(p_num) + for i = 1:p_num + p_out[i], p_fit[i] = objective(obj, populations[i]) + end + + set_f!(output, p_out[1]) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl, p_out[1]) + show(opt, output, obj) + + for ei = 1:(max_episode-1) + for pj = 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) + ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i = 1:ctrl_num] + for ci = 1:ctrl_num + for ti = 1:ctrl_length + ctrl_mut[ci][ti] = + populations[mut_num[1]].data.ctrl[ci][ti] + + c * ( + populations[mut_num[2]].data.ctrl[ci][ti] - + populations[mut_num[3]].data.ctrl[ci][ti] + ) + end + end + #crossover + ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i = 1:ctrl_num] + for cj = 1:ctrl_num + cross_int = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] + for tj = 1:ctrl_length + rand_num = rand(opt.rng) + if rand_num <= cr + ctrl_cross[cj][tj] = ctrl_mut[cj][tj] + else + ctrl_cross[cj][tj] = populations[pj].data.ctrl[cj][tj] + end + end + ctrl_cross[cj][cross_int] = ctrl_mut[cj][cross_int] + end + #selection + bound!(ctrl_cross, opt.ctrl_bound) + dynamics_cross = set_ctrl(populations[pj], ctrl_cross) + f_out, f_cross = objective(obj, dynamics_cross) + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck = 1:ctrl_num + for tk = 1:ctrl_length + populations[pj].data.ctrl[ck][tk] = ctrl_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + set_f!(output, p_out[idx]) + set_buffer!(output, populations[idx].data.ctrl) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state optimization #### +function update!(opt::StateOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.psi,],) + end + ini_population = ini_population[1] + dim = length(dynamics.data.ψ0) + populations = repeat(dynamics, p_num) + # initialization + initial_state!(ini_population, populations, p_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for i in 1:p_num + p_out[i], p_fit[i] = objective(obj, populations[i]) + end + + set_f!(output, p_out[1]) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, p_out[1]) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) + state_mut = zeros(ComplexF64, dim) + for ci in 1:dim + state_mut[ci] = populations[mut_num[1]].data.ψ0[ci]+c*(populations[mut_num[2]].data.ψ0[ci]-populations[mut_num[3]].data.ψ0[ci]) + end + #crossover + state_cross = zeros(ComplexF64, dim) + cross_int = sample(opt.rng, 1:dim, 1, replace=false)[1] + for cj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + state_cross[cj] = state_mut[cj] + else + state_cross[cj] = populations[pj].data.ψ0[cj] + end + state_cross[cross_int] = state_mut[cross_int] + end + psi_cross = state_cross/norm(state_cross) + dynamics_cross = set_state(populations[pj], psi_cross) + f_out, f_cross = objective(obj, dynamics_cross) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:dim + populations[pj].data.ψ0[ck] = psi_cross[ck] + end + end + end + idx = findmax(p_fit)[2] + set_f!(output, p_out[idx]) + set_buffer!(output, transpose(populations[idx].data.ψ0)) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### projective measurement optimization #### +function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.M], ) + end + ini_population = ini_population[1] + + dim = size(dynamics.data.ρ0)[1] + M_num = length(opt.M) + + populations = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + # initialization + initial_M!(ini_population, populations, dim, p_num, M_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + M = [populations[pj][i]*(populations[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, dynamics) + end + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + + M = [populations[1][i]*(populations[1][i])' for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, M) + set_io!(output, p_out[1], f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) + M_mut = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for ci in 1:M_num + for ti in 1:dim + M_mut[ci][ti] = populations[mut_num[1]][ci][ti] + c*(populations[mut_num[2]][ci][ti]- + populations[mut_num[3]][ci][ti]) + end + end + #crossover + M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for cj in 1:M_num + cross_int = sample(opt.rng, 1:dim, 1, replace=false)[1] + for tj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[cj][tj] = M_mut[cj][tj] + else + M_cross[cj][tj] = populations[pj][cj][tj] + end + end + M_cross[cj][cross_int] = M_mut[cj][cross_int] + end + # orthogonality and normalization + M_cross = gramschmidt(M_cross) + M = [M_cross[i]*(M_cross[i])' for i in 1:M_num] + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:M_num + for tk in 1:dim + populations[pj][ck][tk] = M_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + M = [populations[idx][i]*(populations[idx][i])' for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### find the optimal linear combination of a given set of POVM #### +function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + (; B, POVM_basis, M_num) = opt + if ismissing(ini_population) + ini_population = ( [B], ) + end + ini_population = ini_population[1] + dim = size(dynamics.data.ρ0)[1] + basis_num = length(POVM_basis) + populations = [[zeros(basis_num) for j in 1:M_num] for i in 1:p_num] + + # initialization + initial_LinearComb!(ini_population, populations, basis_num, M_num, p_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + M = [sum([populations[pj][i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, dynamics) + end + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + + M = [sum([populations[1][i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, M) + set_io!(output, p_out[1], f_povm, f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) + M_mut = [Vector{Float64}(undef, basis_num) for i in 1:M_num] + for ci in 1:M_num + for ti in 1:basis_num + M_mut[ci][ti] = populations[mut_num[1]][ci][ti] + c*(populations[mut_num[2]][ci][ti]-populations[mut_num[3]][ci][ti]) + end + end + #crossover + M_cross = [Vector{Float64}(undef, basis_num) for i in 1:M_num] + for cj in 1:M_num + cross_int = sample(opt.rng, 1:basis_num, 1, replace=false)[1] + for tj in 1:basis_num + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[cj][tj] = M_mut[cj][tj] + else + M_cross[cj][tj] = populations[pj][cj][tj] + end + end + M_cross[cj][cross_int] = M_mut[cj][cross_int] + end + + # normalize the coefficients + bound_LC_coeff!(M_cross, opt.rng) + M = [sum([M_cross[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:M_num + for tk in 1:basis_num + populations[pj][ck][tk] = M_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + M = [sum([populations[idx][i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### find the optimal rotated measurement of a given set of POVM #### +function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + (; s, POVM_basis, Lambda) = opt + if ismissing(ini_population) + ini_population = ([s,],) + end + ini_population = ini_population[1] + dim = size(dynamics.data.ρ0)[1] + suN = suN_generator(dim) + Lambda = Matrix{ComplexF64}[] + append!(Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + append!(Lambda, [suN[i] for i in 1:length(suN)]) + + # if ismissing(Lambda) + # Lambda = Matrix{ComplexF64}[] + # append!(Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + # append!(Lambda, [suN[i] for i in 1:length(suN)]) + # end + + M_num = length(POVM_basis) + populations = [zeros(dim^2) for i in 1:p_num] + # initialization + initial_Rotation!(ini_population, populations, dim, p_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + U = rotation_matrix(populations[pj], Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, dynamics) + end + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + + U = rotation_matrix(populations[1], Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, M) + set_io!(output, p_out[1], f_povm, f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) + M_mut = Vector{Float64}(undef, dim^2) + for ti in 1:dim^2 + M_mut[ti] = populations[mut_num[1]][ti] + c*(populations[mut_num[2]][ti]-populations[mut_num[3]][ti]) + end + + #crossover + M_cross = Vector{Float64}(undef, dim^2) + cross_int = sample(opt.rng, 1:dim^2, 1, replace=false)[1] + for tj in 1:dim^2 + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[tj] = M_mut[tj] + else + M_cross[tj] = populations[pj][tj] + end + end + M_cross[cross_int] = M_mut[cross_int] + + # normalize the coefficients + bound_rot_coeff!(M_cross) + U = rotation_matrix(M_cross, Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for tk in 1:dim^2 + populations[pj][tk] = M_cross[tk] + end + end + end + idx = findmax(p_fit)[2] + U = rotation_matrix(populations[idx], Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state and control optimization #### +function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.psi], [opt.ctrl,]) + end + psi0, ctrl0 = ini_population + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + dim = length(dynamics.data.ψ0) + populations = repeat(dynamics, p_num) + + # initialization + initial_state!(psi0, populations, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for i in 1:p_num + p_out[i], p_fit[i] = objective(obj, populations[i]) + end + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i in 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + + set_f!(output, p_out[1]) + set_buffer!(output, transpose(populations[1].data.ψ0), populations[1].data.ctrl) + set_io!(output, f_noctrl, p_out[1]) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) + state_mut = zeros(ComplexF64, dim) + for ci in 1:dim + state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) + end + ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for ci in 1:ctrl_num + for ti in 1:ctrl_length + ctrl_mut[ci][ti] = populations[mut_num[1]].data.ctrl[ci][ti] + + c * (populations[mut_num[2]].data.ctrl[ci][ti] - + populations[mut_num[3]].data.ctrl[ci][ti]) + end + end + #crossover + state_cross = zeros(ComplexF64, dim) + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] + for cj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + state_cross[cj] = state_mut[cj] + else + state_cross[cj] = populations[pj].data.ψ0[cj] + end + state_cross[cross_int1] = state_mut[cross_int1] + end + psi_cross = state_cross / norm(state_cross) + ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for cj in 1:ctrl_num + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] + for tj in 1:ctrl_length + rand_num = rand(opt.rng) + if rand_num <= cr + ctrl_cross[cj][tj] = ctrl_mut[cj][tj] + else + ctrl_cross[cj][tj] = populations[pj].data.ctrl[cj][tj] + end + end + ctrl_cross[cj][cross_int2] = ctrl_mut[cj][cross_int2] + end + bound!(ctrl_cross, opt.ctrl_bound) + + dynamics_copy = set_state(populations[pj], psi_cross) + dynamics_copy = set_ctrl(dynamics_copy, ctrl_cross) + f_out, f_cross = objective(obj, dynamics_copy) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:dim + populations[pj].data.ψ0[ck] = psi_cross[ck] + end + for ck in 1:ctrl_num + for tk in 1:ctrl_length + populations[pj].data.ctrl[ck][tk] = ctrl_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + set_f!(output, p_out[idx]) + set_buffer!(output, transpose(populations[idx].data.ψ0), populations[idx].data.ctrl) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state and measurement optimization #### +function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.psi], [opt.M,]) + end + psi0, measurement0 = ini_population + dim = length(dynamics.data.ψ0) + M_num = length(opt.M) + populations = repeat(dynamics, p_num) + + # initialization + initial_state!(psi0, populations, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, populations[pj]) + end + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, transpose(populations[1].data.ψ0), M) + set_io!(output, p_out[1]) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) + state_mut = zeros(ComplexF64, dim) + for ci in 1:dim + state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) + end + + M_mut = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for ci in 1:M_num + for ti in 1:dim + M_mut[ci][ti] = C_all[mut_num[1]][ci][ti] + c * (C_all[mut_num[2]][ci][ti] - + C_all[mut_num[3]][ci][ti]) + end + end + #crossover + state_cross = zeros(ComplexF64, dim) + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] + for cj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + state_cross[cj] = state_mut[cj] + else + state_cross[cj] = populations[pj].data.ψ0[cj] + end + state_cross[cross_int1] = state_mut[cross_int1] + end + psi_cross = state_cross / norm(state_cross) + + M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for cj in 1:M_num + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] + for tj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[cj][tj] = M_mut[cj][tj] + else + M_cross[cj][tj] = C_all[pj][cj][tj] + end + end + M_cross[cj][cross_int] = M_mut[cj][cross_int] + end + # orthogonality and normalization + M_cross = gramschmidt(M_cross) + M = [M_cross[i] * (M_cross[i])' for i in 1:M_num] + dynamics_cross = set_state(populations[pj], psi_cross) + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics_cross) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:dim + populations[pj].data.ψ0[ck] = psi_cross[ck] + end + + for ck in 1:M_num + for tk in 1:dim + C_all[pj][ck][tk] = M_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + M = [C_all[idx][i]*(C_all[idx][i])' for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, transpose(populations[idx].data.ψ0), M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### control and measurement optimization #### +function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.ctrl,], [opt.M]) + end + ctrl0, measurement0 = ini_population + dim = size(dynamics.data.ρ0)[1] + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + M_num = length(opt.M) + populations = repeat(dynamics, p_num) + + # initialization + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, populations[pj]) + end + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, populations[1].data.ctrl, M) + set_io!(output, p_out[1]) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) + ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for ci in 1:ctrl_num + for ti in 1:ctrl_length + ctrl_mut[ci][ti] = populations[mut_num[1]].data.ctrl[ci][ti] + + c * (populations[mut_num[2]].data.ctrl[ci][ti] - + populations[mut_num[3]].data.ctrl[ci][ti]) + end + end + + M_mut = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for ci in 1:M_num + for ti in 1:dim + M_mut[ci][ti] = C_all[mut_num[1]][ci][ti] + c * (C_all[mut_num[2]][ci][ti] - + C_all[mut_num[3]][ci][ti]) + end + end + + #crossover + ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for cj in 1:ctrl_num + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] + for tj in 1:ctrl_length + rand_num = rand(opt.rng) + if rand_num <= cr + ctrl_cross[cj][tj] = ctrl_mut[cj][tj] + else + ctrl_cross[cj][tj] = populations[pj].data.ctrl[cj][tj] + end + end + ctrl_cross[cj][cross_int2] = ctrl_mut[cj][cross_int2] + end + bound!(ctrl_cross, opt.ctrl_bound) + + M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for cj in 1:M_num + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] + for tj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[cj][tj] = M_mut[cj][tj] + else + M_cross[cj][tj] = C_all[pj][cj][tj] + end + end + M_cross[cj][cross_int] = M_mut[cj][cross_int] + end + # orthogonality and normalization + M_cross = gramschmidt(M_cross) + M = [M_cross[i] * (M_cross[i])' for i in 1:M_num] + dynamics_cross = set_ctrl(populations[pj], ctrl_cross) + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics_cross) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:ctrl_num + for tk in 1:ctrl_length + populations[pj].data.ctrl[ck][tk] = ctrl_cross[ck][tk] + end + end + + for ck in 1:M_num + for tk in 1:dim + C_all[pj][ck][tk] = M_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + M = [C_all[idx][i]*(C_all[idx][i])' for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, populations[idx].data.ctrl, M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state, control and measurement optimization #### +function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output) + (; max_episode, p_num, ini_population, c, cr) = alg + if ismissing(ini_population) + ini_population = ([opt.psi], [opt.ctrl,], [opt.M]) + end + psi0, ctrl0, measurement0 = ini_population + dim = length(dynamics.data.ψ0) + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + M_num = length(opt.M) + populations = repeat(dynamics, p_num) + + # initialization + initial_state!(psi0, populations, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + p_out[pj], p_fit[pj] = objective(obj_copy, populations[pj]) + end + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + set_f!(output, p_out[1]) + set_buffer!(output, transpose(populations[1].data.ψ0), populations[1].data.ctrl, M) + set_io!(output, p_out[1]) + show(opt, output, obj) + + for ei in 1:(max_episode-1) + for pj in 1:p_num + #mutations + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) + state_mut = zeros(ComplexF64, dim) + for ci in 1:dim + state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) + end + ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for ci in 1:ctrl_num + for ti in 1:ctrl_length + ctrl_mut[ci][ti] = populations[mut_num[1]].data.ctrl[ci][ti] + + c * (populations[mut_num[2]].data.ctrl[ci][ti] - + populations[mut_num[3]].data.ctrl[ci][ti]) + end + end + M_mut = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for ci in 1:M_num + for ti in 1:dim + M_mut[ci][ti] = C_all[mut_num[1]][ci][ti] + c * (C_all[mut_num[2]][ci][ti] - + C_all[mut_num[3]][ci][ti]) + end + end + #crossover + state_cross = zeros(ComplexF64, dim) + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] + for cj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + state_cross[cj] = state_mut[cj] + else + state_cross[cj] = populations[pj].data.ψ0[cj] + end + state_cross[cross_int1] = state_mut[cross_int1] + end + psi_cross = state_cross / norm(state_cross) + ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] + for cj in 1:ctrl_num + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] + for tj in 1:ctrl_length + rand_num = rand(opt.rng) + if rand_num <= cr + ctrl_cross[cj][tj] = ctrl_mut[cj][tj] + else + ctrl_cross[cj][tj] = populations[pj].data.ctrl[cj][tj] + end + end + ctrl_cross[cj][cross_int2] = ctrl_mut[cj][cross_int2] + end + bound!(ctrl_cross, opt.ctrl_bound) + + M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for cj in 1:M_num + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] + for tj in 1:dim + rand_num = rand(opt.rng) + if rand_num <= cr + M_cross[cj][tj] = M_mut[cj][tj] + else + M_cross[cj][tj] = C_all[pj][cj][tj] + end + end + M_cross[cj][cross_int] = M_mut[cj][cross_int] + end + # orthogonality and normalization + M_cross = gramschmidt(M_cross) + M = [M_cross[i] * (M_cross[i])' for i in 1:M_num] + dynamics_cross = set_state(populations[pj], psi_cross) + dynamics_cross = set_ctrl(dynamics_cross, ctrl_cross) + obj_cross = set_M(obj, M) + f_out, f_cross = objective(obj_cross, dynamics_cross) + #selection + if f_cross > p_fit[pj] + p_fit[pj] = f_cross + p_out[pj] = f_out + for ck in 1:dim + populations[pj].data.ψ0[ck] = psi_cross[ck] + end + for ck in 1:ctrl_num + for tk in 1:ctrl_length + populations[pj].data.ctrl[ck][tk] = ctrl_cross[ck][tk] + end + end + for ck in 1:M_num + for tk in 1:dim + C_all[pj][ck][tk] = M_cross[ck][tk] + end + end + end + end + idx = findmax(p_fit)[2] + M = [C_all[idx][i]*(C_all[idx][i])' for i in 1:M_num] + set_f!(output, p_out[idx]) + set_buffer!(output, transpose(populations[idx].data.ψ0), populations[idx].data.ctrl, M) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end diff --git a/src/Algorithm/GRAPE.jl b/src/Algorithm/GRAPE.jl new file mode 100644 index 0000000..5bd03af --- /dev/null +++ b/src/Algorithm/GRAPE.jl @@ -0,0 +1,493 @@ +function update!(opt::ControlOpt, alg::AbstractGRAPE, obj::QFIM_obj, dynamics, output) + (; max_episode) = alg + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i in 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + set_f!(output, f_ini) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + for ei in 1:(max_episode-1) + gradient_QFIM_analy(opt, alg, obj, dynamics) + bound!(dynamics.data.ctrl, opt.ctrl_bound) + f_out, f_now = objective(obj, dynamics) + set_f!(output, f_out) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function update!(opt::ControlOpt, alg::AbstractGRAPE, obj::CFIM_obj, dynamics, output) + (; max_episode) = alg + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i in 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + set_f!(output, f_ini) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + for ei in 1:(max_episode-1) + gradient_CFIM_analy(opt, alg, obj, dynamics) + bound!(dynamics.data.ctrl, opt.ctrl_bound) + f_out, f_now = objective(obj, dynamics) + set_f!(output, f_out) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +function dynamics_analy(dynamics, dim, tnum, para_num, ctrl_num) + Δt = dynamics.data.tspan[2] - dynamics.data.tspan[1] + H = Htot(dynamics.data.H0, dynamics.data.Hc, dynamics.data.ctrl) + + ρt = [Vector{ComplexF64}(undef, dim^2) for i in 1:tnum] + ∂ρt_∂x = [[Vector{ComplexF64}(undef, dim^2) for para in 1:para_num] for i in 1:tnum] + δρt_δV = [[] for i in 1:ctrl_num] + ∂xδρt_δV = [[[] for i in 1:ctrl_num] for i in 1:para_num] + ∂H_L = [Matrix{ComplexF64}(undef, dim^2,dim^2) for i in 1:para_num] + Hc_L = [Matrix{ComplexF64}(undef, dim^2,dim^2) for i in 1:ctrl_num] + + ρt[1] = dynamics.data.ρ0 |> vec + for cj in 1:ctrl_num + Hc_L[cj] = liouville_commu(dynamics.data.Hc[cj]) + append!(δρt_δV[cj], [-im*Δt*Hc_L[cj]*ρt[1]]) + end + + for pj in 1:para_num + ∂ρt_∂x[1][pj] = ρt[1] |> zero + ∂H_L[pj] = liouville_commu(dynamics.data.dH[pj]) + for ci in 1:ctrl_num + append!(∂xδρt_δV[pj][ci], [-im*Δt*Hc_L[ci]*∂ρt_∂x[1][pj]]) + end + end + + for ti in 2:tnum + exp_L = expL(H[ti-1], dynamics.data.decay_opt, dynamics.data.γ, Δt, ti) + ρt[ti] = exp_L * ρt[ti-1] + for pk in 1:para_num + ∂ρt_∂x[ti][pk] = -im * Δt * ∂H_L[pk] * ρt[ti] + exp_L * ∂ρt_∂x[ti-1][pk] + end + + for ck in 1:ctrl_num + for tk in 1:(ti-1) + δρt_δV_first = popfirst!(δρt_δV[ck]) + δρt_δV_tp = exp_L * δρt_δV_first + append!(δρt_δV[ck], [δρt_δV_tp]) + for pk in 1:para_num + ∂xδρt_δV_first = popfirst!(∂xδρt_δV[pk][ck]) + ∂xδρt_δV_tp = -im * Δt * ∂H_L[pk] * exp_L * δρt_δV_first + exp_L * ∂xδρt_δV_first + append!(∂xδρt_δV[pk][ck], [∂xδρt_δV_tp]) + end + end + δρt_δV_last = -im * Δt * Hc_L[ck] * ρt[ti] + append!(δρt_δV[ck], [δρt_δV_last]) + for pk in 1:para_num + ∂xδρt_δV_last = -im * Δt * Hc_L[ck] * ∂ρt_∂x[ti][pk] + append!(∂xδρt_δV[pk][ck], [∂xδρt_δV_last]) + end + end + end + ρt_T = ρt[end] |> vec2mat + ∂ρt_T = [(∂ρt_∂x[end][para] |> vec2mat) for para in 1:para_num] + return ρt_T, ∂ρt_T, δρt_δV, ∂xδρt_δV +end + +function gradient_QFIM_analy(opt, alg::GRAPE_Adam, obj, dynamics) + dim = size(dynamics.data.ρ0)[1] + tnum = length(dynamics.data.tspan) + para_num = length(dynamics.data.dH) + ctrl_num = length(dynamics.data.Hc) + + ρt_T, ∂ρt_T, δρt_δV, ∂xδρt_δV = dynamics_analy(dynamics, dim, tnum, para_num, ctrl_num) + + Lx = SLD(ρt_T, ∂ρt_T; eps=obj.eps) + F_T = QFIM_SLD(ρt_T, ∂ρt_T; eps=obj.eps) + + if para_num == 1 + cost_function = F_T[1] + anti_commu = 2*Lx[1]*Lx[1] + for cm in 1:ctrl_num + mt, vt = 0.0, 0.0 + for tm in 1:(tnum-1) + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[1][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV*Lx[1]) + term2 = tr(∂ρt_T_δV*anti_commu) + δF = ((2*term1-0.5*term2) |> real) + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + elseif para_num == 2 + coeff1 = real(det(F)) + coeff2 = obj.W[1,1]*F_T[2,2]+obj.W[2,2]*F_T[1,1]-obj.W[1,2]*F_T[2,1]-obj.W[2,1]*F_T[1,2] + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + for cm in 1:ctrl_num + mt, vt = 0.0, 0.0 + for tm in 1:(tnum-1) + δF_all = [[0.0 for i in 1:para_num] for j in 1:para_num] + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + for pm in 1:para_num + for pn in 1:para_num + ∂xδρt_T_δV_a = ∂xδρt_δV[pm][cm][tm] |> vec2mat + ∂xδρt_T_δV_b = ∂xδρt_δV[pn][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV_a * Lx[pn]) + term2 = tr(∂xδρt_T_δV_b * Lx[pm]) + + anti_commu = Lx[pm] * Lx[pn] + Lx[pn] * Lx[pm] + term2 = tr(∂ρt_T_δV * anti_commu) + δF_all[pm][pn] = ((2*term1-0.5*term2) |> real) + end + end + item1 = -coeff2*(F_T[2,2]*δF_all[1][1]+F_T[1,1]*δF_all[2][2]-F_T[2,1]*δF_all[1][2]-F_T[1,2]*δF_all[2][1])/coeff1^2 + item2 = (obj.W[1,1]*δF_all[2][2]+obj.W[2,2]*δF_all[1][1]-obj.W[1,2]*δF_all[2][1]-obj.W[2,1]*δF_all[1][2])/coeff1 + δF = -(item1+item2)*cost_function^2 + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + else + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + coeff = [obj.W[para,para]/F_T[para,para] for para in 1:para_num] |>sum + coeff = coeff^(-2) + for cm in 1:ctrl_num + mt, vt = 0.0, 0.0 + for tm in 1:(tnum-1) + δF = 0.0 + for pm in 1:para_num + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[pm][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV * Lx[pm]) + anti_commu = 2 * Lx[pm] * Lx[pm] + term2 = tr(∂ρt_T_δV * anti_commu) + δF = δF + obj.W[pm,pm]*(1.0/F_T[pm,pm]/F_T[pm,pm])*((2*term1-0.5*term2) |> real) + end + δF = δF*coeff + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + end +end + +function gradient_QFIM_analy(opt, alg::GRAPE, obj, dynamics) + dim = size(dynamics.data.ρ0)[1] + tnum = length(dynamics.data.tspan) + para_num = length(dynamics.data.dH) + ctrl_num = length(dynamics.data.Hc) + + ρt_T, ∂ρt_T, δρt_δV, ∂xδρt_δV = dynamics_analy(dynamics, dim, tnum, para_num, ctrl_num) + + Lx = SLD(ρt_T, ∂ρt_T; eps=obj.eps) + F_T = QFIM_SLD(ρt_T, ∂ρt_T; eps=obj.eps) + + cost_function = F_T[1] + + if para_num == 1 + anti_commu = 2*Lx[1]*Lx[1] + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[1][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV*Lx[1]) + term2 = tr(∂ρt_T_δV*anti_commu) + δF = ((2*term1-0.5*term2) |> real) + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + elseif para_num == 2 + coeff1 = real(det(F)) + coeff2 = obj.W[1,1]*F_T[2,2]+obj.W[2,2]*F_T[1,1]-obj.W[1,2]*F_T[2,1]-obj.W[2,1]*F_T[1,2] + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + δF_all = [[0.0 for i in 1:para_num] for j in 1:para_num] + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + for pm in 1:para_num + for pn in 1:para_num + ∂xδρt_T_δV_a = ∂xδρt_δV[pm][cm][tm] |> vec2mat + ∂xδρt_T_δV_b = ∂xδρt_δV[pn][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV_a * Lx[pn]) + term2 = tr(∂xδρt_T_δV_b * Lx[pm]) + + anti_commu = Lx[pm] * Lx[pn] + Lx[pn] * Lx[pm] + term2 = tr(∂ρt_T_δV * anti_commu) + δF_all[pm][pn] = ((2*term1-0.5*term2) |> real) + end + end + item1 = -coeff2*(F_T[2,2]*δF_all[1][1]+F_T[1,1]*δF_all[2][2]-F_T[2,1]*δF_all[1][2]-F_T[1,2]*δF_all[2][1])/coeff1^2 + item2 = (obj.W[1,1]*δF_all[2][2]+obj.W[2,2]*δF_all[1][1]-obj.W[1,2]*δF_all[2][1]-obj.W[2,1]*δF_all[1][2])/coeff1 + δF = -(item1+item2)*cost_function^2 + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + else + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + coeff = [obj.W[para,para]/F_T[para,para] for para in 1:para_num] |>sum + coeff = coeff^(-2) + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + δF = 0.0 + for pm in 1:para_num + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[pm][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV * Lx[pm]) + anti_commu = 2 * Lx[pm] * Lx[pm] + term2 = tr(∂ρt_T_δV * anti_commu) + δF = δF + obj.W[pm,pm]*(1.0/F_T[pm,pm]/F_T[pm,pm])*((2*term1-0.5*term2) |> real) + end + δF = δF*coeff + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + end +end + +function gradient_CFIM_analy_Adam(opt, alg, obj, dynamics) + dim = size(dynamics.data.ρ0)[1] + tnum = length(dynamics.data.tspan) + para_num = length(dynamics.data.dH) + ctrl_num = length(dynamics.data.Hc) + + ρt_T, ∂ρt_T, δρt_δV, ∂xδρt_δV = dynamics_analy(dynamics, dim, tnum, para_num, ctrl_num) + + if para_num == 1 + F_T = CFIM(ρt_T, ∂ρt_T[1], obj.M; eps=obj.eps) + cost_function = F_T + L1_tidle = zeros(ComplexF64, dim, dim) + L2_tidle = zeros(ComplexF64, dim, dim) + + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[1]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle = L1_tidle + dp*obj.M[mi]/p + L2_tidle = L2_tidle + dp*dp*obj.M[mi]/p^2 + end + end + + for cm in 1:ctrl_num + mt, vt = 0.0, 0.0 + for tm in 1:(tnum-1) + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[1][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV*L1_tidle) + term2 = tr(∂ρt_T_δV*L2_tidle) + δF = ((2*term1-term2) |> real) + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + elseif para_num == 2 + F_T = CFIM(ρt_T, ∂ρt_T, obj.M; eps=obj.eps) + L1_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + L2_tidle = [[zeros(ComplexF64, dim, dim) for i in 1:para_num] for j in 1:para_num] + + for para_i in 1:para_num + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle[para_i] = L1_tidle[para_i] + dp*obj.M[mi]/p + end + end + end + + for para_i in 1:para_num + dp_a = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + for para_j in 1:para_num + dp_b = (tr(∂ρt_T[para_j]*obj.M[mi]) |> real) + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + if p > obj.eps + L2_tidle[para_i][para_j] = L2_tidle[para_i][para_j] + dp_a*dp_b*obj.M[mi]/p^2 + end + end + end + end + coeff1 = real(det(F)) + coeff2 = obj.W[1,1]*F_T[2,2]+obj.W[2,2]*F_T[1,1]-obj.W[1,2]*F_T[2,1]-obj.W[2,1]*F_T[1,2] + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + for cm in 1:ctrl_num + mt, vt = 0.0, 0.0 + for tm in 1:(tnum-1) + δF_all = [[0.0 for i in 1:para_num] for j in 1:para_num] + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + for pm in 1:para_num + for pn in 1:para_num + ∂xδρt_T_δV_a = ∂xδρt_δV[pm][cm][tm] |> vec2mat + ∂xδρt_T_δV_b = ∂xδρt_δV[pn][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV_a * L1_tidle[pn]) + term2 = tr(∂xδρt_T_δV_b * L1_tidle[pm]) + term3 = tr(∂ρt_T_δV * L2_tidle[pm][pn]) + δF_all[pm][pn] = ((term1+term2-term3) |> real) + end + end + item1 = -coeff2*(F_T[2,2]*δF_all[1][1]+F_T[1,1]*δF_all[2][2]-F_T[2,1]*δF_all[1][2]-F_T[1,2]*δF_all[2][1])/coeff1^2 + item2 = (obj.W[1,1]*δF_all[2][2]+obj.W[2,2]*δF_all[1][1]-obj.W[1,2]*δF_all[2][1]-obj.W[2,1]*δF_all[1][2])/coeff1 + δF = -(item1+item2)*cost_function^2 + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + else + F_T = CFIM(ρt_T, ∂ρt_T, obj.M; eps=obj.eps) + L1_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + L2_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + + for para_i in 1:para_num + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle[para_i] = L1_tidle[para_i] + dp*obj.M[mi]/p + L2_tidle[para_i] = L2_tidle[para_i] + dp*dp*obj.M[mi]/p^2 + end + end + end + + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + coeff = [obj.W[para,para]/F_T[para,para] for para in 1:para_num] |>sum + coeff = coeff^(-2) + for cm in 1:ctrl_num + mt = grape.mt + vt = grape.vt + for tm in 1:(tnum-1) + δF = 0.0 + for pm in 1:para_num + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[pm][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV * L1_tidle[pm]) + term2 = tr(∂ρt_T_δV * L2_tidle[pm]) + δF = δF + obj.W[pm,pm]*(1.0/F_T[pm,pm]/F_T[pm,pm])*((2*term1-term2) |> real) + end + δF = δF*coeff + dynamics.data.ctrl[cm][tm], mt, vt = Adam(δF, tm, dynamics.data.ctrl[cm][tm], mt, vt, alg.epsilon, alg.beta1, alg.beta2, obj.eps) + end + end + end +end + +function gradient_CFIM_analy(opt, alg, obj, dynamics) + dim = size(dynamics.data.ρ0)[1] + tnum = length(dynamics.data.tspan) + para_num = length(dynamics.data.dH) + ctrl_num = length(dynamics.data.Hc) + + ρt_T, ∂ρt_T, δρt_δV, ∂xδρt_δV = dynamics_analy(dynamics, dim, tnum, para_num, ctrl_num) + + if para_num == 1 + F_T = CFIM(ρt_T, ∂ρt_T[1], obj.M; eps=obj.eps) + cost_function = F_T + L1_tidle = zeros(ComplexF64, dim, dim) + L2_tidle = zeros(ComplexF64, dim, dim) + + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[1]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle = L1_tidle + dp*obj.M[mi]/p + L2_tidle = L2_tidle + dp*dp*obj.M[mi]/p^2 + end + end + + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[1][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV*L1_tidle) + term2 = tr(∂ρt_T_δV*L2_tidle) + δF = ((2*term1-term2) |> real) + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + elseif para_num == 2 + F_T = CFIM(ρt_T, ∂ρt_T, obj.M; eps=obj.eps) + L1_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + L2_tidle = [[zeros(ComplexF64, dim, dim) for i in 1:para_num] for j in 1:para_num] + + for para_i in 1:para_num + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle[para_i] = L1_tidle[para_i] + dp*obj.M[mi]/p + end + end + end + + for para_i in 1:para_num + dp_a = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + for para_j in 1:para_num + dp_b = (tr(∂ρt_T[para_j]*obj.M[mi]) |> real) + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + if p > obj.eps + L2_tidle[para_i][para_j] = L2_tidle[para_i][para_j] + dp_a*dp_b*obj.M[mi]/p^2 + end + end + end + end + coeff1 = real(det(F)) + coeff2 = obj.W[1,1]*F_T[2,2]+obj.W[2,2]*F_T[1,1]-obj.W[1,2]*F_T[2,1]-obj.W[2,1]*F_T[1,2] + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + δF_all = [[0.0 for i in 1:para_num] for j in 1:para_num] + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + for pm in 1:para_num + for pn in 1:para_num + ∂xδρt_T_δV_a = ∂xδρt_δV[pm][cm][tm] |> vec2mat + ∂xδρt_T_δV_b = ∂xδρt_δV[pn][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV_a * L1_tidle[pn]) + term2 = tr(∂xδρt_T_δV_b * L1_tidle[pm]) + term3 = tr(∂ρt_T_δV * L2_tidle[pm][pn]) + δF_all[pm][pn] = ((term1+term2-term3) |> real) + end + end + item1 = -coeff2*(F_T[2,2]*δF_all[1][1]+F_T[1,1]*δF_all[2][2]-F_T[2,1]*δF_all[1][2]-F_T[1,2]*δF_all[2][1])/coeff1^2 + item2 = (obj.W[1,1]*δF_all[2][2]+obj.W[2,2]*δF_all[1][1]-obj.W[1,2]*δF_all[2][1]-obj.W[2,1]*δF_all[1][2])/coeff1 + δF = -(item1+item2)*cost_function^2 + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + else + F_T = CFIM(ρt_T, ∂ρt_T, obj.M; eps=obj.eps) + L1_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + L2_tidle = [zeros(ComplexF64, dim, dim) for i in 1:para_num] + + for para_i in 1:para_num + for mi in 1:dim + p = (tr(ρt_T*obj.M[mi]) |> real) + dp = (tr(∂ρt_T[para_i]*obj.M[mi]) |> real) + if p > obj.eps + L1_tidle[para_i] = L1_tidle[para_i] + dp*obj.M[mi]/p + L2_tidle[para_i] = L2_tidle[para_i] + dp*dp*obj.M[mi]/p^2 + end + end + end + + cost_function = (abs(det(F_T)) < obj.eps ? (1.0/obj.eps) : real(tr(obj.W*inv(F_T)))) + coeff = [obj.W[para,para]/F_T[para,para] for para in 1:para_num] |>sum + coeff = coeff^(-2) + for cm in 1:ctrl_num + for tm in 1:(tnum-1) + δF = 0.0 + for pm in 1:para_num + ∂ρt_T_δV = δρt_δV[cm][tm] |> vec2mat + ∂xδρt_T_δV = ∂xδρt_δV[pm][cm][tm] |> vec2mat + term1 = tr(∂xδρt_T_δV * L1_tidle[pm]) + term2 = tr(∂ρt_T_δV * L2_tidle[pm]) + δF = δF + obj.W[pm,pm]*(1.0/F_T[pm,pm]/F_T[pm,pm])*((2*term1-term2) |> real) + end + δF = δF*coeff + dynamics.data.ctrl[cm][tm] = dynamics.data.ctrl[cm][tm] + alg.epsilon*δF + end + end + end +end diff --git a/src/Algorithm/Iterative.jl b/src/Algorithm/Iterative.jl new file mode 100644 index 0000000..46c9d98 --- /dev/null +++ b/src/Algorithm/Iterative.jl @@ -0,0 +1,43 @@ +function update!(opt::StateOpt, alg::Iterative, obj, dynamics, output) + (; max_episode) = alg + + rho, drho = evolve(dynamics) + f = QFIM(rho, drho) + + set_f!(output, f[1,1]) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f[1,1]) + show(opt, output, obj) + + f_list = [f[1,1]] + idx = 0 + ## single-parameter scenario + for ei in 1:(max_episode-1) + rho, drho = evolve(dynamics) + f, LD = QFIM(rho, drho, exportLD=true) + M1 = d_DualMap(LD[1], dynamics.data.K, dynamics.data.dK) + M2 = DualMap(LD[1]*LD[1], dynamics.data.K) + M = 2*M1[1] - M2 + value, vec = eigen(M) + val, idx = findmax(real(value)) + psi0 = vec[:, idx] + dynamics.data.ψ0 = psi0 + + set_f!(output, f[1,1]) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f[1,1], ei) + show(output, obj) + end + set_io!(output, f[1,1]) +end + +function DualMap(L, K) + return [Ki'*L*Ki for Ki in K] |> sum +end + +function d_DualMap(L, K, dK) + K_num = length(K) + para_num = length(dK[1]) + Lambda = [[dK[i][j]' * L * K[i] + K[i]' * L * dK[i][j] for i in 1:K_num] |> sum for j in 1:para_num] + return Lambda +end diff --git a/src/Algorithm/NM.jl b/src/Algorithm/NM.jl new file mode 100644 index 0000000..d20a17f --- /dev/null +++ b/src/Algorithm/NM.jl @@ -0,0 +1,152 @@ +function update!(opt::StateOpt, alg::NM, obj, dynamics, output) + (; max_episode, p_num, ini_state, ar, ae, ac, as0) = alg + if ismissing(ini_state) + ini_state = [opt.psi] + end + dim = length(dynamics.data.ψ0) + nelder_mead = repeat(dynamics, p_num) + + # initialize + if length(ini_state) > p_num + ini_state = [ini_state[i] for i in 1:p_num] + end + for pj in 1:length(ini_state) + nelder_mead[pj].data.ψ0 = [ini_state[pj][i] for i in 1:dim] + end + for pj in (length(ini_state)+1):p_num + r_ini = 2*rand(opt.rng, dim)-ones(dim) + r = r_ini/norm(r_ini) + phi = 2*pi*rand(opt.rng, dim) + nelder_mead[pj].data.ψ0 = [r[i]*exp(1.0im*phi[i]) for i in 1:dim] + end + + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num + p_out[pj], p_fit[pj] = objective(obj, nelder_mead[pj]) + end + sort_ind = sortperm(p_fit, rev=true) + + set_f!(output, p_out[1]) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, p_out[1]) + show(opt, output, obj) + + f_list = [p_out[1]] + idx = 0 + for ei in 1:(max_episode-1) + # calculate the average vector + vec_ave = zeros(ComplexF64, dim) + for ni in 1:dim + vec_ave[ni] = [nelder_mead[pk].data.ψ0[ni] for pk in 1:(p_num-1)] |> sum + vec_ave[ni] = vec_ave[ni]/(p_num-1) + end + vec_ave = vec_ave/norm(vec_ave) + + # reflection + vec_ref = zeros(ComplexF64, dim) + for nj in 1:dim + vec_ref[nj] = vec_ave[nj] + ar*(vec_ave[nj]-nelder_mead[sort_ind[end]].data.ψ0[nj]) + end + vec_ref = vec_ref/norm(vec_ref) + dynamics_copy = set_state(dynamics, vec_ref) + fr_out, fr = objective(obj, dynamics_copy) + + if fr > p_fit[sort_ind[1]] + # expansion + vec_exp = zeros(ComplexF64, dim) + for nk in 1:dim + vec_exp[nk] = vec_ave[nk] + ae*(vec_ref[nk]-vec_ave[nk]) + end + vec_exp = vec_exp/norm(vec_exp) + dynamics_copy = set_state(dynamics, vec_exp) + fe_out, fe = objective(obj, dynamics_copy) + if fe <= fr + for np in 1:dim + nelder_mead[sort_ind[end]].data.ψ0[np] = vec_ref[np] + end + p_fit[sort_ind[end]] = fr + p_out[sort_ind[end]] = fr_out + sort_ind = sortperm(p_fit, rev=true) + else + for np in 1:dim + nelder_mead[sort_ind[end]].data.ψ0[np] = vec_exp[np] + end + p_fit[sort_ind[end]] = fe + p_out[sort_ind[end]] = fe_out + sort_ind = sortperm(p_fit, rev=true) + end + elseif fr < p_fit[sort_ind[end-1]] + # constraction + if fr <= p_fit[sort_ind[end]] + # inside constraction + vec_ic = zeros(ComplexF64, dim) + for nl in 1:dim + vec_ic[nl] = vec_ave[nl] - ac*(vec_ave[nl]-nelder_mead[sort_ind[end]].data.ψ0[nl]) + end + vec_ic = vec_ic/norm(vec_ic) + dynamics_copy = set_state(dynamics, vec_ic) + fic_out, fic = objective(obj, dynamics_copy) + if fic > p_fit[sort_ind[end]] + for np in 1:dim + nelder_mead[sort_ind[end]].data.ψ0[np] = vec_ic[np] + end + p_fit[sort_ind[end]] = fic + p_out[sort_ind[end]] = fic_out + sort_ind = sortperm(p_fit, rev=true) + else + # shrink + vec_first = [nelder_mead[sort_ind[1]].data.ψ0[i] for i in 1:dim] + for pk in 1:p_num + for nq in 1:dim + nelder_mead[pk].data.ψ0[nq] = vec_first[nq] + as0*(nelder_mead[pk].data.ψ0[nq]-vec_first[nq]) + end + nelder_mead[pk].data.ψ0 = nelder_mead[pk].data.ψ0/norm(nelder_mead[pk].data.ψ0) + p_out[pk], p_fit[pk] = objective(obj, nelder_mead[pk]) + end + sort_ind = sortperm(p_fit, rev=true) + end + else + # outside constraction + vec_oc = zeros(ComplexF64, dim) + for nn in 1:dim + vec_oc[nn] = vec_ave[nn] + ac*(vec_ref[nn]-vec_ave[nn]) + end + vec_oc = vec_oc/norm(vec_oc) + dynamics_copy = set_state(dynamics, vec_oc) + foc_out, foc = objective(obj, dynamics_copy) + if foc >= fr + for np in 1:dim + nelder_mead[sort_ind[end]].data.ψ0[np] = vec_oc[np] + end + p_fit[sort_ind[end]] = foc + p_out[sort_ind[end]] = foc_out + sort_ind = sortperm(p_fit, rev=true) + else + # shrink + vec_first = [nelder_mead[sort_ind[1]].data.ψ0[i] for i in 1:dim] + for pk in 1:p_num + for nq in 1:dim + nelder_mead[pk].data.ψ0[nq] = vec_first[nq] + as0*(nelder_mead[pk].data.ψ0[nq]-vec_first[nq]) + end + nelder_mead[pk].data.ψ0 = nelder_mead[pk].data.ψ0/norm(nelder_mead[pk].data.ψ0) + p_out[pk], p_fit[pk] = objective(obj, nelder_mead[pk]) + end + sort_ind = sortperm(p_fit, rev=true) + end + end + else + for np in 1:dim + nelder_mead[sort_ind[end]].data.ψ0[np] = vec_ref[np] + end + p_fit[sort_ind[end]] = fr + p_out[sort_ind[end]] = fr_out + sort_ind = sortperm(p_fit, rev=true) + end + idx = findmax(p_fit)[2] + set_f!(output, p_out[idx]) + set_buffer!(output, transpose(nelder_mead[sort_ind[1]].data.ψ0)) + set_io!(output, p_out[idx], ei) + show(output, obj) + end + set_io!(output, p_out[idx]) +end diff --git a/src/Algorithm/PSO.jl b/src/Algorithm/PSO.jl new file mode 100644 index 0000000..578524c --- /dev/null +++ b/src/Algorithm/PSO.jl @@ -0,0 +1,964 @@ +#### control optimization #### +function update!(opt::ControlOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.ctrl,],) + end + ini_particle = ini_particle[1] + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) + pbest = zeros(ctrl_num, ctrl_length, p_num) + gbest = zeros(ctrl_num, ctrl_length) + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialize + initial_ctrl!(opt, ini_particle, particles, p_num, opt.rng) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, dynamics.data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + + for ei = 1:(max_episode[1]-1) + for pj = 1:p_num + f_out, f_now = objective(obj, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di = 1:ctrl_num + for ni = 1:ctrl_length + pbest[di, ni, pj] = particles[pj].data.ctrl[di][ni] + end + end + end + end + + for pj = 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj = 1:ctrl_num + for nj = 1:ctrl_length + gbest[dj, nj] = pbest[dj, nj, pj] + end + end + end + end + + for pk = 1:p_num + control_coeff_pre = [zeros(ctrl_length) for i = 1:ctrl_num] + for dk = 1:ctrl_num + for ck = 1:ctrl_length + control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] + velocity[dk, ck, pk] = + c0 * velocity[dk, ck, pk] + + c1 * + rand(opt.rng) * + (pbest[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + +c2 * rand(opt.rng) * (gbest[dk, ck] - particles[pk].data.ctrl[dk][ck]) + particles[pk].data.ctrl[dk][ck] += velocity[dk, ck, pk] + end + end + + for dm = 1:ctrl_num + for cm = 1:ctrl_length + particles[pk].data.ctrl[dm][cm] = ( + x -> + x < opt.ctrl_bound[1] ? opt.ctrl_bound[1] : + x > opt.ctrl_bound[2] ? opt.ctrl_bound[2] : x + )( + particles[pk].data.ctrl[dm][cm], + ) + velocity[dm, cm, pk] = + particles[pk].data.ctrl[dm][cm] - control_coeff_pre[dm][cm] + end + end + end + if ei % max_episode[2] == 0 + dynamics.data.ctrl = [gbest[k, :] for k = 1:ctrl_num] + particles = repeat(dynamics, p_num) + end + + set_f!(output, fit_out) + set_buffer!(output, gbest) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state optimization #### +function update!(opt::StateOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.psi], ) + end + ini_particle = ini_particle[1] + dim = length(dynamics.data.ψ0) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) + pbest = zeros(ComplexF64, dim, p_num) + gbest = zeros(ComplexF64, dim) + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_state!(ini_particle, particles, p_num, opt.rng) + + f_ini, f_comp = objective(obj, dynamics) + set_f!(output, f_ini) + set_buffer!(output, transpose(dynamics.data.ψ0)) + set_io!(output, f_ini) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + f_out, f_now = objective(obj, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:dim + pbest[di,pj] = particles[pj].data.ψ0[di] + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:dim + gbest[dj] = pbest[dj,pj] + end + end + end + + for pk in 1:p_num + psi_pre = zeros(ComplexF64, dim) + for dk in 1:dim + psi_pre[dk] = particles[pk].data.ψ0[dk] + velocity[dk, pk] = c0*velocity[dk, pk] + c1*rand(opt.rng)*(pbest[dk, pk] - particles[pk].data.ψ0[dk]) + c2*rand(opt.rng)*(gbest[dk] - particles[pk].data.ψ0[dk]) + particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity[dk, pk] + end + particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) + + for dm in 1:dim + velocity[dm, pk] = particles[pk].data.ψ0[dm] - psi_pre[dm] + end + end + if ei%max_episode[2] == 0 + dynamics.data.ψ0 = [gbest[i] for i in 1:dim] + particles = repeat(dynamics, p_num) + end + set_f!(output, fit_out) + set_buffer!(output, transpose(gbest)) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### projective measurement optimization #### +function update!(opt::Mopt_Projection, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.M], ) + end + ini_particle = ini_particle[1] + dim = size(dynamics.data.ρ0)[1] + M_num = length(opt.M) + particles = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) + pbest = zeros(ComplexF64, M_num, dim, p_num) + gbest = [zeros(ComplexF64, dim) for i in 1:M_num] + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_M!(ini_particle, particles, dim, p_num, M_num, opt.rng) + + M = [particles[1][i]*(particles[1][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, M) + set_io!(output, f_ini, f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + M = [particles[pj][i]*(particles[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, dynamics) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:M_num + for ni in 1:dim + pbest[di,ni,pj] = particles[pj][di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:M_num + for nj in 1:dim + gbest[dj][nj] = pbest[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + meas_pre = [zeros(ComplexF64, dim) for i in 1:M_num] + for dk in 1:M_num + for ck in 1:dim + meas_pre[dk][ck] = particles[pk][dk][ck] + + velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(opt.rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest[dk][ck] - particles[pk][dk][ck]) + particles[pk][dk][ck] += velocity[dk, ck, pk] + end + end + particles[pk] = gramschmidt(particles[pk]) + + for dm in 1:M_num + for cm in 1:dim + velocity[dm, cm, pk] = particles[pk][dm][cm] - meas_pre[dm][cm] + end + end + end + M = [gbest[i]*(gbest[i])' for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### find the optimal linear combination of a given set of POVM #### +function update!(opt::Mopt_LinearComb, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + (; B, POVM_basis, M_num) = opt + basis_num = length(POVM_basis) + if ismissing(ini_particle) + ini_particle = ( [B], ) + end + ini_particle = ini_particle[1] + particles = [[zeros(basis_num) for j in 1:M_num] for i in 1:p_num] + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity = 0.1*rand(opt.rng, Float64, M_num, basis_num, p_num) + pbest = zeros(Float64, M_num, basis_num, p_num) + gbest = zeros(Float64, M_num, basis_num) + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_LinearComb!(ini_particle, particles, basis_num, M_num, p_num, opt.rng) + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + + M = [sum([particles[1][i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, M) + set_io!(output, f_ini, f_povm, f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + M = [sum([particles[pj][i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, dynamics) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:M_num + for ni in 1:basis_num + pbest[di,ni,pj] = particles[pj][di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:M_num + for nj in 1:basis_num + gbest[dj, nj] = pbest[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + meas_pre = [zeros(Float64, basis_num) for i in 1:M_num] + for dk in 1:M_num + for ck in 1:basis_num + meas_pre[dk][ck] = particles[pk][dk][ck] + + velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(opt.rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest[dk, ck] - particles[pk][dk][ck]) + particles[pk][dk][ck] += velocity[dk, ck, pk] + end + end + bound_LC_coeff!(particles[pk], opt.rng) + + for dm in 1:M_num + for cm in 1:basis_num + velocity[dm, cm, pk] = particles[pk][dm][cm] - meas_pre[dm][cm] + end + end + end + M = [sum([gbest[i,j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### find the optimal rotated measurement of a given set of POVM #### +function update!(opt::Mopt_Rotation, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.s], ) + end + ini_particle = ini_particle[1] + (; s, POVM_basis, Lambda) = opt + M_num = length(POVM_basis) + dim = size(dynamics.data.ρ0)[1] + suN = suN_generator(dim) + Lambda = Matrix{ComplexF64}[] + append!(Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + append!(Lambda, [suN[i] for i in 1:length(suN)]) + + # if ismissing(Lambda) + # Lambda = Matrix{ComplexF64}[] + # append!(Lambda, [Matrix{ComplexF64}(I,dim,dim)]) + # append!(Lambda, [suN[i] for i in 1:length(suN)]) + # end + + particles = repeat(s, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity = 0.1*rand(opt.rng, Float64, dim^2, p_num) + pbest = zeros(Float64, dim^2, p_num) + gbest = zeros(Float64, dim^2) + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + particles = [zeros(dim^2) for i in 1:p_num] + initial_Rotation!(ini_particle, particles, dim, p_num, opt.rng) + + obj_QFIM = QFIM_obj(obj) + f_opt, f_comp = objective(obj_QFIM, dynamics) + obj_POVM = set_M(obj, POVM_basis) + f_povm, f_comp = objective(obj_POVM, dynamics) + + U = rotation_matrix(particles[1], Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + set_f!(output, f_ini) + set_buffer!(output, M) + set_io!(output, f_ini, f_povm, f_opt) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + U = rotation_matrix(particles[pj], Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, dynamics) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for ni in 1:dim^2 + pbest[ni,pj] = particles[pj][ni] + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for nj in 1:dim^2 + gbest[nj] = pbest[nj,pj] + end + end + end + + for pk in 1:p_num + meas_pre = zeros(Float64, dim^2) + + for ck in 1:dim^2 + meas_pre[ck] = particles[pk][ck] + + velocity[ck, pk] = c0*velocity[ck, pk] + c1*rand(opt.rng)*(pbest[ck, pk] - particles[pk][ck]) + c2*rand(opt.rng)*(gbest[ck] - particles[pk][ck]) + particles[pk][ck] += velocity[ck, pk] + end + + bound_rot_coeff!(particles[pk]) + + for cm in 1:dim^2 + velocity[cm, pk] = particles[pk][cm] - meas_pre[cm] + end + end + U = rotation_matrix(gbest, Lambda) + M = [U*POVM_basis[i]*U' for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state and control optimization #### +function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.psi], [opt.ctrl,]) + end + psi0, ctrl0 = ini_particle + dim = length(dynamics.data.ψ0) + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) + pbest_state = zeros(ComplexF64, dim, p_num) + gbest_state = zeros(ComplexF64, dim) + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) + pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) + gbest_ctrl = zeros(ctrl_num, ctrl_length) + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_state!(psi0, particles, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) + + dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i=1:ctrl_num]) + f_noctrl, f_comp = objective(obj, dynamics_copy) + f_ini, f_comp = objective(obj, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, transpose(particles[1].data.ψ0), particles[1].data.ctrl) + set_io!(output, f_noctrl, f_ini) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + f_out, f_now = objective(obj, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:dim + pbest_state[di,pj] = particles[pj].data.ψ0[di] + end + + for di in 1:ctrl_num + for ni in 1:ctrl_length + pbest_ctrl[di,ni,pj] = particles[pj].data.ctrl[di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:dim + gbest_state[dj] = pbest_state[dj,pj] + end + + for dj in 1:ctrl_num + for nj in 1:ctrl_length + gbest_ctrl[dj, nj] = pbest_ctrl[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + psi_pre = zeros(ComplexF64, dim) + for dk in 1:dim + psi_pre[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] + end + particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) + for dm in 1:dim + velocity_state[dm, pk] = particles[pk].data.ψ0[dm] - psi_pre[dm] + end + + control_coeff_pre = [zeros(ctrl_length) for i in 1:ctrl_num] + for dk in 1:ctrl_num + for ck in 1:ctrl_length + control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] + end + end + + for dm in 1:ctrl_num + for cm in 1:ctrl_length + particles[pk].data.ctrl[dm][cm] = (x-> x < opt.ctrl_bound[1] ? opt.ctrl_bound[1] : x > opt.ctrl_bound[2] ? opt.ctrl_bound[2] : x)(particles[pk].data.ctrl[dm][cm]) + velocity_ctrl[dm, cm, pk] = particles[pk].data.ctrl[dm][cm] - control_coeff_pre[dm][cm] + end + end + end + set_f!(output, fit_out) + set_buffer!(output, transpose(gbest_state), gbest_ctrl) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state and measurement optimization #### +function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.psi], [opt.M]) + end + psi0, measurement0 = ini_particle + dim = length(dynamics.data.ψ0) + M_num = length(opt.M) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) + pbest_state = zeros(ComplexF64, dim, p_num) + gbest_state = zeros(ComplexF64, dim) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) + pbest_meas = zeros(ComplexF64, M_num, dim, p_num) + gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_state!(psi0, particles, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, transpose(particles[1].data.ψ0), M) + set_io!(output, f_ini) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:dim + pbest_state[di,pj] = particles[pj].data.ψ0[di] + end + + for di in 1:M_num + for ni in 1:dim + pbest_meas[di,ni,pj] = C_all[pj][di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:dim + gbest_state[dj] = pbest_state[dj,pj] + end + + for dj in 1:M_num + for nj in 1:dim + gbest_meas[dj][nj] = pbest_meas[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + psi_pre = zeros(ComplexF64, dim) + for dk in 1:dim + psi_pre[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] + end + particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) + for dm in 1:dim + velocity_state[dm, pk] = particles[pk].data.ψ0[dm] - psi_pre[dm] + end + + meas_pre = [zeros(ComplexF64, dim) for i in 1:M_num] + for dk in 1:M_num + for ck in 1:dim + meas_pre[dk][ck] = C_all[pk][dk][ck] + + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] + end + end + C_all[pk] = gramschmidt(C_all[pk]) + + for dm in 1:M_num + for cm in 1:dim + velocity_meas[dm, cm, pk] = C_all[pk][dm][cm] - meas_pre[dm][cm] + end + end + end + M = [gbest_meas[i]*(gbest_meas[i])' for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, transpose(gbest_state), M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### control and measurement optimization #### +function update!(opt::ControlMeasurementOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.ctrl,], [opt.M]) + end + ctrl0, measurement0 = ini_particle + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + dim = size(dynamics.data.ρ0)[1] + M_num = length(opt.M) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) + pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) + gbest_ctrl = zeros(ctrl_num, ctrl_length) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) + pbest_meas = zeros(ComplexF64, M_num, dim, p_num) + gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, particles[1].data.ctrl, M) + set_io!(output, f_ini) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:ctrl_num + for ni in 1:ctrl_length + pbest_ctrl[di,ni,pj] = particles[pj].data.ctrl[di][ni] + end + end + for di in 1:M_num + for ni in 1:dim + pbest_meas[di,ni,pj] = C_all[pj][di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:ctrl_num + for nj in 1:ctrl_length + gbest_ctrl[dj, nj] = pbest_ctrl[dj,nj,pj] + end + end + for dj in 1:M_num + for nj in 1:dim + gbest_meas[dj][nj] = pbest_meas[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + control_coeff_pre = [zeros(ctrl_length) for i in 1:ctrl_num] + for dk in 1:ctrl_num + for ck in 1:ctrl_length + control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] + end + end + + for dm in 1:ctrl_num + for cm in 1:ctrl_length + particles[pk].data.ctrl[dm][cm] = (x-> x < opt.ctrl_bound[1] ? opt.ctrl_bound[1] : x > opt.ctrl_bound[2] ? opt.ctrl_bound[2] : x)(particles[pk].data.ctrl[dm][cm]) + velocity_ctrl[dm, cm, pk] = particles[pk].data.ctrl[dm][cm] - control_coeff_pre[dm][cm] + end + end + + meas_pre = [zeros(ComplexF64, dim) for i in 1:M_num] + for dk in 1:M_num + for ck in 1:dim + meas_pre[dk][ck] = C_all[pk][dk][ck] + + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] + end + end + C_all[pk] = gramschmidt(C_all[pk]) + + for dm in 1:M_num + for cm in 1:dim + velocity_meas[dm, cm, pk] = C_all[pk][dm][cm] - meas_pre[dm][cm] + end + end + end + M = [gbest_meas[i]*(gbest_meas[i])' for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, gbest_ctrl, M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end + +#### state, control and measurement optimization #### +function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, output) + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg + if ismissing(ini_particle) + ini_particle = ([opt.psi], [opt.ctrl,], [opt.M]) + end + psi0, ctrl0, measurement0 = ini_particle + ctrl_length = length(dynamics.data.ctrl[1]) + ctrl_num = length(dynamics.data.Hc) + dim = length(dynamics.data.ψ0) + M_num = length(opt.M) + particles = repeat(dynamics, p_num) + + if typeof(max_episode) == Int + max_episode = [max_episode, max_episode] + end + + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) + pbest_state = zeros(ComplexF64, dim, p_num) + gbest_state = zeros(ComplexF64, dim) + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) + pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) + gbest_ctrl = zeros(ctrl_num, ctrl_length) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) + pbest_meas = zeros(ComplexF64, M_num, dim, p_num) + gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] + + p_fit, p_out = zeros(p_num), zeros(p_num) + fit, fit_out = 0.0, 0.0 + + # initialization + initial_state!(psi0, particles, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) + C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) + + M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_ini, f_comp = objective(obj_copy, dynamics) + + set_f!(output, f_ini) + set_buffer!(output, transpose(particles[1].data.ψ0), particles[1].data.ctrl, M) + set_io!(output, f_ini) + show(opt, output, obj) + + for ei in 1:(max_episode[1]-1) + for pj in 1:p_num + M = [C_all[pj][i]*(C_all[pj][i])' for i in 1:M_num] + obj_copy = set_M(obj, M) + f_out, f_now = objective(obj_copy, particles[pj]) + if f_now > p_fit[pj] + p_fit[pj] = f_now + p_out[pj] = f_out + for di in 1:dim + pbest_state[di,pj] = particles[pj].data.ψ0[di] + end + for di in 1:ctrl_num + for ni in 1:ctrl_length + pbest_ctrl[di,ni,pj] = particles[pj].data.ctrl[di][ni] + end + end + for di in 1:M_num + for ni in 1:dim + pbest_meas[di,ni,pj] = C_all[pj][di][ni] + end + end + end + end + + for pj in 1:p_num + if p_fit[pj] > fit + fit = p_fit[pj] + fit_out = p_out[pj] + for dj in 1:dim + gbest_state[dj] = pbest_state[dj,pj] + end + for dj in 1:ctrl_num + for nj in 1:ctrl_length + gbest_ctrl[dj, nj] = pbest_ctrl[dj,nj,pj] + end + end + for dj in 1:M_num + for nj in 1:dim + gbest_meas[dj][nj] = pbest_meas[dj,nj,pj] + end + end + end + end + + for pk in 1:p_num + psi_pre = zeros(ComplexF64, dim) + for dk in 1:dim + psi_pre[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] + end + particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) + for dm in 1:dim + velocity_state[dm, pk] = particles[pk].data.ψ0[dm] - psi_pre[dm] + end + + control_coeff_pre = [zeros(ctrl_length) for i in 1:ctrl_num] + for dk in 1:ctrl_num + for ck in 1:ctrl_length + control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] + end + end + + for dm in 1:ctrl_num + for cm in 1:ctrl_length + particles[pk].data.ctrl[dm][cm] = (x-> x < opt.ctrl_bound[1] ? opt.ctrl_bound[1] : x > opt.ctrl_bound[2] ? opt.ctrl_bound[2] : x)(particles[pk].data.ctrl[dm][cm]) + velocity_ctrl[dm, cm, pk] = particles[pk].data.ctrl[dm][cm] - control_coeff_pre[dm][cm] + end + end + + meas_pre = [zeros(ComplexF64, dim) for i in 1:M_num] + for dk in 1:M_num + for ck in 1:dim + meas_pre[dk][ck] = C_all[pk][dk][ck] + + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] + end + end + C_all[pk]= gramschmidt(C_all[pk]) + + for dm in 1:M_num + for cm in 1:dim + velocity_meas[dm, cm, pk] = C_all[pk][dm][cm] - meas_pre[dm][cm] + end + end + end + M = [gbest_meas[i]*(gbest_meas[i])' for i in 1:M_num] + set_f!(output, fit_out) + set_buffer!(output, transpose(gbest_state), gbest_ctrl, M) + set_io!(output, fit_out, ei) + show(output, obj) + end + set_io!(output, output.f_list[end]) +end diff --git a/src/common/adaptive.jl b/src/Common/AdaptiveScheme.jl similarity index 73% rename from src/common/adaptive.jl rename to src/Common/AdaptiveScheme.jl index 70ac11d..2ffe775 100644 --- a/src/common/adaptive.jl +++ b/src/Common/AdaptiveScheme.jl @@ -1,22 +1,44 @@ -function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save_file=false, max_episode::Int=1000, eps::Float64=1e-8, - Hc::Union{Vector,Nothing}=nothing, ctrl::Union{Vector,Nothing}=nothing, decay::Union{Vector,Nothing}=nothing, - M::Union{AbstractVector,Nothing}=nothing, W::Union{Matrix,Nothing}=nothing) +@doc raw""" + + Adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; savefile=false, max_episode::Int=1000, eps::Float64=1e-8, Hc=missing, ctrl=missing, decay=missing, M=missing, W=missing) + +In QuanEstimation, the Hamiltonian of the adaptive system should be written as +``H(\textbf{x}+\textbf{u})`` with ``\textbf{x}`` the unknown parameters and ``\textbf{u}`` +the tunable parameters. The tunable parameters ``\textbf{u}`` are used to let the +Hamiltonian work at the optimal point ``\textbf{x}_{\mathrm{opt}}``. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho0`: Density matrix. +- `tspan`: The experimental results obtained in practice. +- `H`: Free Hamiltonian with respect to the values in x. +- `dH`: Derivatives of the free Hamiltonian with respect to the unknown parameters to be estimated. +- `savefile`: Whether or not to save all the posterior distributions. +- `max_episode`: The number of episodes. +- `eps`: Machine epsilon. +- `Hc`: Control Hamiltonians. +- `ctrl`: Control coefficients. +- `decay`: Decay operators and the corresponding decay rates. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `W`: Whether or not to save all the posterior distributions. +""" +function Adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; savefile=false, max_episode::Int=1000, eps::Float64=1e-8, + Hc=missing, ctrl=missing, decay=missing, M=missing, W=missing) dim = size(rho0)[1] para_num = length(x) - if M == nothing + if ismissing(M) M = SIC(size(rho0)[1]) end - if decay == nothing + if ismissing(decay) decay_opt = [zeros(ComplexF64, dim, dim)] gamma = [0.0] else decay_opt = [decay[i][1] for i in 1:len(decay)] gamma = [decay[i][2] for i in 1:len(decay)] end - if Hc == nothing + if ismissing(Hc) Hc = [zeros(ComplexF64, dim, dim)] ctrl = [zeros(length(tspan)-1)] - elseif ctrl == nothing + elseif ismissing(ctrl) ctrl = [zeros(length(tspan)-1) for j in range(length(Hc))] else ctrl_length = length(ctrl) @@ -33,7 +55,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save end end end - if W == nothing + if ismissing(W) W = zeros(para_num, para_num) end @@ -63,6 +85,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save rho_tp, drho_tp = evolve(dynamics) rho[hj] = rho_tp end + println("The tunable parameter is $u") print("Please enter the experimental result: ") enter = readline() @@ -88,7 +111,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save append!(y, Int(res_exp-1)) append!(pout, [p]) end - if save_file == false + if savefile == false open("pout.csv","w") do f writedlm(f, [p]) end @@ -168,7 +191,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save append!(y, Int(res_exp-1)) append!(pout, [p]) end - if save_file == false + if savefile == false open("pout.csv","w") do f writedlm(f, [p]) end @@ -192,17 +215,35 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, tspan, H, dH; save end end - -function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; save_file=false, max_episode::Int=1000, - eps::Float64=1e-8, M::Union{AbstractVector,Nothing}=nothing, W::Union{Matrix,Nothing}=nothing) +@doc raw""" + + Adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; savefile=false, max_episode::Int=1000, eps::Float64=1e-8, M=missing, W=missing) + +In QuanEstimation, the Hamiltonian of the adaptive system should be written as +``H(\textbf{x}+\textbf{u})`` with ``\textbf{x}`` the unknown parameters and ``\textbf{u}`` +the tunable parameters. The tunable parameters ``\textbf{u}`` are used to let the +Hamiltonian work at the optimal point ``\textbf{x}_{\mathrm{opt}}``. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho0`: Density matrix. +- `K`: Kraus operator(s) with respect to the values in x. +- `dK`: Derivatives of the Kraus operator(s) with respect to the unknown parameters to be estimated. +- `savefile`: Whether or not to save all the posterior distributions. +- `max_episode`: The number of episodes. +- `eps`: Machine epsilon. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `W`: Whether or not to save all the posterior distributions. +""" +function Adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; savefile=false, max_episode::Int=1000, + eps::Float64=1e-8, M=missing, W=missing) dim = size(rho0)[1] para_num = length(x) - if W == nothing + if ismissing(W) W = zeros(para_num, para_num) end - if M == nothing + if ismissing(M) M = SIC(size(rho0)[1]) end @@ -253,7 +294,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; save_file=f append!(y, Int(res_exp-1)) append!(pout, [p]) end - if save_file == false + if savefile == false open("pout.csv","w") do f writedlm(f, [p]) end @@ -335,7 +376,7 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; save_file=f append!(y, Int(res_exp+1)) append!(pout, [p]) end - if save_file == false + if savefile == false open("pout.csv","w") do f writedlm(f, [p]) end @@ -359,16 +400,16 @@ function adaptive(x::AbstractVector, p, rho0::AbstractMatrix, K, dK; save_file=f end end -mutable struct adaptMZI +mutable struct Adapt_MZI x p rho0 end -function online(apt::adaptMZI; output::String = "phi") +function online(apt::Adapt_MZI; output::String = "phi") (;x, p, rho0) = apt N = Int(sqrt(size(rho0,1))) - 1 - a = destroy(N+1)' |> sparse + a = destroy(N+1) |> sparse adaptMZI_online(x, p, rho0, a, output) end @@ -384,23 +425,24 @@ function brgd(n) return deepcopy(vcat(L0,L1)) end -function offline(apt::adaptMZI, alg;eps = GLOBAL_EPS) +function offline(apt::Adapt_MZI, alg; eps = GLOBAL_EPS, seed=1234) + rng = MersenneTwister(seed) (;x,p,rho0) = apt N = Int(sqrt(size(rho0,1))) - 1 - a = destroy(N+1)' |> sparse + a = destroy(N+1) |> sparse comb = brgd(N)|>x->[[parse(Int, s) for s in ss] for ss in x] if alg isa DE - (;p_num,ini_population,c,cr,rng,max_episode) = alg + (;p_num,ini_population,c,cr,max_episode) = alg if ismissing(ini_population) ini_population = ([apt.rho0],) end - DE_DeltaPhiOpt(x,p,rho0,a,comb,p_num,ini_population[1],c,cr,rng.seed,max_episode,eps) + DE_deltaphiOpt(x,p,rho0,a,comb,p_num,ini_population[1],c,cr,rng,max_episode,eps) elseif alg isa PSO - (;p_num,ini_particle,c0,c1,c2,rng,max_episode) = alg + (;p_num,ini_particle,c0,c1,c2,max_episode) = alg if ismissing(ini_particle) ini_particle = ([apt.rho0],) end - PSO_DeltaPhiOpt(x,p,rho0,a,comb,p_num,ini_particle[1],c0,c1,c2,rng.seed,max_episode,eps) + PSO_deltaphiOpt(x,p,rho0,a,comb,p_num,ini_particle[1],c0,c1,c2,rng,max_episode,eps) end end @@ -546,70 +588,75 @@ function logarithmic(number, N) return res end -function DE_DeltaPhiOpt(x, p, rho0, a, comb, popsize, ini_population, c, cr, seed, max_episode, eps) - Random.seed!(seed) +function DE_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_population, c, cr, rng::AbstractRNG, max_episode, eps) N = size(a)[1] - 1 - DeltaPhi = [zeros(N) for i in 1:popsize] + deltaphi = [zeros(N) for i in 1:p_num] # initialize res = logarithmic(2.0*pi, N) - if length(ini_population) > popsize - ini_population = [ini_population[i] for i in 1:popsize] + if length(ini_population) > p_num + ini_population = [ini_population[i] for i in 1:p_num] end for pj in 1:length(ini_population) - DeltaPhi[pj] = [ini_population[pj][i] for i in 1:N] + deltaphi[pj] = [ini_population[pj][i] for i in 1:N] end - for pk in (length(ini_population)+1):popsize - DeltaPhi[pk] = [res[i]+rand() for i in 1:N] + for pk in (length(ini_population)+1):p_num + deltaphi[pk] = [res[i]+rand(rng) for i in 1:N] end - p_fit = [0.0 for i in 1:popsize] + p_fit = [0.0 for i in 1:p_num] for pl in 1:N - p_fit[pl] = adaptMZI_offline(DeltaPhi[pl], x, p, rho0, a, comb, eps) + p_fit[pl] = adaptMZI_offline(deltaphi[pl], x, p, rho0, a, comb, eps) end f_ini = maximum(p_fit) f_list = [f_ini] for ei in 1:(max_episode-1) - for pm in 1:popsize + for pm in 1:p_num #mutations - mut_num = sample(1:popsize, 3, replace=false) - DeltaPhi_mut = [0.0 for i in 1:N] + mut_num = sample(rng, 1:p_num, 3, replace=false) + deltaphi_mut = [0.0 for i in 1:N] for ci in 1:N - DeltaPhi_mut[ci] = DeltaPhi[mut_num[1]][ci]+c*(DeltaPhi[mut_num[2]][ci]-DeltaPhi[mut_num[3]][ci]) + deltaphi_mut[ci] = deltaphi[mut_num[1]][ci]+c*(deltaphi[mut_num[2]][ci]-deltaphi[mut_num[3]][ci]) end #crossover - DeltaPhi_cross = [0.0 for i in 1:N] - cross_int = sample(1:N, 1, replace=false)[1] + deltaphi_cross = [0.0 for i in 1:N] + cross_int = sample(rng, 1:N, 1, replace=false)[1] for cj in 1:N - rand_num = rand() + rand_num = rand(rng) if rand_num <= cr - DeltaPhi_cross[cj] = DeltaPhi_mut[cj] + deltaphi_cross[cj] = deltaphi_mut[cj] else - DeltaPhi_cross[cj] = DeltaPhi[pm][cj] + deltaphi_cross[cj] = deltaphi[pm][cj] end - DeltaPhi_cross[cross_int] = DeltaPhi_mut[cross_int] + deltaphi_cross[cross_int] = deltaphi_mut[cross_int] end #selection for cm in 1:N - DeltaPhi_cross[cm] = (x-> x < 0.0 ? 0.0 : x > pi ? pi : x)(DeltaPhi_cross[cm]) + deltaphi_cross[cm] = (x-> x < 0.0 ? 0.0 : x > pi ? pi : x)(deltaphi_cross[cm]) end - f_cross = adaptMZI_offline(DeltaPhi_cross, x, p, rho0, a, comb, eps) + f_cross = adaptMZI_offline(deltaphi_cross, x, p, rho0, a, comb, eps) if f_cross > p_fit[pm] p_fit[pm] = f_cross for ck in 1:N - DeltaPhi[pm][ck] = DeltaPhi_cross[ck] + deltaphi[pm][ck] = deltaphi_cross[ck] end end end - println(maximum(p_fit)) - println(DeltaPhi[findmax(p_fit)[2]]) append!(f_list, maximum(p_fit)) end - return DeltaPhi[findmax(p_fit)[2]] + open("deltaphi.csv","w") do m + writedlm(m, deltaphi[findmax(p_fit)[2]]) + end + open("f.csv","w") do n + writedlm(n, f_list) + end + return deltaphi[findmax(p_fit)[2]] end -function PSO_DeltaPhiOpt(x, p, rho0, a, comb, particle_num, ini_particle, c0, c1, c2, seed, max_episode, eps) - Random.seed!(seed) +DE_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_population, c, cr, seed::Number, max_episode, eps) = +DE_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_population, c, cr, MersenneTwister(seed), max_episode, eps) + +function PSO_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_particle, c0, c1, c2, rng::AbstractRNG, max_episode, eps) N = size(a)[1] - 1 n = size(a)[1] @@ -617,40 +664,40 @@ function PSO_DeltaPhiOpt(x, p, rho0, a, comb, particle_num, ini_particle, c0, c1 max_episode = [max_episode, max_episode] end - DeltaPhi = [zeros(N) for i in 1:particle_num] - velocity = [zeros(N) for i in 1:particle_num] + deltaphi = [zeros(N) for i in 1:p_num] + velocity = [zeros(N) for i in 1:p_num] # initialize res = logarithmic(2.0*pi, N) - if length(ini_particle) > particle_num - ini_particle = [ini_particle[i] for i in 1:particle_num] + if length(ini_particle) > p_num + ini_particle = [ini_particle[i] for i in 1:p_num] end for pj in 1:length(ini_particle) - DeltaPhi[pj] = [ini_particle[pj][i] for i in 1:N] + deltaphi[pj] = [ini_particle[pj][i] for i in 1:N] end - for pk in (length(ini_particle)+1):particle_num - DeltaPhi[pk] = [res[i]+rand() for i in 1:N] + for pk in (length(ini_particle)+1):p_num + deltaphi[pk] = [res[i]+rand(rng) for i in 1:N] end - for pl in 1:particle_num - velocity[pl] = [0.1*rand() for i in 1:N] + for pl in 1:p_num + velocity[pl] = [0.1*rand(rng) for i in 1:N] end - pbest = [zeros(N) for i in 1:particle_num] + pbest = [zeros(N) for i in 1:p_num] gbest = zeros(N) fit = 0.0 - p_fit = [0.0 for i in 1:particle_num] + p_fit = [0.0 for i in 1:p_num] f_list = [] for ei in 1:(max_episode[1]-1) - for pm in 1:particle_num - f_now = adaptMZI_offline(DeltaPhi[pm], x, p, rho0, a, comb, eps) + for pm in 1:p_num + f_now = adaptMZI_offline(deltaphi[pm], x, p, rho0, a, comb, eps) if f_now > p_fit[pm] p_fit[pm] = f_now for ci in 1:N - pbest[pm][ci] = DeltaPhi[pm][ci] + pbest[pm][ci] = deltaphi[pm][ci] end end end - for pn in 1:particle_num + for pn in 1:p_num if p_fit[pn] > fit fit = p_fit[pn] for cj in 1:N @@ -659,29 +706,35 @@ function PSO_DeltaPhiOpt(x, p, rho0, a, comb, particle_num, ini_particle, c0, c1 end end - for pa in 1:particle_num - DeltaPhi_pre = [0.0 for i in 1:N] + for pa in 1:p_num + deltaphi_pre = [0.0 for i in 1:N] for ck in 1:N - DeltaPhi_pre[ck] = DeltaPhi[pa][ck] - velocity[pa][ck] = c0*velocity[pa][ck] + c1*rand()*(pbest[pa][ck] - DeltaPhi[pa][ck]) - + c2*rand()*(gbest[ck] - DeltaPhi[pa][ck]) - DeltaPhi[pa][ck] += velocity[pa][ck] + deltaphi_pre[ck] = deltaphi[pa][ck] + velocity[pa][ck] = c0*velocity[pa][ck] + c1*rand(rng)*(pbest[pa][ck] - deltaphi[pa][ck]) + + c2*rand(rng)*(gbest[ck] - deltaphi[pa][ck]) + deltaphi[pa][ck] += velocity[pa][ck] end for cn in 1:N - DeltaPhi[pa][cn] = (x-> x < 0.0 ? 0.0 : x > pi ? pi : x)(DeltaPhi[pa][cn]) - velocity[pa][cn] = DeltaPhi[pa][cn] - DeltaPhi_pre[cn] + deltaphi[pa][cn] = (x-> x < 0.0 ? 0.0 : x > pi ? pi : x)(deltaphi[pa][cn]) + velocity[pa][cn] = deltaphi[pa][cn] - deltaphi_pre[cn] end end - println(fit) - println(gbest) append!(f_list, fit) if ei%max_episode[2] == 0 - for pb in 1:particle_num - DeltaPhi[pb] = [gbest[i] for i in 1:N] + for pb in 1:p_num + deltaphi[pb] = [gbest[i] for i in 1:N] end end end + open("deltaphi.csv","w") do m + writedlm(m, gbest) + end + open("f.csv","w") do n + writedlm(n, f_list) + end return gbest end +PSO_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_particle, c0, c1, c2, seed::Number, max_episode, eps) = +PSO_deltaphiOpt(x, p, rho0, a, comb, p_num, ini_particle, c0, c1, c2, MersenneTwister(seed), max_episode, eps) \ No newline at end of file diff --git a/src/Common/BayesEstimation.jl b/src/Common/BayesEstimation.jl new file mode 100644 index 0000000..6981bbb --- /dev/null +++ b/src/Common/BayesEstimation.jl @@ -0,0 +1,461 @@ +""" + + Bayes(x, p, rho, y; M=missing, savefile=false) + +Bayesian estimation. The prior distribution is updated via the posterior distribution obtained by the Bayes’ rule and the estimated value of parameters obtained via the maximum a posteriori probability (MAP). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `y`: The experimental results obtained in practice. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `savefile`: Whether or not to save all the posterior distributions. +""" +function Bayes(x, p, rho, y; M=missing, estimator="mean", savefile=false) + y = y .+ 1 + para_num = length(x) + max_episode = length(y) + if para_num == 1 + #### singleparameter senario #### + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + if savefile == false + x_out = [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + append!(x_out, trapz(x[1], p.*x[1])) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + indx = findmax(p)[2] + append!(x_out, x[1][indx]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") + end + + open("pout.csv","w") do f + writedlm(f, [p]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] + else + p_out, x_out = [], [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + append!(p_out, [p]) + append!(x_out, trapz(x[1], p.*x[1])) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + indx = findmax(p)[2] + append!(p_out, [p]) + append!(x_out, x[1][indx]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") + end + + open("pout.csv","w") do f + writedlm(f, [p_out]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] + end + else + #### multiparameter senario #### + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + if savefile == false + x_out = [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + + p_update = p.*pyx/py + p = p_update + append!(x_out, [integ(x, p)]) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + + p_update = p.*pyx/py + p = p_update + + indx = findmax(p)[2] + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") + end + + open("pout.csv","w") do f + writedlm(f, [p]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] + else + p_out, x_out = [], [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + p_update = p.*pyx/py + p = p_update + + append!(p_out, [p]) + append!(x_out, [integ(x,p)]) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + p_update = p.*pyx/py + p = p_update + + indx = findmax(p)[2] + append!(p_out, [p]) + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") + end + + open("pout.csv","w") do f + writedlm(f, p_out) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] + end + end +end + +""" + + MLE(x, rho, y; M=missing, savefile=false) + +Bayesian estimation. The estimated value of parameters obtained via the maximum likelihood estimation (MLE). +- `x`: The regimes of the parameters for the integral. +- `rho`: Parameterized density matrix. +- `y`: The experimental results obtained in practice. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `savefile`: Whether or not to save all the posterior distributions. +""" +function MLE(x, rho, y; M=missing, savefile=false) + y = y .+ 1 + para_num = length(x) + max_episode = length(y) + if para_num == 1 + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + if savefile == false + x_out = [] + L_out = ones(length(x[1])) + for mi in 1:max_episode + res_exp = y[mi] |> Int + p_tp = real.(tr.(rho.*[M[res_exp]])) + L_out = L_out.*p_tp + indx = findmax(L_out)[2] + append!(x_out, x[1][indx]) + end + + open("Lout.csv","w") do f + writedlm(f, [L_out]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return L_out, x_out[end] + else + L_out, x_out = [], [] + L_tp = ones(length(x[1])) + for mi in 1:max_episode + res_exp = y[mi] |> Int + p_tp = real.(tr.(rho.*[M[res_exp]])) + L_tp = L_tp.*p_tp + + indx = findmax(L_tp)[2] + append!(L_out, [L_tp]) + append!(x_out, x[1][indx]) + end + + open("Lout.csv","w") do f + writedlm(f, L_out) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return L_tp, x_out[end] + end + else + #### multiparameter senario #### + p_shape = [] + for i in 1:para_num + append!(p_shape,length(x[i])) + end + + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + + if savefile == false + x_out = [] + L_out = ones(p_shape...) + for mi in 1:max_episode + res_exp = y[mi] |> Int + p_tp = real.(tr.(rho.*[M[res_exp]])) + L_out = L_out.*p_tp + indx = findmax(L_out)[2] + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + open("Lout.csv","w") do f + writedlm(f, [L_out]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return L_out, x_out[end] + else + L_out, x_out = [], [] + L_tp = ones(p_shape...) + for mi in 1:max_episode + res_exp = y[mi] |> Int + p_tp = real.(tr.(rho.*[M[res_exp]])) + L_tp = L_tp.*p_tp + indx = findmax(L_tp)[2] + append!(L_out, [L_tp]) + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + + open("Lout.csv","w") do f + writedlm(f, L_out) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return L_tp, x_out[end] + end + end +end + +function integ(x, p) + para_num = length(x) + mean = [0.0 for i in 1:para_num] + for i in 1:para_num + p_tp = p + if i == para_num + for si = 1:para_num-1 + p_tp = trapz(x[si], p_tp, Val(1)) + end + + elseif i == 1 + for si = para_num:2 + p_tp = trapz(x[si], p_tp) + end + else + p_tp = trapz(x[end], p_tp) + for si = 1:para_num-1 + p_tp = trapz(x[si], p_tp, Val(1)) + end + end + mean[i] = trapz(x[i], x[i].*p_tp) + end + mean +end + +""" + + BayesCost(x, p, xest, rho, M; W=missing, eps=GLOBAL_EPS) + +Calculation of the average Bayesian cost with a quadratic cost function. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `xest`: The estimators. +- `rho`: Parameterized density matrix. +- `M`: A set of POVM. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" +function BayesCost(x, p, xest, rho, M; W=missing, eps=GLOBAL_EPS) + para_num = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if para_num == 1 + # single-parameter scenario + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + + p_num = length(x[1]) + value = [p[i]*sum([tr(rho[i]*M[mi])*(x[1][i]-xest[mi][1])^2 for mi in 1:length(M)]) for i in 1:p_num] + return real(trapz(x[1], value)) + else + # multi-parameter scenario + if ismissing(W) + W = Matrix(I, para_num, para_num) + end + + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + + x_list = Iterators.product(x...) + p_num = length(x_list) + xCx = [sum([tr(rho_i*M[mi])*([xi...]-xest[mi])'*W*([xi...]-xest[mi]) for mi in 1:length(M)]) for (xi,rho_i) in zip(x_list,rho)] + xCx = reshape(xCx, size(p)) + + value = p.*xCx + for si in reverse(1:para_num) + value = trapz(x[si], value) + end + return real(value) + end +end + +""" + + BCB(x, p, rho; W=missing, eps=GLOBAL_EPS) + +Calculation of the minimum Bayesian cost with a quadratic cost function. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" +function BCB(x, p, rho; W=missing, eps=GLOBAL_EPS) + para_num = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if para_num == 1 + # single-parameter scenario + dim = size(rho[1])[1] + p_num = length(x[1]) + value = [p[i]*x[1][i]^2 for i in 1:p_num] + delta2_x = trapz(x[1], value) + rho_avg = zeros(ComplexF64, dim, dim) + rho_pri = zeros(ComplexF64, dim, dim) + + for di in 1:dim + for dj in 1:dim + rho_avg_arr = [p[m]*rho[m][di,dj] for m in 1:p_num] + rho_pri_arr = [p[n]*x[1][n]*rho[n][di,dj] for n in 1:p_num] + rho_avg[di,dj] = trapz(x[1], rho_avg_arr) + rho_pri[di,dj] = trapz(x[1], rho_pri_arr) + end + end + + Lambda = Lambda_avg(rho_avg, rho_pri, eps=eps) + minBC = delta2_x-real(tr(rho_avg*Lambda*Lambda)) + return minBC + else + # multi-parameter scenario + if ismissing(W) + W = Matrix(I, para_num, para_num) + end + x_list = Iterators.product(x...) + p_num = length(x_list) + xCx = [[xi...]'*W*[xi...] for xi in x_list] + xCx = reshape(xCx, size(p)) + + delta2_x = p.*xCx + for si in reverse(1:para_num) + delta2_x = trapz(x[si], delta2_x) + end + + term_tp = [pp*rho_i|>vec for (pp, rho_i) in zip(p, rho)] + rho_avg = trapzm(x, term_tp, para_num^2) |> I->reshape(I,para_num,para_num) + + x_re = Vector{Float64}[] + for xj in x_list + append!(x_re, [[_ for _ in xj]]) + end + + rho_pri = [trapzm(x, term_tp.*reshape([x_re[i][para_i] for i in 1:p_num], size(p)), para_num^2) |> I->reshape(I,para_num,para_num) for para_i in 1:para_num] + + Lambda = Lambda_avg(rho_avg, rho_pri, eps=eps) + + Mat = zeros(ComplexF64, para_num, para_num) + for para_m in 1:para_num + for para_n in 1:para_num + Mat += W[para_m, para_n]*(Lambda[para_m]*Lambda[para_n]) + end + end + + minBC = delta2_x-real(tr(rho_avg*Mat)) + return minBC + end +end + + +function Lambda_avg(rho_avg::Matrix{T}, rho_pri::Matrix{T}; eps=GLOBAL_EPS) where {T<:Complex} + dim = size(rho_avg)[1] + Lambda = Matrix{ComplexF64}(undef, dim, dim) + + val, vec = eigen(rho_avg) + val = val |> real + Lambda_eig = zeros(T, dim, dim) + for fi = 1:dim + for fj = 1:dim + if abs(val[fi] + val[fj]) > eps + Lambda_eig[fi, fj] = 2 * (vec[:, fi]' * rho_pri * vec[:, fj]) / (val[fi] + val[fj]) + end + end + end + Lambda_eig[findall(Lambda_eig == Inf)] .= 0.0 + + Lambda = vec * (Lambda_eig * vec') + return Lambda +end + +function Lambda_avg(rho_avg::Matrix{T}, rho_pri::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} + (x -> SLD(rho_avg, x; eps = eps)).(rho_pri) +end \ No newline at end of file diff --git a/src/Common/Common.jl b/src/Common/Common.jl new file mode 100644 index 0000000..27fd2f4 --- /dev/null +++ b/src/Common/Common.jl @@ -0,0 +1,368 @@ +include("mintime.jl") +include("BayesEstimation.jl") + +destroy(N) = diagm(1 => [sqrt(n)+0.0im for n in 1:N-1]) + +bases(dim; T=ComplexF64) = [e for e in I(dim).|>T|>eachrow] + +function vec2mat(x::Vector{T}) where {T <: Number} + reshape(x, x |> length |> sqrt |> Int, :) +end + +function vec2mat(x) + vec2mat.(x) +end + +function vec2mat(x::Matrix) + throw(ErrorException("vec2mating a matrix of size $(size(x))")) +end + +unzip(X) = map(x->getfield.(X, x), fieldnames(eltype(X))) + +function Base.repeat(system, N) + [deepcopy(system) for i in 1:N] +end + +function Base.repeat(system, M, N) + reshape(repeat(system, M * N), M, N) +end + +function filterZeros!(x::Matrix{T}) where {T <: Complex} + x[abs.(x) .< eps()] .= zero(T) + x +end +function filterZeros!(x) + filterZeros!.(x) +end + +function filterZeros(x::AbstractVecOrMat{T}) where T<:Number + [x+1≈1 ? zero(T) : x for x in x] +end + +function t2Num(t0, dt, t) + Int(round((t - t0) / dt)) + 1 +end + +function basis(dim, si, ::T)::Array{T} where {T <: Complex} + result = zeros(T, dim) + result[si] = 1.0 + result +end + +function suN_generatorU(n, k) + tmp1, tmp2 = ceil((1+sqrt(1+8k))/2), ceil((-1+sqrt(1+8k))/2) + i = k - tmp2*(tmp2-1)/2 |> Int + j = tmp1 |> Int + return sparse([i, j], [j,i], [1, 1], n, n) +end + +function suN_generatorV(n, k) + tmp1, tmp2 = ceil((1+sqrt(1+8k))/2), ceil((-1+sqrt(1+8k))/2) + i = k - tmp2*(tmp2-1)/2 |> Int + j = tmp1 |> Int + return sparse([i, j], [j,i], [-im, im], n, n) +end + +function suN_generatorW(n, k) + diagw = spzeros(n) + diagw[1:k] .=1 + diagw[k+1] = -k + return spdiagm(n,n,diagw) +end + +@doc raw""" + + suN_generator(n::Int64) + +Generation of the SU(``N``) generators with ``N`` the dimension of the system. +- `N`: The dimension of the system. +""" +function suN_generator(n::Int64) + result = Vector{SparseMatrixCSC{ComplexF64, Int64}}(undef, n^2-1) + idx = 2 + itr = 1 + + for i in 1:n-1 + idx_t = idx + while idx_t > 0 + result[itr] = iseven(idx_t) ? suN_generatorU(n, (i*(i-1)+idx-idx_t+2)/2) : suN_generatorV(n, (i*(i-1)+idx-idx_t+1)/2) + itr += 1 + idx_t -= 1 + end + result[itr] = sqrt(2/(i+i*i))*suN_generatorW(n, i) + itr += 1 + idx += 2 + end + return result +end + +function basis(dim, index) + x = zeros(dim) + x[index] = 1.0 + return x +end + +function sic_povm(fiducial) + """ + Generate a set of POVMs by applying the d^2 Weyl-Heisenberg displacement operators to a + fiducial state. The Weyl-Heisenberg displacement operators are constructioned by Fuchs + et al. in the article https://doi.org/10.3390/axioms6030021 and it is realized in QBism. + """ + d = length(fiducial) + w = exp(2.0*pi*1.0im/d) + Z = diagm([w^(i-1) for i in 1:d]) + X = zeros(ComplexF64, d, d) + for i in 1:d + for j in 1:d + if j != d + X += basis(d, j+1)*basis(d,j)' + else + X += basis(d, 1)* basis(d,j)' + end + end + end + X = X/d + + D = [[Matrix{ComplexF64}(undef,d,d) for i in 1:d] for j in 1:d] + for a in 1:d + for b in 1:d + X_a = X^(b-1) + Z_b = Z^(a-1) + D[a][b] = (-exp(1.0im*pi/d))^((a-1)*(b-1))*X_a*Z_b + end + end + + res = Vector{Matrix{ComplexF64}}() + for m in 1:d + for n in 1:d + res_tp = D[m][n]*fiducial + res_tp = res_tp/norm(res_tp) + push!(res, res_tp*res_tp'/d) + end + end + return res +end + +""" + + SIC(dim::Int64) + +Generation of a set of rank-one symmetric informationally complete positive operator-valued measure (SIC-POVM). +- `dim`: The dimension of the system. +Note: SIC-POVM is calculated by the Weyl-Heisenberg covariant SIC-POVM fiducial state which can be downloaded from [here](http://www.physics.umb.edu/Research/QBism/solutions.html). +""" +function SIC(dim::Int64) + data = readdlm("$(pkgpath)/sic_fiducial_vectors/d$(dim).txt", '\t', Float64, '\n') + fiducial = data[:,1]+1.0im*data[:,2] + M = sic_povm(fiducial) +end + +function BayesInput(x, func, dfunc; channel="dynamics") + para_num = length(x) + x_size = [x[i] for i in 1:para_num] + x_list = Iterators.product(x...) + if channel == "dynamics" + H = [func(xi) for xi in x_list] + dH = [dfunc(xi) for xi in x_list] + return H, dH + elseif channel == "Kraus" + K = [func(xi) for xi in x_list] + dK = [dfunc(xi) for xi in x_list] + return K, dK + else + throw("Supported values for channel are 'dynamics' and 'Kraus'") + end +end + +#### bound control coefficients #### +function bound!(ctrl::Vector{Vector{Float64}}, ctrl_bound) + for ck in 1:length(ctrl) + for tk in 1:length(ctrl[1]) + ctrl[ck][tk] = (x-> x < ctrl_bound[1] ? ctrl_bound[1] : x > ctrl_bound[2] ? ctrl_bound[2] : x)(ctrl[ck][tk]) + end + end +end + +function bound!(ctrl::Vector{Float64}, ctrl_bound) + for ck in 1:length(ctrl) + ctrl[ck] = (x-> x < ctrl_bound[1] ? ctrl_bound[1] : x > ctrl_bound[2] ? ctrl_bound[2] : x)(ctrl[ck]) + end +end + +function Adam(gt, t, para, mt, vt, epsilon, beta1, beta2, eps) + t = t+1 + mt = beta1*mt + (1-beta1)*gt + vt = beta2*vt + (1-beta2)*(gt*gt) + m_cap = mt/(1-(beta1^t)) + v_cap = vt/(1-(beta2^t)) + para = para+(epsilon*m_cap)/(sqrt(v_cap)+eps) + return para, mt, vt +end + +#### bound coefficients of linear combination in Mopt #### +function bound_LC_coeff!(coefficients::Vector{Vector{Float64}}, rng) + M_num = length(coefficients) + basis_num = length(coefficients[1]) + for ck in 1:M_num + for tk in 1:basis_num + coefficients[ck][tk] = (x-> x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x)(coefficients[ck][tk]) + end + end + + Sum_col = [sum([coefficients[m][n] for m in 1:M_num]) for n in 1:basis_num] + for si in 1:basis_num + if Sum_col[si] == 0.0 + int_num = sample(rng, 1:M_num, 1, replace=false)[1] + coefficients[int_num][si] = 1.0 + end + end + + Sum_row = [sum([coefficients[m][n] for n in 1:basis_num]) for m in 1:M_num] + for mi in 1:M_num + if Sum_row[mi] == 0.0 + int_num = sample(rng, 1:basis_num, 1, replace=false)[1] + coefficients[mi][int_num] = rand(rng) + end + end + + Sum_col = [sum([coefficients[m][n] for m in 1:M_num]) for n in 1:basis_num] + for i in 1:M_num + for j in 1:basis_num + coefficients[i][j] = coefficients[i][j]/Sum_col[j] + end + end +end + +#### bound coefficients of rotation in Mopt #### +function bound_rot_coeff!(coefficients::Vector{Float64}) + n = length(coefficients) + for tk in 1:n + coefficients[tk] = (x-> x < 0.0 ? 0.0 : x > 2*pi ? 2*pi : x)(coefficients[tk]) + end +end + +function gramschmidt(A::Vector{Vector{ComplexF64}}) + n = length(A[1]) + m = length(A) + Q = [zeros(ComplexF64,n) for i in 1:m] + for j in 1:m + q = A[j] + for i in 1:j + rij = dot(Q[i], q) + q = q - rij*Q[i] + end + Q[j] = q/norm(q) + end + Q +end + +function rotation_matrix(coefficients, Lambda) + dim = size(Lambda[1])[1] + U = Matrix{ComplexF64}(I,dim,dim) + for i in 1:length(Lambda) + U = U*exp(1.0im*coefficients[i]*Matrix(Lambda[i])) + end + U +end + +#### initialization states for DE and PSO method #### +function initial_state!(psi0, dynamics, p_num, rng) + dim = length(dynamics[1].data.ψ0) + if length(psi0) > p_num + psi0 = [psi0[i] for i in 1:p_num] + end + for pj in 1:length(psi0) + dynamics[pj].data.ψ0 = [psi0[pj][i] for i in 1:dim] + end + for pj in (length(psi0)+1):p_num + r_ini = 2*rand(rng, dim)-ones(dim) + r = r_ini/norm(r_ini) + phi = 2*pi*rand(rng, dim) + dynamics[pj].data.ψ0 = [r[i]*exp(1.0im*phi[i]) for i in 1:dim] + end +end + +#### initialization control coefficients for DE and PSO method #### +function initial_ctrl!(opt, ctrl0, dynamics, p_num, rng) + ctrl_length = length(dynamics[1].data.ctrl[1]) + ctrl_num = length(dynamics[1].data.Hc) + if length(ctrl0) > p_num + ctrl0 = [ctrl0[i] for i in 1:p_num] + end + for pj in 1:length(ctrl0) + dynamics[pj].data.ctrl = ctrl0[pj] isa AbstractVector ? deepcopy(ctrl0[pj]) : [[ctrl0[pj][i, j] for j in 1:ctrl_length] for i in 1:ctrl_num] + end + if opt.ctrl_bound[1] == -Inf || opt.ctrl_bound[2] == Inf + for pj in (length(ctrl0)+1):p_num + dynamics[pj].data.ctrl = [[2*rand(rng)-1.0 for j in 1:ctrl_length] for i in 1:ctrl_num] + end + else + a = opt.ctrl_bound[1] + b = opt.ctrl_bound[2] + for pj in (length(ctrl0)+1):p_num + dynamics[pj].data.ctrl = [[(b-a)*rand(rng)+a for j in 1:ctrl_length] for i in 1:ctrl_num] + end + end +end + +#### initialization velocity for PSO #### +function initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, rng) + if opt.ctrl_bound[1] == -Inf || opt.ctrl_bound[2] == Inf + velocity = 0.1*(2.0*rand(rng, ctrl_num, ctrl_length, p_num)-ones(ctrl_num, ctrl_length, p_num)) + else + a = opt.ctrl_bound[1] + b = opt.ctrl_bound[2] + velocity = 0.1*((b-a)*rand(rng, ctrl_num, ctrl_length, p_num)+a*ones(ctrl_num, ctrl_length, p_num)) + end + velocity +end + +#### initialization measurements for DE and PSO #### +function initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + if length(measurement0) > p_num + measurement0 = [measurement0[i] for i in 1:p_num] + end + for pj in 1:length(measurement0) + C_all[pj] = measurement0[pj] isa AbstractVector ? deepcopy(measurement0[pj]) : [[measurement0[pj][i,j] for j in 1:dim] for i in 1:M_num] + end + for pj in (length(measurement0)+1):p_num + M_tp = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] + for mi in 1:M_num + r_ini = 2*rand(rng, dim)-ones(dim) + r = r_ini/norm(r_ini) + phi = 2*pi*rand(rng, dim) + M_tp[mi] = [r[i]*exp(1.0im*phi[i]) for i in 1:dim] + end + C_all[pj] = [[M_tp[i][j] for j in 1:dim] for i in 1:M_num] + # orthogonality and normalization + C_all[pj] = gramschmidt(C_all[pj]) + end +end + +function initial_LinearComb!(measurement0, B_all, basis_num, M_num, p_num, rng) + if length(measurement0) > p_num + measurement0 = [measurement0[i] for i in 1:p_num] + end + for pj in 1:length(measurement0) + B_all[pj] = measurement0[pj] isa AbstractVector ? deepcopy(measurement0[pj]) : [[measurement0[pj][i,j] for j in 1:basis_num] for i in 1:M_num] + end + + for pj in (length(measurement0)+1):p_num + B_all[pj] = [rand(rng, basis_num) for i in 1:M_num] + bound_LC_coeff!(B_all[pj], rng) + end +end + +function initial_Rotation!(measurement0, s_all, dim, p_num, rng) + if length(measurement0) > p_num + measurement0 = [measurement0[i] for i in 1:p_num] + end + for pj in 1:length(measurement0) + s_all[pj] = [measurement0[pj][i] for i in 1:dim*dim] + end + + for pj in (length(measurement0)+1):p_num + s_all[pj] = rand(rng, dim*dim) + end +end + diff --git a/src/Common/mintime.jl b/src/Common/mintime.jl new file mode 100644 index 0000000..c4c0650 --- /dev/null +++ b/src/Common/mintime.jl @@ -0,0 +1,74 @@ +###################### mintime opt ############################# +function mintime(::Val{:binary}, f::Number, system) + (; dynamics, output, obj, optim, algorithm) = system + (; tspan, ctrl) = deepcopy(dynamics.data) + low, high = 1, length(tspan) + mid = 0 + f_mid = 0.0 + + while low < high + mid = fld1(low + high, 2) + + dynamics.data.tspan = tspan[1:mid] + dynamics.data.ctrl = [c[1:mid-1] for c in ctrl] + if algorithm isa DE + algorithm.ini_population = ([dynamics.data.ctrl],) + elseif algorithm isa PSO + algorithm.ini_particle = ([dynamics.data.ctrl],) + end + + f_ini = objective(obj, dynamics)[2] + + if f > f_ini + run(system) + f_mid = output.f_list[end] + else + f_mid = f_ini + end + + if abs(f-f_mid) < obj.eps + break + elseif f_mid < f + low = mid + 1 + else + high = mid - 1 + end + end + open("mtspan.csv","w") do t + writedlm(t, dynamics.data.tspan) + end + open("controls.csv","w") do c + writedlm(c, dynamics.data.ctrl) + end + println("The minimum time to reach target is ", dynamics.data.tspan[end],", data saved.") +end + +function mintime(::Val{:forward}, f::Number, system) + (; dynamics, output, obj, algorithm) = system + (; tspan, ctrl) = deepcopy(dynamics.data) + idx = 2 + f_now = 0.0 + + while f_now < f && idx "optimization algorithm: Differential Evolution (DE)", :DDPG => "optimization algorithm: Deep Deterministic Policy Gradient (DDPG)", :NM => "optimization algorithm: Nelder-Mead (NM)", + :Iterative => "optimization algorithm: Iterative", ) const IO_ini = Dict( diff --git a/src/objective/AsymptoticBound/AsymptoticBound.jl b/src/ObjectiveFunc/AsymptoticBound/AsymptoticBound.jl similarity index 86% rename from src/objective/AsymptoticBound/AsymptoticBound.jl rename to src/ObjectiveFunc/AsymptoticBound/AsymptoticBound.jl index 2962885..87088fd 100644 --- a/src/objective/AsymptoticBound/AsymptoticBound.jl +++ b/src/ObjectiveFunc/AsymptoticBound/AsymptoticBound.jl @@ -4,31 +4,59 @@ abstract type SLD <: AbstractLDtype end abstract type RLD <: AbstractLDtype end abstract type LLD <: AbstractLDtype end -Base.@kwdef struct QFIM_obj{P,D} <: AbstractObj +struct QFIM_obj{P,D} <: AbstractObj W::Union{AbstractMatrix, Missing} - eps::Number = GLOBAL_EPS + eps::Number end -Base.@kwdef struct CFIM_obj{P} <: AbstractObj +struct CFIM_obj{P} <: AbstractObj M::Union{AbstractVecOrMat, Missing} W::Union{AbstractMatrix, Missing} - eps::Number = GLOBAL_EPS + eps::Number end -Base.@kwdef struct HCRB_obj{P} <: AbstractObj +struct HCRB_obj{P} <: AbstractObj W::Union{AbstractMatrix, Missing} - eps::Number = GLOBAL_EPS + eps::Number end -QFIM_obj(;W=missing, eps=GLOBAL_EPS, para_type::Symbol=:single_para, LD_type::Symbol=:SLD) = QFIM_obj{eval.([para_type, LD_type])...}(W, eps) +@doc raw""" + + QFIM_obj(;W=missing, eps=GLOBAL_EPS, LDtype::Symbol=:SLD) + +Choose QFI [``\mathrm{Tr}(WF^{-1})``] as the objective function with ``W`` the weight matrix and ``F`` the QFIM. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are `:SLD` (default), `:RLD` and `:LLD`. +""" +QFIM_obj(;W=missing, eps=GLOBAL_EPS, para_type::Symbol=:single_para, LDtype::Symbol=:SLD) = QFIM_obj{eval.([para_type, LDtype])...}(W, eps) + +@doc raw""" + + CFIM_obj(;M=missing, W=missing, eps=GLOBAL_EPS) + +Choose CFI [``\mathrm{Tr}(WI^{-1})``] as the objective function with ``W`` the weight matrix and ``I`` the CFIM. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" CFIM_obj(;M=missing, W=missing, eps=GLOBAL_EPS, para_type::Symbol=:single_para) = CFIM_obj{eval(para_type)}(M, W, eps) + +@doc raw""" + + HCRB_obj(;W=missing, eps=GLOBAL_EPS) + +Choose HCRB as the objective function. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" HCRB_obj(;W=missing, eps=GLOBAL_EPS, para_type::Symbol=:single_para) = HCRB_obj{eval(para_type)}(W, eps) -QFIM_obj(W, eps, para_type::Symbol, LD_type::Symbol) = QFIM_obj{eval.([para_type, LD_type])...}(W, eps) +QFIM_obj(W, eps, para_type::Symbol, LDtype::Symbol) = QFIM_obj{eval.([para_type, LDtype])...}(W, eps) CFIM_obj(M, W, eps, para_type::Symbol) = CFIM_obj{eval(para_type)}(M, W, eps) HCRB_obj(W, eps, para_type::Symbol) = HCRB_obj{eval(para_type)}(W, eps) -QFIM_obj(W::AbstractMatrix, eps::Number, para_type::String, LD_type::String) = QFIM_obj(W, eps, Symbol.([para_type, LD_type])...) +QFIM_obj(W::AbstractMatrix, eps::Number, para_type::String, LDtype::String) = QFIM_obj(W, eps, Symbol.([para_type, LDtype])...) CFIM_obj(M::AbstractVecOrMat, W::AbstractMatrix, eps::Number, para_type::String) = CFIM_obj(M, W, eps, Symbol(para_type)) HCRB_obj(W::AbstractMatrix, eps::Number, para_type::String) = HCRB_obj(W, eps, Symbol(para_type)) @@ -43,9 +71,9 @@ para_type(::CFIM_obj{multi_para}) = :multi_para para_type(::HCRB_obj{single_para}) = :single_para para_type(::HCRB_obj{multi_para}) = :multi_para -LD_type(::QFIM_obj{P,SLD}) where {P} = :SLD -LD_type(::QFIM_obj{P,RLD}) where {P} = :RLD -LD_type(::QFIM_obj{P,LLD}) where {P} = :LLD +LDtype(::QFIM_obj{P,SLD}) where {P} = :SLD +LDtype(::QFIM_obj{P,RLD}) where {P} = :RLD +LDtype(::QFIM_obj{P,LLD}) where {P} = :LLD QFIM_obj(opt::CFIM_obj{P}) where P = QFIM_obj{P, SLD}(opt.W, opt.eps) QFIM_obj(opt::CFIM_obj{P}, LDtype::Symbol) where P = QFIM_obj{P, eval(LDtype)}(opt.W, opt.eps) diff --git a/src/objective/AsymptoticBound/AsymptoticBoundWrapper.jl b/src/ObjectiveFunc/AsymptoticBound/AsymptoticBoundWrapper.jl similarity index 96% rename from src/objective/AsymptoticBound/AsymptoticBoundWrapper.jl rename to src/ObjectiveFunc/AsymptoticBound/AsymptoticBoundWrapper.jl index 5950a6b..07e89a1 100644 --- a/src/objective/AsymptoticBound/AsymptoticBoundWrapper.jl +++ b/src/ObjectiveFunc/AsymptoticBound/AsymptoticBoundWrapper.jl @@ -4,7 +4,7 @@ function Objective(dynamics::AbstractDynamics, obj::QFIM_obj{P,D}) where {P,D} W = I(get_para(dynamics.data))|>Matrix end - d = LD_type(obj) |> eval + d = LDtype(obj) |> eval p = para_type(dynamics.data) |> eval return QFIM_obj{p,d}(W,eps) diff --git a/src/objective/AsymptoticBound/CramerRao.jl b/src/ObjectiveFunc/AsymptoticBound/CramerRao.jl similarity index 56% rename from src/objective/AsymptoticBound/CramerRao.jl rename to src/ObjectiveFunc/AsymptoticBound/CramerRao.jl index 8c3c968..cff2974 100644 --- a/src/objective/AsymptoticBound/CramerRao.jl +++ b/src/ObjectiveFunc/AsymptoticBound/CramerRao.jl @@ -6,24 +6,22 @@ const σ_z = [1.0 0.0im; 0.0 -1.0] ############## logarrithmic derivative ############### @doc raw""" - SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) Complex} - -Calculate the symmetric logarrithmic derivatives (SLDs).The SLD operator $L_a$ is defined as``\partial_{a}\rho=\frac{1}{2}(\rho L_{a}+L_{a}\rho)``, where ρ is the parameterized density matrix. + SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} +Calculate the symmetric logarrithmic derivatives (SLDs). The SLD operator ``L_a`` is defined +as``\partial_{a}\rho=\frac{1}{2}(\rho L_{a}+L_{a}\rho)``, where ``\rho`` is the parameterized density matrix. - `ρ`: Density matrix. -- `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. -- `rep`: Representation of the SLD operator. Options can be: - - "original" (default) -- The SLD matrix will be written in terms of the same basis as the input density matrix (ρ). - - "eigen" -- The SLD matrix will be written in terms of the eigenbasis of the input ρ. -- `eps`: Machine epsilon +- `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. +- `rep`: Representation of the SLD operator. Options can be: "original" (default) and "eigen" . +- `eps`: Machine epsilon. """ -function SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) where {T<:Complex} +function SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} (x -> SLD(ρ, x; rep=rep, eps = eps)).(dρ) end """ - SLD(ρ::Matrix{T},dρ::Matrix{T};rep = "original",eps = GLOBAL_EPS,) where {T<:Complex} + SLD(ρ::Matrix{T}, dρ::Matrix{T}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} When applied to the case of single parameter. """ @@ -42,7 +40,7 @@ function SLD( SLD_eig = zeros(T, dim, dim) for fi = 1:dim for fj = 1:dim - if abs(val[fi] + val[fj]) > eps + if abs(val[fi] + val[fj]) > eps SLD_eig[fi, fj] = 2 * (vec[:, fi]' * dρ * vec[:, fj]) / (val[fi] + val[fj]) end end @@ -54,7 +52,7 @@ function SLD( elseif rep == "eigen" SLD = SLD_eig else - throw(ArgumentError("the rep should be chosen between")) + throw(ArgumentError("The rep should be chosen in {'original', 'eigen'}.")) end SLD end @@ -65,10 +63,6 @@ end L, SLD_pullback end -function SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} - (x -> SLD(ρ, x; eps = eps)).(dρ) -end - function SLD_liouville(ρ::Matrix{T}, ∂ρ_∂x::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} 2 * pinv(kron(ρ |> transpose, ρ |> one) + kron(ρ |> one, ρ), rtol = eps) * vec(∂ρ_∂x) |> vec2mat @@ -94,25 +88,22 @@ end @doc raw""" -RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) where {T<:Complex} - -Calculate the right logarrithmic derivatives (RLDs). The RLD operator is defined as ``\partial_{a}\rho=\rho \mathcal{R}_a``, where ρ is the parameterized density matrix. + RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} +Calculate the right logarrithmic derivatives (RLDs). The RLD operator is defined as +``\partial_{a}\rho=\rho \mathcal{R}_a``, where ``\rho`` is the parameterized density matrix. - `ρ`: Density matrix. - `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. -- `rep`: Representation of the RLD operator. Options can be: - - "original" (default) -- The RLD matrix will be written in terms of the same basis as the input density matrix (ρ). - - "eigen" -- The RLD matrix will be written in terms of the eigenbasis of the input ρ. -- `eps`: Machine epsilon - +- `rep`: Representation of the RLD operator. Options can be: "original" (default) and "eigen". +- `eps`: Machine epsilon. """ -function RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) where {T<:Complex} +function RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} (x -> RLD(ρ, x; rep=rep, eps = eps)).(dρ) end """ - RLD(ρ::Matrix{T},dρ::Matrix{T};rep = "original",eps = GLOBAL_EPS,) where {T<:Complex} + RLD(ρ::Matrix{T}, dρ::Matrix{T}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} When applied to the case of single parameter. """ @@ -123,7 +114,7 @@ function RLD( eps = GLOBAL_EPS, ) where {T<:Complex} -dim = size(ρ)[1] + dim = size(ρ)[1] RLD = Matrix{ComplexF64}(undef, dim, dim) val, vec = eigen(ρ) @@ -131,8 +122,14 @@ dim = size(ρ)[1] RLD_eig = zeros(T, dim, dim) for fi = 1:dim for fj = 1:dim + term_tp = (vec[:, fi]' * dρ * vec[:, fj]) if abs(val[fi]) > eps - RLD_eig[fi, fj] = (vec[:, fi]' * dρ * vec[:, fj]) / val[fi] + RLD_eig[fi, fj] = term_tp / val[fi] + else + if abs(term_tp) < eps + println("RLD does not exist. It only exist when the support of drho is contained in the support of rho.") + return nothing + end end end end @@ -146,34 +143,24 @@ dim = size(ρ)[1] RLD end -function RLD(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} - pinv(ρ, rtol = eps) * dρ -end - -function RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} - (x -> RLD(ρ, x; eps = eps)).(dρ) -end @doc raw""" -LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) where {T<:Complex} + LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} -Calculate the left logarrithmic derivatives (LLDs). The LLD operator is defined as ``\partial_{a}\rho=\mathcal{R}_a^{\dagger}\rho``, where ρ is the parameterized density matrix. +Calculate the left logarrithmic derivatives (LLDs). The LLD operator is defined as ``\partial_{a}\rho=\mathcal{R}_a^{\dagger}\rho``, where ρ is the parameterized density matrix. - `ρ`: Density matrix. - `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. -- `rep`: Representation of the LLD operator. Options can be: - - "original" (default) -- The RLD matrix will be written in terms of the same basis as the input density matrix (ρ). - - "eigen" -- The RLD matrix will be written in terms of the eigenbasis of the input ρ. -- `eps`: Machine epsilon - +- `rep`: Representation of the LLD operator. Options can be: "original" (default) and "eigen". +- `eps`: Machine epsilon. """ -function LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep = "original", eps = GLOBAL_EPS) where {T<:Complex} +function LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} (x -> LLD(ρ, x; rep=rep, eps = eps)).(dρ) end """ -LLD(ρ::Matrix{T},dρ::Matrix{T};rep = "original",eps = GLOBAL_EPS,) where {T<:Complex} + LLD(ρ::Matrix{T}, dρ::Matrix{T}; rep="original", eps=GLOBAL_EPS) where {T<:Complex} When applied to the case of single parameter. """ @@ -192,8 +179,14 @@ function LLD( LLD_eig = zeros(T, dim, dim) for fi = 1:dim for fj = 1:dim + term_tp = (vec[:, fi]' * dρ * vec[:, fj]) if abs(val[fj]) > eps - LLD_eig[fj, fi] = ((vec[:, fi]' * dρ * vec[:, fj]) / val[fj]) |> conj() + LLD_eig[fj, fi] = (term_tp / val[fj]) |> conj() + else + if abs(term_tp) < eps + println("LLD does not exist. It only exist when the support of drho is contained in the support of rho.") + return nothing + end end end end @@ -207,13 +200,6 @@ function LLD( LLD end -function LLD(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} - (dρ * pinv(ρ, rtol = eps)) -end - -function LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} - (x -> LLD(ρ, x; eps = eps)).(dρ) -end #========================================================# ####################### calculate QFI #################### @@ -225,13 +211,13 @@ function QFIM_SLD(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Com end function QFIM_RLD(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} - RLD_tp = RLD(ρ, dρ; eps = eps) + RLD_tp = pinv(ρ, rtol = eps) * dρ F = tr(ρ * RLD_tp * RLD_tp') F |> real end function QFIM_LLD(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} - LLD_tp = LLD(ρ, dρ; eps = eps) + LLD_tp = (dρ * pinv(ρ, rtol = eps))' F = tr(ρ * LLD_tp * LLD_tp') F |> real end @@ -247,7 +233,7 @@ end ####################### calculate QFIM ##################### function QFIM_SLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} p_num = length(dρ) - LD_tp = SLD(ρ, dρ; eps = eps) + LD_tp = (x -> SLD(ρ, x; eps = eps)).(dρ) ( [0.5 * ρ] .* (kron(LD_tp, reshape(LD_tp, 1, p_num)) + kron(reshape(LD_tp, 1, p_num), LD_tp)) @@ -256,21 +242,22 @@ end function QFIM_RLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} p_num = length(dρ) - LD_tp = RLD(ρ, dρ; eps = eps) + LD_tp = (x -> (pinv(ρ, rtol = eps) * x) ).(dρ) LD_dag = [LD_tp[i]' for i = 1:p_num] - ([ρ] .* (kron(LD_tp, reshape(LD_dag, 1, p_num)))) .|> tr .|> real + ([ρ] .* (kron(LD_tp, reshape(LD_dag, 1, p_num)))) .|> tr end function QFIM_LLD(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} p_num = length(dρ) - LD_tp = LLD(ρ, dρ; eps = eps) + LD_tp = (x -> (x * pinv(ρ, rtol = eps))').(dρ) LD_dag = [LD_tp[i]' for i = 1:p_num] - ([ρ] .* (kron(LD_tp, reshape(LD_dag, 1, p_num)))) .|> tr .|> real + ([ρ] .* (kron(LD_tp, reshape(LD_dag, 1, p_num)))) .|> tr end function QFIM_liouville(ρ, dρ) p_num = length(dρ) - LD_tp = SLD_liouville(ρ, dρ) + LD_tp = SLD_lio + uville(ρ, dρ) ( [0.5 * ρ] .* (kron(LD_tp, reshape(LD_tp, 1, p_num)) + kron(reshape(LD_tp, 1, p_num), LD_tp)) @@ -279,10 +266,10 @@ end function QFIM_pure(ρ::Matrix{T}, ∂ρ_∂x::Vector{Matrix{T}}) where {T<:Complex} p_num = length(∂ρ_∂x) - SLD = [2 * ∂ρ_∂x[i] for i = 1:p_num] + sld = [2 * ∂ρ_∂x[i] for i = 1:p_num] ( [0.5 * ρ] .* - (kron(SLD, reshape(SLD, 1, p_num)) + kron(reshape(SLD, 1, p_num), SLD)) + (kron(sld, reshape(sld, 1, p_num)) + kron(reshape(sld, 1, p_num), sld)) ) .|> tr .|> real @@ -292,16 +279,15 @@ end #################### calculate CFIM #################### @doc raw""" - CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}, M; eps = GLOBAL_EPS) where {T<:Complex} + CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}, M; eps=GLOBAL_EPS) where {T<:Complex} Calculate the classical Fisher information matrix (CFIM). - - `ρ`: Density matrix. -- `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. +- `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. - `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). - `eps`: Machine epsilon. """ -function CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}, M; eps = GLOBAL_EPS) where {T<:Complex} +function CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}, M; eps=GLOBAL_EPS) where {T<:Complex} m_num = length(M) p_num = length(dρ) [ @@ -315,9 +301,9 @@ end """ - CFIM(ρ::Matrix{T}, dρ::Matrix{T}, M; eps = GLOBAL_EPS) where {T<:Complex} + CFIM(ρ::Matrix{T}, dρ::Matrix{T}, M; eps=GLOBAL_EPS) where {T<:Complex} -When applied to the case of single parameter. Calculate the classical Fisher information(CFI). +When applied to the case of single parameter. Calculate the classical Fisher information (CFI). """ function CFIM(ρ::Matrix{T}, dρ::Matrix{T}, M; eps = GLOBAL_EPS) where {T<:Complex} m_num = length(M) @@ -337,11 +323,11 @@ end """ - CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} + CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; M=nothing, eps=GLOBAL_EPS) where {T<:Complex} -When the set of POVM is not given. Calculate the CFIM with SIC-POVM. The SIC-POVM is generated from the Weyl-Heisenberg covariant SIC-POVM fiducial state which can be downloaded from the [website](http://www.physics.umb.edu/Research/QBism/solutions.html). +When the set of POVM is not given. Calculate the CFIM with SIC-POVM. The SIC-POVM is generated from the Weyl-Heisenberg covariant SIC-POVM fiducial state which can be downloaded from [here](http://www.physics.umb.edu/Research/QBism/solutions.html). """ -function CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} +function CFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; M=nothing, eps = GLOBAL_EPS) where {T<:Complex} M = SIC(size(ρ)[1]) m_num = length(M) p_num = length(dρ) @@ -356,11 +342,11 @@ end """ - CFIM(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} + CFIM(ρ::Matrix{T}, dρ::Matrix{T}; eps=GLOBAL_EPS) where {T<:Complex} When applied to the case of single parameter and the set of POVM is not given. Calculate the CFI with SIC-POVM. """ -function CFIM(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex} +function CFIM(ρ::Matrix{T}, dρ::Matrix{T}; M=nothing, eps=GLOBAL_EPS) where {T<:Complex} M = SIC(size(ρ)[1]) m_num = length(M) F = 0.0 @@ -377,80 +363,98 @@ function CFIM(ρ::Matrix{T}, dρ::Matrix{T}; eps = GLOBAL_EPS) where {T<:Complex real(F) end +## QFI with exportLD """ + QFIM(ρ::Matrix{T}, dρ::Matrix{T}; LDtype=:SLD, exportLD::Bool= false, eps=GLOBAL_EPS) where {T<:Complex} + +Calculation of the quantum Fisher information (QFI) for all types. +- `ρ`: Density matrix. +- `dρ`: Derivatives of the density matrix with respect to the unknown parameters to be estimated. For example, drho[1] is the derivative vector with respect to the first parameter. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are `:SLD` (default), `:RLD` and `:LLD`. +- `exportLD`: export logarithmic derivatives apart from F. +- `eps`: Machine epsilon. """ function QFIM( ρ::Matrix{T}, dρ::Matrix{T}; LDtype = :SLD, + exportLD ::Bool= false, eps = GLOBAL_EPS, ) where {T<:Complex} - eval(Symbol("QFIM_" * string(LDtype)))(ρ, dρ; eps = eps) + F = eval(Symbol("QFIM_" * string(LDtype)))(ρ, dρ; eps = eps) + if exportLD == false + return F + else + LD = eval(Symbol(LDtype))(ρ, dρ; eps = eps) + return F, LD + end end -## QFIM +""" + + QFIM(ρ::Matrix{T}, dρ::Vector{Matrix{T}}; LDtype=:SLD, exportLD::Bool= false, eps=GLOBAL_EPS) where {T<:Complex} + +When applied to the case of single parameter. Calculation of the quantum Fisher information (QFI) for all types. +""" function QFIM( ρ::Matrix{T}, dρ::Vector{Matrix{T}}; LDtype = :SLD, + exportLD ::Bool= false, eps = GLOBAL_EPS, ) where {T<:Complex} - eval(Symbol("QFIM_" * string(LDtype)))(ρ, dρ; eps = eps) + F = eval(Symbol("QFIM_" * string(LDtype)))(ρ, dρ; eps = eps) + if exportLD == false + return F + else + LD = eval(Symbol(LDtype))(ρ, dρ; eps = eps) + return F, LD + end end - QFIM(sym::Symbol, args...; kwargs...) = QFIM(Val{sym}, args...; kwargs...) -## QFI with exportLD -function QFIM( - ::Val{:exportLD}, - ρ::Matrix{T}, - dρ::Matrix{T}; - LDtype = :SLD, - eps = GLOBAL_EPS, -) where {T<:Complex} - - F = QFIM(ρ, dρ; LDtype = LDtype, eps = eps) - LD = eval(LDtype)(ρ, dρ; eps = eps) - return F, LD -end +""" -## QFIM with exportLD -function QFIM( - ::Val{:exportLD}, - ρ::Matrix{T}, - dρ::Vector{Matrix{T}}; - LDtype = :SLD, - eps = GLOBAL_EPS, -) where {T<:Complex} + QFIM_Kraus(ρ0::AbstractMatrix, K::AbstractVector, dK::AbstractVector; LDtype=:SLD, exportLD::Bool=false, eps=GLOBAL_EPS) - F = QFIM(ρ, dρ; LDtype = LDtype, eps = eps) - LD = eval(LDtype)(ρ, dρ; eps = eps) - return F, LD +Calculation of the quantum Fisher information (QFI) and quantum Fisher information matrix (QFIM) with Kraus operator(s) for all types. +- `ρ0`: Density matrix. +- `K`: Kraus operator(s). +- `dK`: Derivatives of the Kraus operator(s) on the unknown parameters to be estimated. For example, dK[0] is the derivative vector on the first parameter. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are `:SLD` (default), `:RLD` and `:LLD`. +- `exportLD`: Whether or not to export the values of logarithmic derivatives. If set True then the the values of logarithmic derivatives will be exported. +- `eps`: Machine epsilon. +""" +function QFIM_Kraus(ρ0::AbstractMatrix, K::AbstractVector, dK::AbstractVector; LDtype=:SLD, exportLD::Bool=false, eps=GLOBAL_EPS) + para_num = length(dK[1]) + dK = [[dK[i][j] for i in 1:length(K)] for j in 1:para_num] + ρ = [K * ρ0 * K' for K in K] |> sum + dρ = [[dK * ρ0 * K' + K * ρ0 * dK' for (K,dK) in zip(K,dK)] |> sum for dK in dK] + F = QFIM(ρ, dρ; LDtype=LDtype, exportLD=exportLD, eps=eps) + if para_num == 1 + # single-parameter scenario + return F[1,1] + else + # multiparameter scenario + return F + end end - """ - QFIM_Bloch(r, dr; eps = 1e-8) - -Calculate the SLD based quantum Fisher information (QFI) or quantum -Fisher information matrix (QFIM) in Bloch representation. + QFIM_Bloch(r, dr; eps=GLOBAL_EPS) +Calculate the SLD based quantum Fisher information (QFI) or quantum Fisher information matrix (QFIM) in Bloch representation. - `r`: Parameterized Bloch vector. - -- `dr`: Derivative(s) of the Bloch vector with respect to the unknown parameters to be - estimated. For example, dr[1] is the derivative vector with respect to the first - parameter. - +- `dr`: Derivative(s) of the Bloch vector with respect to the unknown parameters to be estimated. For example, dr[1] is the derivative vector with respect to the first parameter. - `eps`: Machine epsilon. - """ ## TODO: 👇 check type stability -function QFIM_Bloch(r, dr; eps = 1e-8) +function QFIM_Bloch(r, dr; eps=GLOBAL_EPS) para_num = length(dr) QFIM_res = zeros(para_num, para_num) @@ -461,7 +465,7 @@ function QFIM_Bloch(r, dr; eps = 1e-8) if abs(r_norm - 1.0) < eps for para_i = 1:para_num for para_j = para_i:para_num - QFIM_res[para_i, para_j] = dr[para_i]' * dr[para_j] + QFIM_res[para_i, para_j] = real(dr[para_i]' * dr[para_j]) QFIM_res[para_j, para_i] = QFIM_res[para_i, para_j] end end @@ -469,8 +473,8 @@ function QFIM_Bloch(r, dr; eps = 1e-8) for para_i = 1:para_num for para_j = para_i:para_num QFIM_res[para_i, para_j] = - dr[para_i]' * dr[para_j] + - (r' * dr[para_i]) * (r' * dr[para_j]) / (1 - r_norm) + real(dr[para_i]' * dr[para_j] + + (r' * dr[para_i]) * (r' * dr[para_j]) / (1 - r_norm)) QFIM_res[para_j, para_i] = QFIM_res[para_i, para_j] end end @@ -491,8 +495,7 @@ function QFIM_Bloch(r, dr; eps = 1e-8) for para_m = 1:para_num for para_n = para_m:para_num - # println(dr[para_n]*mat_inv*dr[para_m]') - QFIM_res[para_m, para_n] = dr[para_n]' * mat_inv * dr[para_m] + QFIM_res[para_m, para_n] = real(dr[para_n]' * mat_inv * dr[para_m]) QFIM_res[para_n, para_m] = QFIM_res[para_m, para_n] end end @@ -504,6 +507,66 @@ function QFIM_Bloch(r, dr; eps = 1e-8) end end +""" + + FIM(p::Vector{R}, dp::Vector{R}; eps=GLOBAL_EPS) where {R<:Real} + +When applied to the case of single parameter and the set of POVM is not given. Calculate the classical Fisher information for classical scenarios. +""" +function FIM(p::Vector{R}, dp::Vector{R}; eps=GLOBAL_EPS) where {R<:Real} + m_num = length(p) + F = 0.0 + for i = 1:m_num + p_tp = p[i] + dp_tp = dp[i] + cadd = 0.0 + if p_tp > eps + cadd = (dp_tp * dp_tp) / p_tp + end + F += cadd + end + real(F) +end + +""" + + FIM(p::Vector{R}, dp::Vector{R}; eps=GLOBAL_EPS) where {R<:Real} + +Calculation of the classical Fisher information matrix for classical scenarios. +- `p`: The probability distribution. +- `dp`: Derivatives of the probability distribution on the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `eps`: Machine epsilon. +""" +function FIM(p::Vector{R}, dp::Vector{Vector{R}}; eps=GLOBAL_EPS) where {R<:Real} + m_num = length(p) + para_num = length(dp[1]) + + FIM_res = zeros(para_num, para_num) + for pj in 1:m_num + p_tp = p[pj] + Cadd = zeros(para_num, para_num) + if p_tp > eps + for para_i in 1:para_num + dp_i = dp[pj][para_i] + for para_j in para_i:para_num + dp_j = dp[pj][para_j] + Cadd[para_i,para_j] = real(dp_i * dp_j / p_tp) + Cadd[para_j,para_i] = real(dp_i * dp_j / p_tp) + end + end + FIM_res += Cadd + end + end + if length(dp[1]) == 1 + # single-parameter scenario + return FIM_res[1,1] + else + # multiparameter scenario + return FIM_res + end + +end + #======================================================# ################# Gaussian States QFIM ################# function Williamson_form(A::AbstractMatrix) @@ -521,7 +584,7 @@ function Williamson_form(A::AbstractMatrix) return S, c end -# const a_Gauss = [im*σ_y,σ_z,σ_x|>one, σ_x] +const a_Gauss = [im*σ_y,σ_z,σ_x|>one, σ_x] function A_Gauss(m::Int) e = bases(m) @@ -536,7 +599,6 @@ function G_Gauss(S::M, dC::VM, c::V) where {M<:AbstractMatrix,V,VM<:AbstractVect gs = [ [[inv(S) * ∂ₓC * inv(transpose(S)) * a' |> tr for a in A] for A in As] for ∂ₓC in dC ] - #[[inv(S)*∂ₓC*inv(transpose(S))*As[l][j,k]|>tr for j in 1:m, k in 1:m] for l in 1:4] G = [zero(S) for _ = 1:para_num] for i = 1:para_num @@ -559,29 +621,20 @@ end QFIM_Gauss(R̄::V, dR̄::VV, D::M, dD::VM) where {V,VV,M,VM<:AbstractVecOrMat} -Calculate the SLD based quantum Fisher information matrix (QFIM) with gaussian states. - +Calculate the SLD based quantum Fisher information matrix (QFIM) with gaussian states. - `R̄` : First-order moment. - -- `dR̄`: Derivatives of the first-order moment with respect to the unknown parameters to be -estimated. For example, dR[1] is the derivative vector on the first -parameter. - +- `dR̄`: Derivatives of the first-order moment with respect to the unknown parameters to be estimated. For example, dR[1] is the derivative vector on the first parameter. - `D`: Second-order moment. - -- `dD`: Derivatives of the second-order moment with respect to the unknown parameters to be -estimated. - -- `eps`: Machine epsilon - +- `dD`: Derivatives of the second-order moment with respect to the unknown parameters to be estimated. +- `eps`: Machine epsilon. """ function QFIM_Gauss(R̄::V, dR̄::VV, D::M, dD::VM) where {V,VV,M,VM<:AbstractVecOrMat} para_num = length(dR̄) quad_num = length(R̄) - C = [(D[i, j] + D[j, i]) / 2 - R̄[i]R̄[j] for i = 1:quad_num, j = 1:quad_num] + C = [D[i, j] - R̄[i]R̄[j] for i = 1:quad_num, j = 1:quad_num] dC = [ [ - (dD[k][i, j] + dD[k][j, i]) / 2 - dR̄[k][i]R̄[j] - R̄[i]dR̄[k][j] for + dD[k][i, j] - dR̄[k][i]R̄[j] - R̄[i]dR̄[k][j] for i = 1:quad_num, j = 1:quad_num ] for k = 1:para_num ] @@ -593,5 +646,9 @@ function QFIM_Gauss(R̄::V, dR̄::VV, D::M, dD::VM) where {V,VV,M,VM<:AbstractVe j = 1:para_num ] - F |> real + if para_num == 1 + return F[1,1] |> real + else + return F |> real + end end diff --git a/src/objective/AsymptoticBound/Holevo.jl b/src/ObjectiveFunc/AsymptoticBound/Holevo.jl similarity index 77% rename from src/objective/AsymptoticBound/Holevo.jl rename to src/ObjectiveFunc/AsymptoticBound/Holevo.jl index beba772..1e80313 100644 --- a/src/objective/AsymptoticBound/Holevo.jl +++ b/src/ObjectiveFunc/AsymptoticBound/Holevo.jl @@ -6,42 +6,43 @@ end """ - HCRB(ρ::Matrix{T},dρ::Vector{Matrix{T}},C::Matrix{Float64};eps = 1e-8,) where {T<:Complex} + HCRB(ρ::AbstractMatrix, dρ::AbstractVector, C::AbstractMatrix; eps=GLOBAL_EPS) Caltulate the Holevo Cramer-Rao bound (HCRB) via the semidefinite program (SDP). - - `ρ`: Density matrix. - - `dρ`: Derivatives of the density matrix on the unknown parameters to be estimated. For example, drho[0] is the derivative vector on the first parameter. - - `W`: Weight matrix. - - `eps`: Machine epsilon. - """ function HCRB( - ρ::Matrix{T}, - dρ::Vector{Matrix{T}}, - C::Matrix{Float64}; - eps = 1e-8, -) where {T<:Complex} + ρ::AbstractMatrix, + dρ::AbstractVector, + C::AbstractMatrix; + eps=GLOBAL_EPS, +) if length(dρ) == 1 println( - "In the single-parameter scenario, the HCRB is equivalent to the QFI. This function will return the value of the QFI", + "In the single-parameter scenario, the HCRB is equivalent to the QFI. This function will return the value of the QFI.", ) f = QFIM_SLD(ρ, dρ[1]; eps=eps) return f + elseif rank(C) == 1 + println( + "For rank-one wight matrix, the HCRB is equivalent to QFIM. This function will return the value of Tr(WF^{-1})." + ) + F = QFIM_SLD(ρ, dρ; eps=eps) + return tr(C*pinv(F)) else Holevo_bound(ρ, dρ, C; eps = eps) end end function Holevo_bound( - ρ::Matrix{T}, - dρ::Vector{Matrix{T}}, - C::Matrix{Float64}; - eps = eps_default, -) where {T<:Complex} + ρ::AbstractMatrix, + dρ::AbstractVector, + C::AbstractMatrix; + eps = GLOBAL_EPS, +) dim = size(ρ)[1] num = dim * dim @@ -86,10 +87,10 @@ function Holevo_bound( end function Holevo_bound_obj( - ρ::Matrix{T}, - dρ::Vector{Matrix{T}}, - C::Matrix{Float64}; - eps = eps_default, -) where {T<:Complex} + ρ::AbstractMatrix, + dρ::AbstractVector, + C::AbstractMatrix; + eps = GLOBAL_EPS, +) return Holevo_bound(ρ, dρ, C; eps = eps)[1] end diff --git a/src/objective/BayesianBound/BayesianBound.jl b/src/ObjectiveFunc/BayesianBound/BayesianBound.jl similarity index 100% rename from src/objective/BayesianBound/BayesianBound.jl rename to src/ObjectiveFunc/BayesianBound/BayesianBound.jl diff --git a/src/ObjectiveFunc/BayesianBound/BayesianCramerRao.jl b/src/ObjectiveFunc/BayesianBound/BayesianCramerRao.jl new file mode 100644 index 0000000..621bdae --- /dev/null +++ b/src/ObjectiveFunc/BayesianBound/BayesianCramerRao.jl @@ -0,0 +1,470 @@ +########## Bayesian version of CFIM ########## +@doc raw""" + + BCFIM(x::AbstractVector, p, rho, drho; M=missing, eps=GLOBAL_EPS) + +Calculation of the Bayesian classical Fisher information (BCFI) and the Bayesian classical Fisher information matrix (BCFIM) of the form +``\mathcal{I}_{\mathrm{Bayes}}=\int p(\textbf{x})\mathcal{I}\mathrm{d}\textbf{x}`` with ``\mathcal{I}`` the CFIM and ``p(\textbf{x})`` the prior distribution. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `eps`: Machine epsilon. +""" +function BCFIM(x::AbstractVector, p, rho, drho; M=missing, eps=GLOBAL_EPS) + para_num = length(x) + if para_num == 1 + #### singleparameter scenario #### + p_num = length(p) + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + F_tp = zeros(p_num) + for i in 1:p_num + F_tp[i] = CFIM(rho[i], drho[i][1], M; eps=eps) + end + F = 0.0 + arr = [p[i]*F_tp[i] for i in 1:p_num] + F = trapz(x[1], arr) + else + #### multiparameter scenario #### + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + + xnum = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + end +end + +########## Bayesian version of QFIM ########## +@doc raw""" + + BQFIM(x::AbstractVector, p, rho, drho; LDtype=:SLD, eps=GLOBAL_EPS) + +Calculation of the Bayesian quantum Fisher information (BQFI) and the Bayesian quantum Fisher information matrix (BQFIM) of the form +``\mathcal{F}_{\mathrm{Bayes}}=\int p(\textbf{x})\mathcal{F}\mathrm{d}\textbf{x}`` with ``\mathcal{F}`` the QFIM of all types and ``p(\textbf{x})`` the prior distribution. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are "SLD" (default), "RLD" and "LLD". +- `eps`: Machine epsilon. +""" +function BQFIM(x::AbstractVector, p, rho, drho; LDtype=:SLD, eps=GLOBAL_EPS) + para_num = length(x) + if para_num == 1 + #### singleparameter scenario #### + p_num = length(p) + F_tp = zeros(p_num) + for i in 1:p_num + F_tp[i] = QFIM(rho[i], drho[i][1]; LDtype=LDtype, eps=eps) + end + F = 0.0 + arr = [p[i]*F_tp[i] for i in 1:p_num] + F = trapz(x[1], arr) + else + #### multiparameter scenario #### + xnum = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + Fs = [p*QFIM(rho,drho;LDtype=LDtype,eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + end +end + +########## Bayesian quantum Cramer-Rao bound ########## +@doc raw""" + + BQCRB(x::AbstractVector, p, dp, rho, drho; b=missing, db=missing, LDtype=:SLD, btype=1, eps=GLOBAL_EPS) + +Calculation of the Bayesian quantum Cramer-Rao bound (BQCRB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `dp`: Derivatives of the prior distribution with respect to the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `b`: Vector of biases of the form ``\textbf{b}=(b(x_0),b(x_1),\dots)^{\mathrm{T}}``. +- `db`: Derivatives of b on the unknown parameters to be estimated, It should be expressed as ``\textbf{b}'=(\partial_0 b(x_0),\partial_1 b(x_1),\dots)^{\mathrm{T}}``. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are "SLD" (default), "RLD" and "LLD". +- `btype`: Types of the BCRB. Options are 1, 2 and 3. +- `eps`: Machine epsilon. +""" +function BQCRB(x::AbstractVector, p, dp, rho, drho; b=missing, db=missing, LDtype=:SLD, btype=1, eps=GLOBAL_EPS) + para_num = length(x) + + if ismissing(b) + b = [zero(x) for x in x] + db = [zero(x) for x in x] + end + if ismissing(db) + db = [zero(x) for x in x] + end + + if para_num == 1 + + #### singleparameter scenario #### + p_num = length(p) + + if typeof(drho[1]) == Vector{Matrix{ComplexF64}} + drho = [drho[i][1] for i in 1:p_num] + end + if typeof(b[1]) == Vector{Float64} || typeof(b[1]) == Vector{Int64} + b = b[1] + end + if typeof(db[1]) == Vector{Float64} || typeof(db[1]) == Vector{Int64} + db = db[1] + end + F_tp = zeros(p_num) + for i in 1:p_num + f = QFIM(rho[i], drho[i]; LDtype=LDtype, eps=eps) + F_tp[i] = f + end + F = 0.0 + if btype == 1 + arr = [p[i]*((1+db[i])^2/F_tp[i]+b[i]^2) for i in 1:p_num] + F = trapz(x[1], arr) + elseif btype == 2 + arr = [p[i]*F_tp[i] for i in 1:p_num] + F1 = trapz(x[1], arr) + arr2 = [p[j]*(1+db[j]) for j in 1:p_num] + B = trapz(x[1], arr2) + arr3 = [p[k]*b[k]^2 for k in 1:p_num] + bb = trapz(x[1], arr3) + F = B^2/F1+bb + elseif btype == 3 + I_tp = [real(dp[i]*dp[i]/p[i]^2) for i in 1:p_num] + arr = [p[j]*(dp[j]*b[j]/p[j]+(1 + db[j]))^2 / (I_tp[j] + F_tp[j]) for j in 1:p_num] + F = trapz(x[1], arr) + else + println("NameError: btype should be choosen in {1, 2, 3}.") + end + return F + else + #### multiparameter scenario #### + xnum = length(x) + bs = Iterators.product(b...) + dbs = Iterators.product(db...) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if btype == 1 + integrand1(p,rho,drho,b,db)=p*diagm(1 .+db)*pinv(QFIM(rho,drho;LDtype=LDtype,eps=eps))*diagm(1 .+db)+b*b' + integrands = [integrand1(p,rho,drho,[b...],[db...])|>vec for (p,rho,drho,b,db) in zip(p,rho,drho,bs,dbs)] + I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) + elseif btype == 2 + Bs = [p*(1 .+[db...]) for (p,db) in zip(p,dbs)] + B = trapzm(x, Bs, xnum)|> diagm + Fs = [p*QFIM(rho,drho;LDtype=LDtype,eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + bbts = [p*[b...]*[b...]'|>vec for (p,b) in zip(p,bs)] + I = B*pinv(F)*B + (trapzm(x, bbts, xnum^2) |> I->reshape(I,xnum,xnum)) + elseif btype == 3 + Ip(p,dp) = dp*dp'/p^2 + G = [G_mat(p,dp,[b...],[db...]) for (p,dp,b,db) in zip(p,dp,bs,dbs)] + integrand3(p,dp,rho,drho,G_tp)=p*G_tp*pinv(Ip(p,dp)+QFIM(rho,drho;LDtype=LDtype,eps=eps))*G_tp' + integrands = [integrand3(p,dp,rho,drho,G_tp)|>vec for (p,dp,rho,drho,G_tp) in zip(p,dp,rho,drho,G)] + I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) + else + println("NameError: btype should be choosen in {1, 2, 3}.") + end + return I + end +end + +@doc raw""" + + BCRB(x::AbstractVector, p, dp, rho, drho; M=missing, b=missing, db=missing, btype=1, eps=GLOBAL_EPS) + +Calculation of the Bayesian Cramer-Rao bound (BCRB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `dp`: Derivatives of the prior distribution with respect to the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `b`: Vector of biases of the form ``\textbf{b}=(b(x_0),b(x_1),\dots)^{\mathrm{T}}``. +- `db`: Derivatives of b on the unknown parameters to be estimated, It should be expressed as ``\textbf{b}'=(\partial_0 b(x_0),\partial_1 b(x_1),\dots)^{\mathrm{T}}``. +- `btype`: Types of the BCRB. Options are 1, 2 and 3. +- `eps`: Machine epsilon. +""" +function BCRB(x::AbstractVector, p, dp, rho, drho; M=missing, b=missing, db=missing, btype=1, eps=GLOBAL_EPS) + para_num = length(x) + + if ismissing(b) + b = [zero(x) for x in x] + db = [zero(x) for x in x] + end + if ismissing(db) + db = [zero(x) for x in x] + end + + if para_num == 1 + #### singleparameter scenario #### + p_num = length(p) + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + if typeof(drho[1]) == Vector{Matrix{ComplexF64}} + drho = [drho[i][1] for i in 1:p_num] + end + if typeof(b[1]) == Vector{Float64} || typeof(b[1]) == Vector{Int64} + b = b[1] + end + if typeof(db[1]) == Vector{Float64} || typeof(db[1]) == Vector{Int64} + db = db[1] + end + F_tp = zeros(p_num) + + for i in 1:p_num + f = CFIM(rho[i], drho[i], M; eps=eps) + F_tp[i] = f + end + F = 0.0 + if btype == 1 + arr = [p[i]*((1+db[i])^2/F_tp[i]+b[i]^2) for i in 1:p_num] + F = trapz(x[1], arr) + elseif btype == 2 + arr = [p[i]*F_tp[i] for i in 1:p_num] + F1 = trapz(x[1], arr) + arr2 = [p[j]*(1+db[j]) for j in 1:p_num] + B = trapz(x[1], arr2) + arr3 = [p[k]*b[k]^2 for k in 1:p_num] + bb = trapz(x[1], arr3) + F = B^2/F1+bb + elseif btype == 3 + I_tp = [real(dp[i]*dp[i]/p[i]^2) for i in 1:p_num] + arr = [p[j]*(dp[j]*b[j]/p[j]+(1 + db[j]))^2 / (I_tp[j] + F_tp[j]) for j in 1:p_num] + F = trapz(x[1], arr) + else + println("NameError: btype should be choosen in {1, 2, 3}") + end + return F + else + #### multiparameter scenario #### + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + + xnum = length(x) + bs = Iterators.product(b...) + dbs = Iterators.product(db...) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if btype == 1 + integrand1(p,rho,drho,b,db)=p*diagm(1 .+db)*pinv(CFIM(rho,drho,M;eps=eps))*diagm(1 .+db)+b*b' + integrands = [integrand1(p,rho,drho,[b...],[db...])|>vec for (p,rho,drho,b,db) in zip(p,rho,drho,bs,dbs)] + I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) + elseif btype == 2 + Bs = [p*(1 .+[db...]) for (p,db) in zip(p,dbs)] + B = trapzm(x, Bs, xnum)|> diagm + Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + bbts = [p*[b...]*[b...]'|>vec for (p,b) in zip(p,bs)] + I = B*pinv(F)*B + (trapzm(x, bbts, xnum^2) |> I->reshape(I,xnum,xnum)) + elseif btype == 3 + Ip(p,dp) = dp*dp'/p^2 + G = [G_mat(p,dp,[b...],[db...]) for (p,dp,b,db) in zip(p,dp,bs,dbs)] + integrand3(p,dp,rho,drho,G_tp)=p*G_tp*pinv(Ip(p,dp)+CFIM(rho,drho,M;eps=eps))*G_tp' + integrands = [integrand3(p,dp,rho,drho,G_tp)|>vec for (p,dp,rho,drho,G_tp) in zip(p,dp,rho,drho,G)] + I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) + else + println("NameError: btype should be choosen in {1, 2, 3}.") + end + return I + end +end + +function G_mat(p, dp, b, db) + para_num = length(db) + G_tp = zeros(para_num, para_num) + for i in 1:para_num + for j in 1:para_num + if i == j + G_tp[i,j] = dp[j]*b[i]/p + (1+db[i]) + else + G_tp[i,j] = dp[j]*b[i]/p + end + end + end + return G_tp +end + +""" + + QVTB(x::AbstractVector, p, dp, rho, drho; LDtype=:SLD, eps=GLOBAL_EPS) + +Calculation of the Bayesian version of Cramer-Rao bound in troduced by Van Trees (VTB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `dp`: Derivatives of the prior distribution with respect to the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are "SLD" (default), "RLD" and "LLD". +- `eps`: Machine epsilon. +""" +function QVTB(x::AbstractVector, p, dp, rho, drho; LDtype=:SLD, eps=GLOBAL_EPS) + para_num = length(x) + if para_num == 1 + #### singleparameter scenario #### + p_num = length(p) + if typeof(drho[1]) == Vector{Matrix{ComplexF64}} + drho = [drho[i][1] for i in 1:p_num] + end + if typeof(dp[1]) == Vector{Float64} + dp = [dp[i][1] for i in 1:p_num] + end + F_tp = zeros(p_num) + for m in 1:p_num + F_tp[m] = QFIM(rho[m], drho[m]; LDtype=LDtype, eps=eps) + end + + arr1 = [real(dp[i]*dp[i]/p[i]) for i in 1:p_num] + I = trapz(x[1], arr1) + arr2 = [real(F_tp[j]*p[j]) for j in 1:p_num] + F = trapz(x[1], arr2) + I = 1.0/(I+F) + return I + else + #### multiparameter scenario #### + xnum = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + Ip(p,dp) = dp*dp'/p^2 + + Iprs = [p*Ip(p,dp)|>vec for (p,dp) in zip(p,dp)] + Ipr = trapzm(x, Iprs, xnum^2)|> I->reshape(I,xnum,xnum) + Fs = [p*QFIM(rho,drho;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + I = pinv(Ipr+F) + return I + end +end + +""" + + VTB(x::AbstractVector, p, dp, rho, drho; M=missing, eps=GLOBAL_EPS) + +Calculation of the Bayesian version of Cramer-Rao bound introduced by Van Trees (VTB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `dp`: Derivatives of the prior distribution with respect to the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `eps`: Machine epsilon. +""" +function VTB(x::AbstractVector, p, dp, rho, drho; M=missing, eps=GLOBAL_EPS) + para_num = length(x) + if para_num == 1 + #### singleparameter scenario #### + p_num = length(p) + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + if typeof(drho[1]) == Vector{Matrix{ComplexF64}} + drho = [drho[i][1] for i in 1:p_num] + end + if typeof(dp[1]) == Vector{Float64} + dp = [dp[i][1] for i in 1:p_num] + end + F_tp = zeros(p_num) + for m in 1:p_num + F_tp[m] = CFIM(rho[m], drho[m], M; eps=eps) + end + + arr1 = [real(dp[i]*dp[i]/p[i]) for i in 1:p_num] + I = trapz(x[1], arr1) + arr2 = [real(F_tp[j]*p[j]) for j in 1:p_num] + F = trapz(x[1], arr2) + res = 1.0/(I+F) + return res + else + #### multiparameter scenario #### + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + xnum = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + Ip(p,dp) = dp*dp'/p^2 + + Iprs = [p*Ip(p,dp)|>vec for (p,dp) in zip(p,dp)] + Ipr = trapzm(x, Iprs, xnum^2)|> I->reshape(I,xnum,xnum) + Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] + F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) + I = pinv(Ipr+F) + return I + end +end + +########## optimal biased bound ########## +function OBB_func(du, u, para, t) + F, J, x = para + J_tp = interp1(x, J, t) + F_tp = interp1(x, F, t) + bias = u[1] + dbias = u[2] + du[1] = dbias + du[2] = -J_tp*dbias + F_tp*bias - J_tp +end + +function boundary_condition(residual, u, p, t) + residual[1] = u[1][2] + 1.0 + residual[2] = u[end][2] + 1.0 +end + +function interp1(xspan, yspan, x) + idx = (x .>= xspan[1]) .& (x .<= xspan[end]) + intf = interpolate((xspan,), yspan, Gridded(Linear())) + y = intf[x[idx]] + return y +end + +""" + + OBB(x::AbstractVector, p, dp, rho, drho, d2rho; LDtype=:SLD, eps=GLOBAL_EPS) + +Calculation of the Bayesian version of Cramer-Rao bound introduced by Van Trees (VTB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `dp`: Derivatives of the prior distribution with respect to the unknown parameters to be estimated. For example, dp[0] is the derivative vector on the first parameter. +- `rho`: Parameterized density matrix. +- `drho`: Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `d2rho`: Second order Derivatives of the parameterized density matrix (rho) with respect to the unknown parameters to be estimated. +- `LDtype`: Types of QFI (QFIM) can be set as the objective function. Options are "SLD" (default), "RLD" and "LLD". +- `eps`: Machine epsilon. +""" +function OBB(x::AbstractVector, p, dp, rho, drho, d2rho; LDtype=:SLD, eps=GLOBAL_EPS) + p_num = length(p) + + if typeof(drho[1]) == Vector{Matrix{ComplexF64}} + drho = [drho[i][1] for i in 1:p_num] + end + if typeof(d2rho[1]) == Vector{Matrix{ComplexF64}} + d2rho = [d2rho[i][1] for i in 1:p_num] + end + if typeof(dp[1]) == Vector{Float64} + dp = [dp[i][1] for i in 1:p_num] + end + if typeof(x[1]) != Float64 || typeof(x[1]) != Int64 + x = x[1] + end + + delta = x[2] - x[1] + F, J = zeros(p_num), zeros(p_num) + for m in 1:p_num + f, LD = QFIM(rho[m], drho[m], LDtype=LDtype, exportLD=true) + dF = real(tr(2*d2rho[m]*d2rho[m]*LD - LD*LD*drho[m])) + J[m] = dp[m]/p[m] - dF/f + F[m] = f + end + + prob = BVProblem(OBB_func, boundary_condition, [0.0, 0.0], (x[1], x[end]), (F, J, x)) + sol = solve(prob, GeneralMIRK4(), dt=delta) + + bias = [sol.u[i][1] for i in 1:p_num] + dbias = [sol.u[i][2] for i in 1:p_num] + + value = [p[i]*((1+dbias[i])^2/F[i] + bias[i]^2) for i in 1:p_num] + return trapz(x, value) +end diff --git a/src/objective/BayesianBound/ZivZakai.jl b/src/ObjectiveFunc/BayesianBound/ZivZakai.jl similarity index 81% rename from src/objective/BayesianBound/ZivZakai.jl rename to src/ObjectiveFunc/BayesianBound/ZivZakai.jl index f57a9c2..6b9f31f 100644 --- a/src/objective/BayesianBound/ZivZakai.jl +++ b/src/ObjectiveFunc/BayesianBound/ZivZakai.jl @@ -22,7 +22,17 @@ end prior_uniform(W=1., μ=0.) = x -> abs(x-μ)>abs(W/2) ? 0 : 1/W -function QZZB(x::AbstractVector, p::AbstractVector, rho::AbstractVecOrMat; eps=1e-8, ν::Number=1) +""" + + QZZB(x::AbstractVector, p::AbstractVector, rho::AbstractVecOrMat; eps=GLOBAL_EPS) + +Calculation of the quantum Ziv-Zakai bound (QZZB). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `eps`: Machine epsilon. +""" +function QZZB(x::AbstractVector, p::AbstractVector, rho::AbstractVecOrMat; eps=GLOBAL_EPS, ν::Number=1) if typeof(x[1]) == Vector{Float64} || typeof(x[1]) == Vector{Int64} x = x[1] end diff --git a/src/objective/objective.jl b/src/ObjectiveFunc/ObjectiveFunc.jl similarity index 100% rename from src/objective/objective.jl rename to src/ObjectiveFunc/ObjectiveFunc.jl diff --git a/src/OptScenario/OptScenario.jl b/src/OptScenario/OptScenario.jl new file mode 100644 index 0000000..10bf9fd --- /dev/null +++ b/src/OptScenario/OptScenario.jl @@ -0,0 +1,215 @@ +abstract type AbstractOpt end + +abstract type AbstractMeasurementType end +abstract type Projection <: AbstractMeasurementType end +abstract type LC <: AbstractMeasurementType end +abstract type Rotation <: AbstractMeasurementType end + +abstract type Opt <: AbstractOpt end + +mutable struct ControlOpt <: Opt + ctrl::Union{AbstractVector, Missing} + ctrl_bound::AbstractVector + rng::AbstractRNG +end + +""" + + ControlOpt(ctrl=missing, ctrl_bound=[-Inf, Inf], seed=1234) + +Control optimization. +- `ctrl`: Guessed control coefficients. +- `ctrl_bound`: Lower and upper bounds of the control coefficients. +- `seed`: Random seed. +""" +ControlOpt(;ctrl=missing, ctrl_bound=[-Inf, Inf], seed=1234) = ControlOpt(ctrl, ctrl_bound, MersenneTwister(seed)) + +Copt = ControlOpt +ControlOpt(ctrl::Matrix{R}, ctrl_bound::AbstractVector) where R<:Number = ControlOpt([c[:] for c in eachrow(ctrl)], ctrl_bound) + +mutable struct StateOpt <: Opt + psi::Union{AbstractVector, Missing} + rng::AbstractRNG +end + +""" + + StateOpt(psi=missing, seed=1234) + +State optimization. +- `psi`: Guessed probe state. +- `seed`: Random seed. +""" +StateOpt(;psi=missing, seed=1234) = StateOpt(psi, MersenneTwister(seed)) + +Sopt = StateOpt + +abstract type AbstractMopt <: Opt end + +mutable struct Mopt_Projection <: AbstractMopt + M::Union{AbstractVector, Missing} + rng::AbstractRNG +end + +Mopt_Projection(;M=missing, seed=1234) = Mopt_Projection(M, MersenneTwister(seed)) + +mutable struct Mopt_LinearComb <: AbstractMopt + B::Union{AbstractVector, Missing} + POVM_basis::Union{AbstractVector, Missing} + M_num::Int + rng::AbstractRNG +end + +Mopt_LinearComb(;B=missing, POVM_basis=missing, M_num=1, seed=1234) = Mopt_LinearComb(B, POVM_basis, M_num, MersenneTwister(seed)) + +mutable struct Mopt_Rotation <: AbstractMopt + s::Union{AbstractVector, Missing} + POVM_basis::Union{AbstractVector, Missing} + Lambda::Union{AbstractVector, Missing} + rng::AbstractRNG +end + +Mopt_Rotation(;s=missing, POVM_basis=missing, Lambda=missing, seed=1234) = Mopt_Rotation(s, POVM_basis, Lambda, MersenneTwister(seed)) + + +""" + + MeasurementOpt(mtype=:Projection, kwargs...) + +Measurement optimization. +- `mtype`: The type of scenarios for the measurement optimization. Options are `:Projection` (default), `:LC` and `:Rotation`. +- `kwargs...`: keywords and the correponding default vaules. `mtype=:Projection`, `mtype=:LC` and `mtype=:Rotation`, the `kwargs...` are `M=missing`, `B=missing, POVM_basis=missing`, and `s=missing, POVM_basis=missing`, respectively. +""" +function MeasurementOpt(;mtype=:Projection, kwargs...) + if mtype==:Projection + return Mopt_Projection(;kwargs...) + elseif mtype==:LC + return Mopt_LinearComb(;kwargs...) + elseif mtype==:Rotation + return Mopt_Rotation(;kwargs...) + end +end + +Mopt = MeasurementOpt + +abstract type CompOpt <: Opt end + +mutable struct StateControlOpt <: CompOpt + psi::Union{AbstractVector, Missing} + ctrl::Union{AbstractVector, Missing} + ctrl_bound::AbstractVector + rng::AbstractRNG +end + +StateControlOpt(;psi=missing, ctrl=missing, ctrl_bound=[-Inf, Inf], seed=1234) = StateControlOpt(psi, ctrl, ctrl_bound, MersenneTwister(seed)) + +""" + + SCopt(psi=missing, ctrl=missing, ctrl_bound=[-Inf, Inf], seed=1234) + +State and control optimization. +- `psi`: Guessed probe state. +- `ctrl`: Guessed control coefficients. +- `ctrl_bound`: Lower and upper bounds of the control coefficients. +- `seed`: Random seed. +""" +SCopt = StateControlOpt + +mutable struct ControlMeasurementOpt <: CompOpt + ctrl::Union{AbstractVector, Missing} + M::Union{AbstractVector, Missing} + ctrl_bound::AbstractVector + rng::AbstractRNG +end + +ControlMeasurementOpt(;ctrl=missing, M=missing, ctrl_bound=[-Inf, Inf], seed=1234) = ControlMeasurementOpt(ctrl, M, ctrl_bound, MersenneTwister(seed)) + +""" + + CMopt(ctrl=missing, M=missing, ctrl_bound=[-Inf, Inf], seed=1234) + +Control and measurement optimization. +- `ctrl`: Guessed control coefficients. +- `M`: Guessed projective measurement (a set of basis) +- `ctrl_bound`: Lower and upper bounds of the control coefficients. +- `seed`: Random seed. +""" +CMopt = ControlMeasurementOpt + +mutable struct StateMeasurementOpt <: CompOpt + psi::Union{AbstractVector, Missing} + M::Union{AbstractVector, Missing} + rng::AbstractRNG +end + +StateMeasurementOpt(;psi=missing, M=missing, seed=1234) = StateMeasurementOpt(psi, M, MersenneTwister(seed)) +""" + + SMopt(psi=missing, M=missing, seed=1234) + +State and control optimization. +- `psi`: Guessed probe state. +- `M`: Guessed projective measurement (a set of basis). +- `seed`: Random seed. +""" +SMopt = StateMeasurementOpt + +mutable struct StateControlMeasurementOpt <: CompOpt + psi::Union{AbstractVector, Missing} + ctrl::Union{AbstractVector, Missing} + M::Union{AbstractVector, Missing} + ctrl_bound::AbstractVector + rng::AbstractRNG +end + +StateControlMeasurementOpt(;psi=missing, ctrl=missing, M=missing, ctrl_bound=[-Inf, Inf], seed=1234) = StateControlMeasurementOpt(psi, ctrl, M, ctrl_bound, MersenneTwister(seed)) + +""" + + SCMopt(psi=missing, ctrl=missing, M=missing, ctrl_bound=[-Inf, Inf], seed=1234) + +State, control and measurement optimization. +- `psi`: Guessed probe state. +- `ctrl`: Guessed control coefficients. +- `M`: Guessed projective measurement (a set of basis). +- `ctrl_bound`: Lower and upper bounds of the control coefficients. +- `seed`: Random seed. +""" +SCMopt = StateControlMeasurementOpt + +opt_target(::ControlOpt) = :Copt +opt_target(::StateOpt) = :Sopt +opt_target(::Mopt_Projection) = :Mopt +opt_target(::Mopt_LinearComb) = :Mopt_input +opt_target(::Mopt_Rotation) = :Mopt_input +opt_target(::CompOpt) = :CompOpt +opt_target(::StateControlOpt) = :SCopt +opt_target(::ControlMeasurementOpt) = :CMopt +opt_target(::StateMeasurementOpt) = :SMopt +opt_target(::StateControlMeasurementOpt) = :SCMopt + +result(opt::ControlOpt) = [opt.ctrl] +result(opt::StateOpt) = [opt.psi] +result(opt::Mopt_Projection) = [opt.M] +result(opt::Mopt_LinearComb) = [opt.B, opt.POVM_basis, opt.M_num] +result(opt::Mopt_Rotation) = [opt.s] +result(opt::StateControlOpt) = [opt.psi, opt.ctrl] +result(opt::ControlMeasurementOpt) = [opt.ctrl, opt.M] +result(opt::StateMeasurementOpt) = [opt.psi, opt.M] +result(opt::StateControlMeasurementOpt) = [opt.psi, opt.ctrl, opt.M] + +#with reward +result(opt, ::Type{Val{:save_reward}}) = [result(opt)..., [0.0]] + +const res_file_name = Dict( + :Copt => ["controls.csv"], + :Sopt => ["states.csv"], + :Mopt => ["measurements.csv"], + :Mopt_input => ["measurements.csv"], + :SCopt => ["states.csv", "controls.csv"], + :CMopt => ["controls.csv", "measurements.csv"], + :SMopt => ["states.csv", "measurements.csv"], + :SCMopt => ["states.csv", "controls.csv", "measurements.csv"], +) + +res_file(opt::AbstractOpt) = res_file_name[opt_target(opt)] diff --git a/src/dynamics/kraus/Kraus.jl b/src/Parameterization/Kraus/Kraus.jl similarity index 100% rename from src/dynamics/kraus/Kraus.jl rename to src/Parameterization/Kraus/Kraus.jl diff --git a/src/Parameterization/Kraus/KrausData.jl b/src/Parameterization/Kraus/KrausData.jl new file mode 100644 index 0000000..b4e93b4 --- /dev/null +++ b/src/Parameterization/Kraus/KrausData.jl @@ -0,0 +1,48 @@ +abstract type KrausDynamicsData <: AbstractDynamicsData end + +mutable struct Kraus_dm <: KrausDynamicsData + ρ0::AbstractMatrix + K::AbstractVector + dK::AbstractVecOrMat +end + +mutable struct Kraus_pure <: KrausDynamicsData + ψ0::AbstractVector + K::AbstractVector + dK::AbstractVecOrMat +end + +# Constructor for Kraus dynamics +@doc raw""" + + Kraus(ρ0::AbstractMatrix, K::AbstractVector, dK::AbstractVector) + +The parameterization of a state is ``\rho=\sum_i K_i\rho_0K_i^{\dagger}`` with ``\rho`` the evolved density matrix and ``K_i`` the Kraus operator. +- `ρ0`: Initial state (density matrix). +- `K`: Kraus operators. +- `dK`: Derivatives of the Kraus operators with respect to the unknown parameters to be estimated. For example, dK[0] is the derivative vector on the first parameter. +""" +Kraus(ρ0::AbstractMatrix, K::AbstractVector, dK::AbstractVector) = + Kraus{dm}(Kraus_dm(ρ0, K, dK), :noiseless, :free, :dm) +@doc raw""" + + Kraus(ψ0::AbstractMatrix, K::AbstractVector, dK::AbstractVector) + +The parameterization of a state is ``\psi\rangle=\sum_i K_i|\psi_0\rangle`` with ``\psi`` the evolved state and ``K_i`` the Kraus operator. +- `ψ0`: Initial state (ket). +- `K`: Kraus operators. +- `dK`: Derivatives of the Kraus operators with respect to the unknown parameters to be estimated. For example, dK[0] is the derivative vector on the first parameter. +""" +Kraus(ψ0::AbstractVector, K::AbstractVector, dK::AbstractVector) = + Kraus{ket}(Kraus_pure(ψ0, K, dK), :noiseless, :free, :ket) +Kraus(ρ0::AbstractMatrix, K::AbstractVector, dK::AbstractMatrix) = + Kraus{dm}(Kraus_dm(ρ0, K, [[dK[i,j,:,:][1] for j in 1:size(dK,2)] for i in 1:size(dK,1)]), :noiseless, :free, :dm) +Kraus(ψ0::AbstractVector, K::AbstractVector, dK::AbstractMatrix) = + Kraus{ket}(Kraus_pure(ψ0, K,[[dK[i,j,:,:][1] for j in 1:size(dK,2)] for i in 1:size(dK,1)]), :noiseless, :free, :ket) + +para_type(data::KrausDynamicsData) = length(data.dK[1]) == 1 ? :single_para : :multi_para + +get_dim(k::Kraus_dm) = size(k.ρ0, 1) +get_dim(k::Kraus_pure) = size(k.ψ0, 1) + +get_para(k::KrausDynamicsData) = length(k.dK[1]) diff --git a/src/dynamics/kraus/KrausDynamics.jl b/src/Parameterization/Kraus/KrausDynamics.jl similarity index 69% rename from src/dynamics/kraus/KrausDynamics.jl rename to src/Parameterization/Kraus/KrausDynamics.jl index 4056f95..1f27352 100644 --- a/src/dynamics/kraus/KrausDynamics.jl +++ b/src/Parameterization/Kraus/KrausDynamics.jl @@ -1,6 +1,12 @@ #### evolution of pure states under time-independent Hamiltonian without noise and controls #### +""" + + evolve(dynamics::Kraus{ket}) + +Evolution of pure states under time-independent Hamiltonian without noise and controls +""" function evolve(dynamics::Kraus{ket}) - (; K, dK, ψ0) = dynamics.data + (; ψ0, K, dK) = dynamics.data ρ0 = ψ0 * ψ0' K_num = length(K) para_num = length(dK[1]) @@ -11,8 +17,14 @@ function evolve(dynamics::Kraus{ket}) end #### evolution of density matrix under time-independent Hamiltonian without noise and controls #### +""" + + evolve(dynamics::Kraus{dm}) + +Evolution of density matrix under time-independent Hamiltonian without noise and controls. +""" function evolve(dynamics::Kraus{dm}) - (; K, dK, ρ0) = dynamics.data + (; ρ0, K, dK) = dynamics.data K_num = length(K) para_num = length(dK[1]) ρ = [K[i] * ρ0 * K[i]' for i in 1:K_num] |> sum diff --git a/src/Parameterization/Kraus/KrausWrapper.jl b/src/Parameterization/Kraus/KrausWrapper.jl new file mode 100644 index 0000000..58190bb --- /dev/null +++ b/src/Parameterization/Kraus/KrausWrapper.jl @@ -0,0 +1,63 @@ +""" + + Kraus(opt::StateOpt, K, dK) + +Initialize the parameterization described by the Kraus operators for the state optimization. +""" + +function Kraus(opt::StateOpt, K, dK) + (;psi) = opt + dim = size(K[1], 1) + if ismissing(psi) + r_ini = 2*rand(opt.rng, dim) - ones(dim) + r = r_ini ./ norm(r_ini) + ϕ = 2pi*rand(opt.rng, dim) + psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] + opt.psi = psi + end + + K = complex.(K) + dK = [complex.(dk) for dk in dK] + psi = complex(psi) + + Kraus(psi, K, dK) +end +""" + + Kraus(opt::AbstractMopt, ρ₀::AbstractMatrix, K, dK; eps=GLOBAL_EPS) + +Initialize the parameterization described by the Kraus operators for the measurement optimization. +""" +function Kraus(opt::AbstractMopt, ρ₀::AbstractMatrix, K, dK; eps=GLOBAL_EPS) + dim = size(ρ₀, 1) + _ini_measurement!(opt, dim; eps=eps) + + K = complex.(K) + dK = [complex.(dk) for dk in dK] + ρ₀ = complex(ρ₀) + Kraus(ρ₀, K, dK) +end + +""" + + Kraus(opt::CompOpt, K, dK; eps=GLOBAL_EPS) + +Initialize the parameterization described by the Kraus operators for the comprehensive optimization. +""" +function Kraus(opt::CompOpt, K, dK; eps=GLOBAL_EPS) + (;psi) = opt + dim = size(K[1], 1) + if ismissing(psi) + r_ini = 2*rand(opt.rng, dim) - ones(dim) + r = r_ini ./ norm(r_ini) + ϕ = 2pi*rand(opt.rng, dim) + psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] + opt.psi = psi + end + + _ini_measurement!(opt, dim; eps=eps) + K = complex.(K) + dK = [complex.(dk) for dk in dK] + psi = complex(psi) + Kraus(psi, K, dK) +end \ No newline at end of file diff --git a/src/dynamics/lindblad/Lindblad.jl b/src/Parameterization/Lindblad/Lindblad.jl similarity index 100% rename from src/dynamics/lindblad/Lindblad.jl rename to src/Parameterization/Lindblad/Lindblad.jl diff --git a/src/dynamics/lindblad/LindbladData.jl b/src/Parameterization/Lindblad/LindbladData.jl similarity index 99% rename from src/dynamics/lindblad/LindbladData.jl rename to src/Parameterization/Lindblad/LindbladData.jl index 06ca73c..c809585 100644 --- a/src/dynamics/lindblad/LindbladData.jl +++ b/src/Parameterization/Lindblad/LindbladData.jl @@ -155,7 +155,6 @@ Lindblad( :noiseless, :controlled, ) - Lindblad( H0::AbstractVecOrMat, dH::AbstractVector, diff --git a/src/dynamics/lindblad/LindbladDynamics.jl b/src/Parameterization/Lindblad/LindbladDynamics.jl similarity index 90% rename from src/dynamics/lindblad/LindbladDynamics.jl rename to src/Parameterization/Lindblad/LindbladDynamics.jl index e840e9e..fbc6d95 100644 --- a/src/dynamics/lindblad/LindbladDynamics.jl +++ b/src/Parameterization/Lindblad/LindbladDynamics.jl @@ -174,6 +174,19 @@ function expm( ρt_all |> vec2mat, ∂ρt_∂x_all |> vec2mat end +@doc raw""" + +expm(tspan::AbstractVector, ρ0::AbstractMatrix, H0::AbstractMatrix, dH::AbstractVector, decay::Union{AbstractVector, Missing}=missing, Hc::Union{AbstractVector, Missing}=missing, ctrl::Union{AbstractVector, Missing}=missing) + +The dynamics of a density matrix is of the form ``\partial_t\rho=-i[H,\rho]+\sum_i \gamma_i\left(\Gamma_i\rho\Gamma^{\dagger}_i-\frac{1}{2}\left\{\rho,\Gamma^{\dagger}_i \Gamma_i \right\}\right)``, where ``\rho`` is the evolved density matrix, ``H`` is the Hamiltonian of the system, ``\Gamma_i`` and ``\gamma_i`` are the ``i\mathrm{th}`` decay operator and the corresponding decay rate. +- `tspan`: Time length for the evolution. +- `ρ0`: Initial state (density matrix). +- `H0`: Free Hamiltonian. +- `dH`: Derivatives of the free Hamiltonian with respect to the unknown parameters to be estimated. For example, dH[0] is the derivative vector on the first parameter. +- `decay`: Decay operators and the corresponding decay rates. Its input rule is decay=[[``\Gamma_1``, ``\gamma_1``], [``\Gamma_2``, ``\gamma_2``],...], where ``\Gamma_1`` ``(\Gamma_2)`` represents the decay operator and ``\gamma_1`` ``(\gamma_2)`` is the corresponding decay rate. +- `Hc`: Control Hamiltonians. +- `ctrl`: Control coefficients. +""" function expm( tspan::AbstractVector, ρ0::AbstractMatrix, @@ -324,17 +337,16 @@ end expm(dynamics::Lindblad) = expm(dynamics.data...) - function secondorder_derivative( - H0, - dH::Vector{Matrix{T}}, - dH_∂x::Vector{Matrix{T}}, - ρ0::Matrix{T}, + tspan::AbstractVector, + ρ0::AbstractMatrix, + H0::AbstractMatrix, + dH::AbstractVector, + dH_∂x::AbstractVector, decay_opt::Vector{Matrix{T}}, γ, Hc::Vector{Matrix{T}}, ctrl::Vector{Vector{R}}, - tspan, ) where {T<:Complex,R<:Real} para_num = length(dH) @@ -418,59 +430,6 @@ function evolve(dynamics::Lindblad{noiseless,free,dm}) ρt |> vec2mat, ∂ρt_∂x |> vec2mat end -#### evolution of pure states under time-independent Hamiltonian without noise and controls #### -function evolve(dynamics::Lindblad{noiseless,free,ket}) - (; H0, dH, ψ0, tspan) = dynamics.data - - para_num = length(dH) - Δt = tspan[2] - tspan[1] - U = exp(-im * H0 * Δt) - ψt = ψ0 - ∂ψ∂x = [ψ0 |> zero for i = 1:para_num] - for t = 2:length(tspan) - ψt = U * ψt - ∂ψ∂x = [-im * Δt * dH[i] * ψt for i = 1:para_num] + [U] .* ∂ψ∂x - end - ρt = ψt * ψt' - ∂ρt_∂x = [(∂ψ∂x[i] * ψt' + ψt * ∂ψ∂x[i]') for i = 1:para_num] - ρt, ∂ρt_∂x -end - -#### evolution of pure states under time-dependent Hamiltonian without noise and controls #### -function evolve(dynamics::Lindblad{noiseless,timedepend,ket}) - (; H0, dH, ψ0, tspan) = dynamics.data - - para_num = length(dH) - dH_L = [liouville_commu(dH[i]) for i = 1:para_num] - ρt = (ψ0 * ψ0') |> vec - ∂ρt_∂x = [ρt |> zero for i = 1:para_num] - for t = 2:length(tspan) - Δt = tspan[t] - tspan[t-1] # tspan may not be equally spaced - exp_L = expL(H0[t-1], Δt) - ρt = exp_L * ρt - ∂ρt_∂x = [-im * Δt * dH_L[i] * ρt for i = 1:para_num] + [exp_L] .* ∂ρt_∂x - end - # ρt = exp(vec(H0[end])' * zero(ρt)) * ρt - ρt |> vec2mat, ∂ρt_∂x |> vec2mat -end - -#### evolution of density matrix under time-independent Hamiltonian without noise and controls #### -function evolve(dynamics::Lindblad{noiseless,free,dm}) - (; H0, dH, ρ0, tspan) = dynamics.data - - para_num = length(dH) - Δt = tspan[2] - tspan[1] - exp_L = expL(H0, Δt) - dH_L = [liouville_commu(dH[i]) for i = 1:para_num] - ρt = ρ0 |> vec - ∂ρt_∂x = [ρt |> zero for i = 1:para_num] - for t = 2:length(tspan) - ρt = exp_L * ρt - ∂ρt_∂x = [-im * Δt * dH_L[i] * ρt for i = 1:para_num] + [exp_L] .* ∂ρt_∂x - end - # ρt = exp(vec(H0[end])' * zero(ρt)) * ρt - ρt |> vec2mat, ∂ρt_∂x |> vec2mat -end #### evolution of density matrix under time-dependent Hamiltonian without noise and controls #### function evolve(dynamics::Lindblad{noiseless,timedepend,dm}) @@ -646,9 +605,10 @@ function propagate( H = Htot(H0, Hc, a) dH_L = [liouville_commu(dH) for dH in dH] exp_L = expL(H, decay_opt, γ, Δt) - dρₜ_next = [dρₜ|>vec for dρₜ in dρₜ ] - ρₜ_next = exp_L * vec(ρₜ ) + dρₜ_next = [dρₜ|>vec for dρₜ in dρₜ] + ρₜ_next = ρₜ for i in 1:ctrl_interval + ρₜ_next = exp_L * vec(ρₜ_next) for para = 1:para_num dρₜ_next[para] = -im * Δt * dH_L[para] * ρₜ_next + exp_L * dρₜ_next[para] end @@ -670,9 +630,10 @@ function propagate( H = Htot(H0, Hc, a) dH_L = [liouville_commu(dH) for dH in dH] exp_L = expL(H, Δt) - dρₜ_next = [dρₜ|>vec for dρₜ in dρₜ ] - ρₜ_next = exp_L * vec(ρₜ ) + dρₜ_next = [dρₜ|>vec for dρₜ in dρₜ] + ρₜ_next = ρₜ for i in 1:ctrl_interval + ρₜ_next = exp_L * vec(ρₜ_next) for para = 1:para_num dρₜ_next[para] = -im * Δt * dH_L[para] * ρₜ_next + exp_L * dρₜ_next[para] end diff --git a/src/dynamics/lindblad/LindbladWrapper.jl b/src/Parameterization/Lindblad/LindbladWrapper.jl similarity index 77% rename from src/dynamics/lindblad/LindbladWrapper.jl rename to src/Parameterization/Lindblad/LindbladWrapper.jl index 4a27381..7f4fba1 100644 --- a/src/dynamics/lindblad/LindbladWrapper.jl +++ b/src/Parameterization/Lindblad/LindbladWrapper.jl @@ -1,5 +1,11 @@ # wrapper for Lindblad dynamics with ControlOpt -function Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) +""" + + Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the control optimization. +""" +function Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) (;ctrl) = opt dim = size(ρ₀, 1) if ismissing(dH) @@ -47,16 +53,22 @@ function Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, rng= Lindblad(H0, dH, Hc, ctrl, ρ₀, tspan, decay_opt, γ) end -Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, ρ₀, H0, dH, Hc; decay=decay, rng=rng, eps=eps) +Lindblad(opt::ControlOpt, tspan, ρ₀, H0, dH, Hc, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, ρ₀, H0, dH, Hc; decay=decay, eps=eps) + +""" -function Lindblad(opt::StateOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) + Lindblad(opt::StateOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing, eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the state optimization. +""" +function Lindblad(opt::StateOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing, eps=GLOBAL_EPS) (;psi) = opt dim = H0 isa AbstractVector ? size(H0[1], 1) : size(H0, 1) if ismissing(psi) - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini ./ norm(r_ini) - ϕ = 2pi*rand(rng, dim) + ϕ = 2pi*rand(opt.rng, dim) psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] opt.psi = psi end @@ -128,27 +140,25 @@ function Lindblad(opt::StateOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay= end end -Lindblad(opt::StateOpt, tspan, H0, dH, Hc, ctrl, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, rng=rng, eps=eps) +Lindblad(opt::StateOpt, tspan, H0, dH, Hc, ctrl, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, eps=eps) -function _ini_measurement!(opt::Mopt_Projection, dim::Int, rng; eps=GLOBAL_EPS) +function _ini_measurement!(opt::Mopt_Projection, dim::Int; eps=GLOBAL_EPS) (; M) = opt ## initialize the Mopt target M + C = [ComplexF64[] for _ in 1:dim] if ismissing(M) - M = [ComplexF64[] for _ in 1:dim] for i in 1:dim - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini/norm(r_ini) - ϕ = 2pi*rand(rng, dim) - M[i] = [r*exp(im*ϕ) for (r,ϕ) in zip(r,ϕ)] + ϕ = 2pi*rand(opt.rng, dim) + C[i] = [r*exp(im*ϕ) for (r,ϕ) in zip(r,ϕ)] end - M = gramschmidt(M) + opt.M = gramschmidt(C) end - - opt.M = complex.(M) end -function _ini_measurement!(opt::Mopt_LinearComb, dim::Int, rng; eps=GLOBAL_EPS) +function _ini_measurement!(opt::Mopt_LinearComb, dim::Int; eps=GLOBAL_EPS) (;B, POVM_basis, M_num) = opt if ismissing(POVM_basis) opt.POVM_basis = SIC(dim) @@ -165,11 +175,11 @@ function _ini_measurement!(opt::Mopt_LinearComb, dim::Int, rng; eps=GLOBAL_EPS) end if ismissing(B) - opt.B = [rand(rng, length(POVM_basis)) for _ in 1:M_num] + opt.B = [rand(opt.rng, length(POVM_basis)) for _ in 1:M_num] end end -function _ini_measurement!(opt::Mopt_Rotation, dim::Int, rng; eps=GLOBAL_EPS) +function _ini_measurement!(opt::Mopt_Rotation, dim::Int; eps=GLOBAL_EPS) (;s, POVM_basis, Lambda) = opt if ismissing(POVM_basis) throw(ArgumentError("The initial POVM basis should not be empty!")) @@ -186,13 +196,19 @@ function _ini_measurement!(opt::Mopt_Rotation, dim::Int, rng; eps=GLOBAL_EPS) end if ismissing(s) - opt.s = rand(rng, dim^2) + opt.s = rand(opt.rng, dim^2) end end -function Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH; Hc=missing, ctrl=missing, decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) +""" + + Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH; Hc=missing, ctrl=missing, decay=missing, eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the measurement optimization. +""" +function Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH; Hc=missing, ctrl=missing, decay=missing, eps=GLOBAL_EPS) dim = size(ρ₀, 1) - _ini_measurement!(opt, dim, rng; eps=eps) + _ini_measurement!(opt, dim; eps=eps) if ismissing(dH) dH = [zeros(ComplexF64, dim, dim)] @@ -261,31 +277,37 @@ function Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH; Hc=missing, ctrl=miss end end -Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH, Hc, ctrl, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, ρ₀, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, rng=rng, eps=eps) +Lindblad(opt::AbstractMopt, tspan, ρ₀, H0, dH, Hc, ctrl, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, ρ₀, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, eps=eps) -function _ini_measurement!(opt::CompOpt, dim::Int, rng; eps=GLOBAL_EPS) +function _ini_measurement!(opt::CompOpt, dim::Int; eps=GLOBAL_EPS) (; M) = opt ## initialize the Mopt target M - M = [ComplexF64[] for _ in 1:dim] + C = [ComplexF64[] for _ in 1:dim] if ismissing(M) for i in 1:dim - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini/norm(r_ini) - ϕ = 2pi*rand(rng, dim) - M[i] = [r*exp(im*ϕ) for (r,ϕ) in zip(r,ϕ)] + ϕ = 2pi*rand(opt.rng, dim) + C[i] = [r*exp(im*ϕ) for (r,ϕ) in zip(r,ϕ)] end - opt.M = gramschmidt(M) + opt.M = gramschmidt(C) end end -function Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc; decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) +""" + + Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the comprehensive optimization on state and control. +""" +function Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) (;psi, ctrl) = opt dim = H0 isa AbstractVector ? size(H0[1], 1) : size(H0, 1) if ismissing(psi) - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini ./ norm(r_ini) - ϕ = 2pi*rand(rng, dim) + ϕ = 2pi*rand(opt.rng, dim) psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] opt.psi = psi end @@ -333,13 +355,19 @@ function Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc; decay=missing, rng=GL Lindblad(H0, dH, Hc, ctrl, psi, tspan, decay_opt, γ) end -Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, H0, dH, Hc; decay=decay, rng=rng, eps=eps) +Lindblad(opt::StateControlOpt, tspan, H0, dH, Hc, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, H0, dH, Hc; decay=decay, eps=eps) + +""" -function Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) + Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc; decay=missing,eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the comprehensive optimization on control and measurement. +""" +function Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) (;ctrl) = opt dim = size(ρ₀, 1) - _ini_measurement!(opt, dim, rng; eps=eps) + _ini_measurement!(opt, dim; eps=eps) if ismissing(dH) dH = [zeros(ComplexF64, dim, dim)] end @@ -385,17 +413,23 @@ function Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc; decay=mi Lindblad(H0, dH, Hc, ctrl, ρ₀, tspan, decay_opt, γ) end -Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, ρ₀, H0, dH, Hc; decay=decay, rng=rng, eps=eps) +Lindblad(opt::ControlMeasurementOpt, tspan, ρ₀, H0, dH, Hc, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, ρ₀, H0, dH, Hc; decay=decay, eps=eps) + +""" -function Lindblad(opt::StateMeasurementOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing, rng=GLOBAL_RNG) + Lindblad(opt::StateMeasurementOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the comprehensive optimization on state and measurement. +""" +function Lindblad(opt::StateMeasurementOpt, tspan, H0, dH; Hc=missing, ctrl=missing, decay=missing) (;psi) = opt dim = H0 isa AbstractVector ? size(H0[1], 1) : size(H0, 1) - _ini_measurement!(opt, dim, rng; eps=eps) + _ini_measurement!(opt, dim; eps=eps) if ismissing(psi) - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini ./ norm(r_ini) - ϕ = 2pi*rand(rng, dim) + ϕ = 2pi*rand(opt.rng, dim) psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] opt.psi = psi end @@ -467,18 +501,24 @@ function Lindblad(opt::StateMeasurementOpt, tspan, H0, dH; Hc=missing, ctrl=miss end end -Lindblad(opt::StateMeasurementOpt, tspan, H0, dH, Hc, ctrl, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, rng=rng, eps=eps) +Lindblad(opt::StateMeasurementOpt, tspan, H0, dH, Hc, ctrl, decay;eps=GLOBAL_EPS) = + Lindblad(opt, tspan, H0, dH; Hc=Hc, ctrl=ctrl, decay=decay, eps=eps) + +""" -function Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc; decay=missing, rng=GLOBAL_RNG, eps=GLOBAL_EPS) + Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc; decay=missing,eps=GLOBAL_EPS) + +Initialize the parameterization described by the Lindblad master equation governed dynamics for the comprehensive optimization on state, control and measurement. +""" +function Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc; decay=missing, eps=GLOBAL_EPS) (;ctrl, psi) = opt dim = H0 isa AbstractVector ? size(H0[1], 1) : size(H0, 1) - _ini_measurement!(opt, dim, rng; eps=eps) + _ini_measurement!(opt, dim; eps=eps) if ismissing(psi) - r_ini = 2*rand(rng, dim) - ones(dim) + r_ini = 2*rand(opt.rng, dim) - ones(dim) r = r_ini ./ norm(r_ini) - ϕ = 2pi*rand(rng, dim) + ϕ = 2pi*rand(opt.rng, dim) psi = [r*exp(im*ϕ) for (r, ϕ) in zip(r, ϕ)] opt.psi = psi end @@ -528,5 +568,5 @@ function Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc; decay=miss Lindblad(H0, dH, Hc, ctrl, psi, tspan, decay_opt, γ) end -Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc, decay; rng=GLOBAL_RNG, eps=GLOBAL_EPS) = - Lindblad(opt, tspan, H0, dH, Hc; decay=decay, rng=rng, eps=eps) +Lindblad(opt::StateControlMeasurementOpt, tspan, H0, dH, Hc, decay; eps=GLOBAL_EPS) = + Lindblad(opt, tspan, H0, dH, Hc; decay=decay, eps=eps) diff --git a/src/dynamics/dynamics.jl b/src/Parameterization/Parameterization.jl similarity index 93% rename from src/dynamics/dynamics.jl rename to src/Parameterization/Parameterization.jl index 91b73aa..54bd240 100644 --- a/src/dynamics/dynamics.jl +++ b/src/Parameterization/Parameterization.jl @@ -24,5 +24,5 @@ isCtrl(::free) = false isCtrl(::controlled) = true isCtrl(dynamics::AbstractDynamics) = dynamics.ctrl_type |> eval |> isCtrl -include("lindblad/Lindblad.jl") -include("kraus/Kraus.jl") +include("Lindblad/Lindblad.jl") +include("Kraus/Kraus.jl") diff --git a/src/QuanEstimation.jl b/src/QuanEstimation.jl index c19c5f4..625330f 100644 --- a/src/QuanEstimation.jl +++ b/src/QuanEstimation.jl @@ -17,17 +17,15 @@ const pkgpath = @__DIR__ const GLOBAL_RNG = MersenneTwister(1234) const GLOBAL_EPS = 1e-8 -include("optim/optim.jl") -include("common/common.jl") -include("dynamics/dynamics.jl") -include("objective/objective.jl") -include("common/adaptive.jl") +include("OptScenario/OptScenario.jl") +include("Common/Common.jl") +include("Parameterization/Parameterization.jl") +include("ObjectiveFunc/ObjectiveFunc.jl") +include("Common/AdaptiveScheme.jl") include("output.jl") -include("algorithm/algorithm.jl") +include("Algorithm/Algorithm.jl") include("run.jl") include("io.jl") -include("resources/resources.jl") - - +include("Resource/Resource.jl") end diff --git a/src/resources/resources.jl b/src/Resource/Resource.jl similarity index 72% rename from src/resources/resources.jl rename to src/Resource/Resource.jl index 4f60e46..57a8047 100644 --- a/src/resources/resources.jl +++ b/src/Resource/Resource.jl @@ -20,7 +20,14 @@ function Jp_full(N) Jp end -function SpinSqueezing(ρ::AbstractMatrix; basis="Dicke", output = "KU") +""" + + SpinSqueezing(ρ::AbstractMatrix; basis="Dicke", output="KU") + +Calculate the spin squeezing parameter for the input density matrix. The `basis` can be `"Dicke"` for the Dicke basis, or `"Pauli"` for the Pauli basis. The `output` can be both `"KU"`(for spin squeezing defined by Kitagawa and Ueda) and `"WBIMH"`(for spin squeezing defined by Wineland et al.). + +""" +function SpinSqueezing(ρ::AbstractMatrix; basis="Dicke", output="KU") N = size(ρ)[1] - 1 coef = 4.0/N j = N/2 @@ -63,7 +70,13 @@ function SpinSqueezing(ρ::AbstractMatrix; basis="Dicke", output = "KU") return res end -function TargetTime(f::Number, tspan, func::Function, args...;kwargs...) +""" + TargetTime(f::Number, tspan::AbstractVector, func::Function, args...; kwargs...) + +Calculate the minimum time to reach a precision limit of given level. The `func` can be any objective function during the control optimization, e.g. QFIM, CFIM, HCRB, etc. + +""" +function TargetTime(f::Number, tspan::AbstractVector, func::Function, args...; kwargs...) args = zip.(args...)|>a->[[x for x in x] for x in unzip(a)][1] tnum = length(tspan) diff --git a/src/algorithm/AD.jl b/src/algorithm/AD.jl index c212f2b..d825d73 100644 --- a/src/algorithm/AD.jl +++ b/src/algorithm/AD.jl @@ -1,8 +1,4 @@ #### control optimization #### -""" -Control optimization with autoGRAPE. - -""" function update!(opt::ControlOpt, alg::AbstractautoGRAPE, obj, dynamics, output) (; max_episode) = alg ctrl_length = length(dynamics.data.ctrl[1]) @@ -18,7 +14,7 @@ function update!(opt::ControlOpt, alg::AbstractautoGRAPE, obj, dynamics, output) show(opt, output, obj) for ei = 1:(max_episode-1) - δ = gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ctrl])) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ctrl])) update_ctrl!(alg, obj, dynamics, δ[dynamics.data.ctrl]) bound!(dynamics.data.ctrl, opt.ctrl_bound) f_out, f_now = objective(obj, dynamics) @@ -47,10 +43,6 @@ function update_ctrl!(alg::autoGRAPE, obj, dynamics, δ) end #### state optimization #### -""" -State optimization with AD. - -""" function update!(opt::StateOpt, alg::AbstractAD, obj, dynamics, output) (; max_episode) = alg f_ini, f_comp = objective(obj, dynamics) @@ -59,7 +51,7 @@ function update!(opt::StateOpt, alg::AbstractAD, obj, dynamics, output) set_io!(output, f_ini) show(opt, output, obj) for ei in 1:(max_episode-1) - δ = gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0])) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0])) update_state!(alg, obj, dynamics, δ[dynamics.data.ψ0]) dynamics.data.ψ0 = dynamics.data.ψ0/norm(dynamics.data.ψ0) f_out, f_now = objective(obj, dynamics) @@ -84,16 +76,13 @@ function update_state!(alg::AD, obj, dynamics, δ) end #### find the optimal linear combination of a given set of POVM #### -""" -Measurement optimization (method: linear combination) with AD. - -""" function update!(opt::Mopt_LinearComb, alg::AbstractAD, obj, dynamics, output) (; max_episode) = alg (; POVM_basis, M_num) = opt + rng = MersenneTwister(1234) basis_num = length(POVM_basis) - bound_LC_coeff!(opt.B) + bound_LC_coeff!(opt.B, rng) M = [sum([opt.B[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] obj_QFIM = QFIM_obj(obj) f_opt, f_comp = objective(obj_QFIM, dynamics) @@ -106,9 +95,9 @@ function update!(opt::Mopt_LinearComb, alg::AbstractAD, obj, dynamics, output) set_io!(output, f_ini, f_povm, f_opt) show(opt, output, obj) for ei in 1:(max_episode-1) - δ = gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.B])) + δ = Flux.gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.B])) update_M!(opt, alg, obj, δ[opt.B]) - bound_LC_coeff!(opt.B) + bound_LC_coeff!(opt.B, rng) M = [sum([opt.B[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] obj_copy = set_M(obj, M) f_out, f_now = objective(obj_copy, dynamics) @@ -135,10 +124,6 @@ function update_M!(opt::Mopt_LinearComb, alg::AD, obj, δ) end #### find the optimal rotated measurement of a given set of POVM #### -""" -Measurement optimization (method: rotation) with AD. - -""" function update!(opt::Mopt_Rotation, alg::AbstractAD, obj, dynamics, output) (; max_episode) = alg (; POVM_basis) = opt @@ -168,7 +153,7 @@ function update!(opt::Mopt_Rotation, alg::AbstractAD, obj, dynamics, output) set_io!(output, f_ini, f_povm, f_opt) show(opt, output, obj) for ei in 1:(max_episode-1) - δ = gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.s])) + δ = Flux.gradient(() -> objective(opt, obj, dynamics)[2], Flux.Params([opt.s])) update_M!(opt, alg, obj, δ[opt.s]) bound_rot_coeff!(opt.s) U = rotation_matrix(opt.s, opt.Lambda) @@ -196,10 +181,6 @@ function update_M!(opt::Mopt_Rotation, alg::AD, obj, δ) end #### state abd control optimization #### -""" -Comprehensive optimization on state and control with AD. - -""" function update!(opt::StateControlOpt, alg::AbstractAD, obj, dynamics, output) (; max_episode) = alg ctrl_length = length(dynamics.data.ctrl[1]) @@ -215,7 +196,7 @@ function update!(opt::StateControlOpt, alg::AbstractAD, obj, dynamics, output) show(opt, output, obj) for ei = 1:(max_episode-1) - δ = gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0, dynamics.data.ctrl])) + δ = Flux.gradient(() -> objective(obj, dynamics)[2], Flux.Params([dynamics.data.ψ0, dynamics.data.ctrl])) update_state!(alg, obj, dynamics, δ[dynamics.data.ψ0]) update_ctrl!(alg, obj, dynamics, δ[dynamics.data.ctrl]) bound!(dynamics.data.ctrl, opt.ctrl_bound) diff --git a/src/algorithm/DDPG.jl b/src/algorithm/DDPG.jl index 52fefd6..5f353f2 100644 --- a/src/algorithm/DDPG.jl +++ b/src/algorithm/DDPG.jl @@ -41,10 +41,6 @@ mutable struct ControlEnv <: AbstractEnv end #### control optimization #### -""" -Control optimization with DDPG. - -""" function update!(opt::ControlOpt, alg::DDPG, obj, dynamics, output) (; max_episode, layer_num, layer_dim, rng) = alg #### environment of DDPG #### @@ -247,10 +243,6 @@ RLBase.reward(env::StateEnv) = env.reward RLBase.is_terminated(env::StateEnv) = env.done RLBase.state(env::StateEnv) = env.state -""" -State optimization with DDPG. - -""" function update!(Sopt::StateOpt, alg::DDPG, obj, dynamics::Lindblad, output) (; max_episode, layer_num, layer_dim, rng) = alg episode = 1 diff --git a/src/algorithm/DE.jl b/src/algorithm/DE.jl index 304592d..fabe12a 100644 --- a/src/algorithm/DE.jl +++ b/src/algorithm/DE.jl @@ -1,10 +1,6 @@ #### control optimization #### -""" -Control optimization with DE. - -""" function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.ctrl,],) end @@ -14,7 +10,7 @@ function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) populations = repeat(dynamics, p_num) # initialization - initial_ctrl!(opt, ini_population, populations, p_num, rng) + initial_ctrl!(opt, ini_population, populations, p_num, opt.rng) dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) f_noctrl, f_comp = objective(obj, dynamics_copy) @@ -31,7 +27,7 @@ function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) for ei = 1:(max_episode-1) for pj = 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace = false) + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i = 1:ctrl_num] for ci = 1:ctrl_num for ti = 1:ctrl_length @@ -46,9 +42,9 @@ function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) #crossover ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i = 1:ctrl_num] for cj = 1:ctrl_num - cross_int = sample(1:ctrl_length, 1, replace = false)[1] + cross_int = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] for tj = 1:ctrl_length - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr ctrl_cross[cj][tj] = ctrl_mut[cj][tj] else @@ -81,12 +77,8 @@ function update!(opt::ControlOpt, alg::DE, obj, dynamics, output) end #### state optimization #### -""" -State optimization with DE. - -""" function update!(opt::StateOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.psi,],) end @@ -94,7 +86,7 @@ function update!(opt::StateOpt, alg::DE, obj, dynamics, output) dim = length(dynamics.data.ψ0) populations = repeat(dynamics, p_num) # initialization - initial_state!(ini_population, populations, p_num, rng) + initial_state!(ini_population, populations, p_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for i in 1:p_num @@ -109,16 +101,16 @@ function update!(opt::StateOpt, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace=false) + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) state_mut = zeros(ComplexF64, dim) for ci in 1:dim state_mut[ci] = populations[mut_num[1]].data.ψ0[ci]+c*(populations[mut_num[2]].data.ψ0[ci]-populations[mut_num[3]].data.ψ0[ci]) end #crossover state_cross = zeros(ComplexF64, dim) - cross_int = sample(1:dim, 1, replace=false)[1] + cross_int = sample(opt.rng, 1:dim, 1, replace=false)[1] for cj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr state_cross[cj] = state_mut[cj] else @@ -148,12 +140,8 @@ function update!(opt::StateOpt, alg::DE, obj, dynamics, output) end #### projective measurement optimization #### -""" -Measurement optimization (method: projection) with DE. - -""" function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.M], ) end @@ -164,7 +152,7 @@ function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) populations = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] # initialization - initial_M!(ini_population, populations, dim, p_num, M_num, rng) + initial_M!(ini_population, populations, dim, p_num, M_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -185,7 +173,7 @@ function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace=false) + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) M_mut = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] for ci in 1:M_num for ti in 1:dim @@ -196,9 +184,9 @@ function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) #crossover M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] for cj in 1:M_num - cross_int = sample(1:dim, 1, replace=false)[1] + cross_int = sample(opt.rng, 1:dim, 1, replace=false)[1] for tj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[cj][tj] = M_mut[cj][tj] else @@ -234,22 +222,19 @@ function update!(opt::Mopt_Projection, alg::DE, obj, dynamics, output) end #### find the optimal linear combination of a given set of POVM #### -""" -Measurement optimization (method: linear combination) with DE. - -""" function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg (; B, POVM_basis, M_num) = opt if ismissing(ini_population) ini_population = ( [B], ) end ini_population = ini_population[1] + dim = size(dynamics.data.ρ0)[1] basis_num = length(POVM_basis) populations = [[zeros(basis_num) for j in 1:M_num] for i in 1:p_num] # initialization - initial_LinearComb!(ini_population, populations, basis_num, M_num, p_num, rng) + initial_LinearComb!(ini_population, populations, basis_num, M_num, p_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -272,7 +257,7 @@ function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace=false) + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) M_mut = [Vector{Float64}(undef, basis_num) for i in 1:M_num] for ci in 1:M_num for ti in 1:basis_num @@ -282,9 +267,9 @@ function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) #crossover M_cross = [Vector{Float64}(undef, basis_num) for i in 1:M_num] for cj in 1:M_num - cross_int = sample(1:basis_num, 1, replace=false)[1] + cross_int = sample(opt.rng, 1:basis_num, 1, replace=false)[1] for tj in 1:basis_num - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[cj][tj] = M_mut[cj][tj] else @@ -295,7 +280,7 @@ function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) end # normalize the coefficients - bound_LC_coeff!(M_cross) + bound_LC_coeff!(M_cross, opt.rng) M = [sum([M_cross[i][j]*POVM_basis[j] for j in 1:basis_num]) for i in 1:M_num] obj_cross = set_M(obj, M) f_out, f_cross = objective(obj_cross, dynamics) @@ -321,12 +306,8 @@ function update!(opt::Mopt_LinearComb, alg::DE, obj, dynamics, output) end #### find the optimal rotated measurement of a given set of POVM #### -""" -Measurement optimization (method: rotation) with DE. - -""" function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg (; s, POVM_basis, Lambda) = opt if ismissing(ini_population) ini_population = ([s,],) @@ -347,7 +328,7 @@ function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) M_num = length(POVM_basis) populations = [zeros(dim^2) for i in 1:p_num] # initialization - initial_Rotation!(ini_population, populations, dim, p_num, rng) + initial_Rotation!(ini_population, populations, dim, p_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -372,7 +353,7 @@ function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace=false) + mut_num = sample(opt.rng, 1:p_num, 3, replace=false) M_mut = Vector{Float64}(undef, dim^2) for ti in 1:dim^2 M_mut[ti] = populations[mut_num[1]][ti] + c*(populations[mut_num[2]][ti]-populations[mut_num[3]][ti]) @@ -380,9 +361,9 @@ function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) #crossover M_cross = Vector{Float64}(undef, dim^2) - cross_int = sample(1:dim^2, 1, replace=false)[1] + cross_int = sample(opt.rng, 1:dim^2, 1, replace=false)[1] for tj in 1:dim^2 - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[tj] = M_mut[tj] else @@ -418,12 +399,8 @@ function update!(opt::Mopt_Rotation, alg::DE, obj, dynamics, output) end #### state and control optimization #### -""" -Comprehensive optimization on state and control with DE. - -""" function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.psi], [opt.ctrl,]) end @@ -434,8 +411,8 @@ function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) populations = repeat(dynamics, p_num) # initialization - initial_state!(psi0, populations, p_num, rng) - initial_ctrl!(opt, ctrl0, populations, p_num, rng) + initial_state!(psi0, populations, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for i in 1:p_num @@ -453,7 +430,7 @@ function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace = false) + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) state_mut = zeros(ComplexF64, dim) for ci in 1:dim state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) @@ -468,9 +445,9 @@ function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) end #crossover state_cross = zeros(ComplexF64, dim) - cross_int1 = sample(1:dim, 1, replace = false)[1] + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] for cj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr state_cross[cj] = state_mut[cj] else @@ -481,9 +458,9 @@ function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) psi_cross = state_cross / norm(state_cross) ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] for cj in 1:ctrl_num - cross_int2 = sample(1:ctrl_length, 1, replace = false)[1] + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] for tj in 1:ctrl_length - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr ctrl_cross[cj][tj] = ctrl_mut[cj][tj] else @@ -521,12 +498,8 @@ function update!(opt::StateControlOpt, alg::DE, obj, dynamics, output) end #### state and measurement optimization #### -""" -Comprehensive optimization on state and measurement with DE. - -""" function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.psi], [opt.M,]) end @@ -536,9 +509,9 @@ function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) populations = repeat(dynamics, p_num) # initialization - initial_state!(psi0, populations, p_num, rng) + initial_state!(psi0, populations, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -556,7 +529,7 @@ function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace = false) + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) state_mut = zeros(ComplexF64, dim) for ci in 1:dim state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) @@ -571,9 +544,9 @@ function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) end #crossover state_cross = zeros(ComplexF64, dim) - cross_int1 = sample(1:dim, 1, replace = false)[1] + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] for cj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr state_cross[cj] = state_mut[cj] else @@ -585,9 +558,9 @@ function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] for cj in 1:M_num - cross_int = sample(1:dim, 1, replace = false)[1] + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] for tj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[cj][tj] = M_mut[cj][tj] else @@ -628,12 +601,8 @@ function update!(opt::StateMeasurementOpt, alg::DE, obj, dynamics, output) end #### control and measurement optimization #### -""" -Comprehensive optimization on control and measurement with DE. - -""" function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.ctrl,], [opt.M]) end @@ -645,9 +614,9 @@ function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) populations = repeat(dynamics, p_num) # initialization - initial_ctrl!(opt, ctrl0, populations, p_num, rng) + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -665,7 +634,7 @@ function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace = false) + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) ctrl_mut = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] for ci in 1:ctrl_num for ti in 1:ctrl_length @@ -686,9 +655,9 @@ function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) #crossover ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] for cj in 1:ctrl_num - cross_int2 = sample(1:ctrl_length, 1, replace = false)[1] + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] for tj in 1:ctrl_length - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr ctrl_cross[cj][tj] = ctrl_mut[cj][tj] else @@ -701,9 +670,9 @@ function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] for cj in 1:M_num - cross_int = sample(1:dim, 1, replace = false)[1] + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] for tj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[cj][tj] = M_mut[cj][tj] else @@ -746,12 +715,8 @@ function update!(opt::ControlMeasurementOpt, alg::DE, obj, dynamics, output) end #### state, control and measurement optimization #### -""" -Comprehensive optimization on state, control and measurement with DE. - -""" function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output) - (; max_episode, p_num, ini_population, c, cr, rng) = alg + (; max_episode, p_num, ini_population, c, cr) = alg if ismissing(ini_population) ini_population = ([opt.psi], [opt.ctrl,], [opt.M]) end @@ -763,10 +728,10 @@ function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output populations = repeat(dynamics, p_num) # initialization - initial_state!(psi0, populations, p_num, rng) - initial_ctrl!(opt, ctrl0, populations, p_num, rng) + initial_state!(psi0, populations, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, populations, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) p_fit, p_out = zeros(p_num), zeros(p_num) for pj in 1:p_num @@ -784,7 +749,7 @@ function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output for ei in 1:(max_episode-1) for pj in 1:p_num #mutations - mut_num = sample(1:p_num, 3, replace = false) + mut_num = sample(opt.rng, 1:p_num, 3, replace = false) state_mut = zeros(ComplexF64, dim) for ci in 1:dim state_mut[ci] = populations[mut_num[1]].data.ψ0[ci] + c * (populations[mut_num[2]].data.ψ0[ci] - populations[mut_num[3]].data.ψ0[ci]) @@ -806,9 +771,9 @@ function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output end #crossover state_cross = zeros(ComplexF64, dim) - cross_int1 = sample(1:dim, 1, replace = false)[1] + cross_int1 = sample(opt.rng, 1:dim, 1, replace = false)[1] for cj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr state_cross[cj] = state_mut[cj] else @@ -819,9 +784,9 @@ function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output psi_cross = state_cross / norm(state_cross) ctrl_cross = [Vector{Float64}(undef, ctrl_length) for i in 1:ctrl_num] for cj in 1:ctrl_num - cross_int2 = sample(1:ctrl_length, 1, replace = false)[1] + cross_int2 = sample(opt.rng, 1:ctrl_length, 1, replace = false)[1] for tj in 1:ctrl_length - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr ctrl_cross[cj][tj] = ctrl_mut[cj][tj] else @@ -834,9 +799,9 @@ function update!(opt::StateControlMeasurementOpt, alg::DE, obj, dynamics, output M_cross = [Vector{ComplexF64}(undef, dim) for i in 1:M_num] for cj in 1:M_num - cross_int = sample(1:dim, 1, replace = false)[1] + cross_int = sample(opt.rng, 1:dim, 1, replace = false)[1] for tj in 1:dim - rand_num = rand(rng) + rand_num = rand(opt.rng) if rand_num <= cr M_cross[cj][tj] = M_mut[cj][tj] else diff --git a/src/algorithm/GRAPE.jl b/src/algorithm/GRAPE.jl index 2c15943..5bd03af 100644 --- a/src/algorithm/GRAPE.jl +++ b/src/algorithm/GRAPE.jl @@ -1,9 +1,3 @@ -""" - update!(opt::ControlOpt, alg::AbstractGRAPE, obj::QFIM_obj, dynamics, output) - -Control optimization with GRAPE, where the objective is QFIM. - -""" function update!(opt::ControlOpt, alg::AbstractGRAPE, obj::QFIM_obj, dynamics, output) (; max_episode) = alg ctrl_length = length(dynamics.data.ctrl[1]) @@ -28,10 +22,6 @@ function update!(opt::ControlOpt, alg::AbstractGRAPE, obj::QFIM_obj, dynamics, o set_io!(output, output.f_list[end]) end -""" -Control optimization with GRAPE, where the objective is CFIM. - -""" function update!(opt::ControlOpt, alg::AbstractGRAPE, obj::CFIM_obj, dynamics, output) (; max_episode) = alg ctrl_length = length(dynamics.data.ctrl[1]) diff --git a/src/algorithm/NM.jl b/src/algorithm/NM.jl index 014db42..d20a17f 100644 --- a/src/algorithm/NM.jl +++ b/src/algorithm/NM.jl @@ -1,27 +1,27 @@ function update!(opt::StateOpt, alg::NM, obj, dynamics, output) - (; max_episode, state_num, ini_state, ar, ae, ac, as0, rng) = alg + (; max_episode, p_num, ini_state, ar, ae, ac, as0) = alg if ismissing(ini_state) ini_state = [opt.psi] end dim = length(dynamics.data.ψ0) - nelder_mead = repeat(dynamics, state_num) + nelder_mead = repeat(dynamics, p_num) # initialize - if length(ini_state) > state_num - ini_state = [ini_state[i] for i in 1:state_num] + if length(ini_state) > p_num + ini_state = [ini_state[i] for i in 1:p_num] end for pj in 1:length(ini_state) nelder_mead[pj].data.ψ0 = [ini_state[pj][i] for i in 1:dim] end - for pj in (length(ini_state)+1):state_num - r_ini = 2*rand(rng, dim)-ones(dim) + for pj in (length(ini_state)+1):p_num + r_ini = 2*rand(opt.rng, dim)-ones(dim) r = r_ini/norm(r_ini) - phi = 2*pi*rand(rng, dim) + phi = 2*pi*rand(opt.rng, dim) nelder_mead[pj].data.ψ0 = [r[i]*exp(1.0im*phi[i]) for i in 1:dim] end - p_fit, p_out = zeros(state_num), zeros(state_num) - for pj in 1:state_num + p_fit, p_out = zeros(p_num), zeros(p_num) + for pj in 1:p_num p_out[pj], p_fit[pj] = objective(obj, nelder_mead[pj]) end sort_ind = sortperm(p_fit, rev=true) @@ -37,8 +37,8 @@ function update!(opt::StateOpt, alg::NM, obj, dynamics, output) # calculate the average vector vec_ave = zeros(ComplexF64, dim) for ni in 1:dim - vec_ave[ni] = [nelder_mead[pk].data.ψ0[ni] for pk in 1:(state_num-1)] |> sum - vec_ave[ni] = vec_ave[ni]/(state_num-1) + vec_ave[ni] = [nelder_mead[pk].data.ψ0[ni] for pk in 1:(p_num-1)] |> sum + vec_ave[ni] = vec_ave[ni]/(p_num-1) end vec_ave = vec_ave/norm(vec_ave) @@ -96,7 +96,7 @@ function update!(opt::StateOpt, alg::NM, obj, dynamics, output) else # shrink vec_first = [nelder_mead[sort_ind[1]].data.ψ0[i] for i in 1:dim] - for pk in 1:state_num + for pk in 1:p_num for nq in 1:dim nelder_mead[pk].data.ψ0[nq] = vec_first[nq] + as0*(nelder_mead[pk].data.ψ0[nq]-vec_first[nq]) end @@ -124,7 +124,7 @@ function update!(opt::StateOpt, alg::NM, obj, dynamics, output) else # shrink vec_first = [nelder_mead[sort_ind[1]].data.ψ0[i] for i in 1:dim] - for pk in 1:state_num + for pk in 1:p_num for nq in 1:dim nelder_mead[pk].data.ψ0[nq] = vec_first[nq] + as0*(nelder_mead[pk].data.ψ0[nq]-vec_first[nq]) end diff --git a/src/algorithm/PSO.jl b/src/algorithm/PSO.jl index e83d9ed..578524c 100644 --- a/src/algorithm/PSO.jl +++ b/src/algorithm/PSO.jl @@ -1,6 +1,6 @@ #### control optimization #### function update!(opt::ControlOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.ctrl,],) end @@ -13,7 +13,7 @@ function update!(opt::ControlOpt, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, rng) + velocity = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) pbest = zeros(ctrl_num, ctrl_length, p_num) gbest = zeros(ctrl_num, ctrl_length) @@ -21,7 +21,7 @@ function update!(opt::ControlOpt, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialize - initial_ctrl!(opt, ini_particle, particles, p_num, rng) + initial_ctrl!(opt, ini_particle, particles, p_num, opt.rng) dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i = 1:ctrl_num]) f_noctrl, f_comp = objective(obj, dynamics_copy) @@ -66,9 +66,9 @@ function update!(opt::ControlOpt, alg::PSO, obj, dynamics, output) velocity[dk, ck, pk] = c0 * velocity[dk, ck, pk] + c1 * - rand(rng) * + rand(opt.rng) * (pbest[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) - +c2 * rand(rng) * (gbest[dk, ck] - particles[pk].data.ctrl[dk][ck]) + +c2 * rand(opt.rng) * (gbest[dk, ck] - particles[pk].data.ctrl[dk][ck]) particles[pk].data.ctrl[dk][ck] += velocity[dk, ck, pk] end end @@ -102,7 +102,7 @@ end #### state optimization #### function update!(opt::StateOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.psi], ) end @@ -114,7 +114,7 @@ function update!(opt::StateOpt, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity = 0.1.*rand(rng, ComplexF64, dim, p_num) + velocity = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) pbest = zeros(ComplexF64, dim, p_num) gbest = zeros(ComplexF64, dim) @@ -122,7 +122,7 @@ function update!(opt::StateOpt, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialization - initial_state!(ini_particle, particles, p_num, rng) + initial_state!(ini_particle, particles, p_num, opt.rng) f_ini, f_comp = objective(obj, dynamics) set_f!(output, f_ini) @@ -156,7 +156,7 @@ function update!(opt::StateOpt, alg::PSO, obj, dynamics, output) psi_pre = zeros(ComplexF64, dim) for dk in 1:dim psi_pre[dk] = particles[pk].data.ψ0[dk] - velocity[dk, pk] = c0*velocity[dk, pk] + c1*rand(rng)*(pbest[dk, pk] - particles[pk].data.ψ0[dk]) + c2*rand(rng)*(gbest[dk] - particles[pk].data.ψ0[dk]) + velocity[dk, pk] = c0*velocity[dk, pk] + c1*rand(opt.rng)*(pbest[dk, pk] - particles[pk].data.ψ0[dk]) + c2*rand(opt.rng)*(gbest[dk] - particles[pk].data.ψ0[dk]) particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity[dk, pk] end particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) @@ -179,7 +179,7 @@ end #### projective measurement optimization #### function update!(opt::Mopt_Projection, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.M], ) end @@ -192,7 +192,7 @@ function update!(opt::Mopt_Projection, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity = 0.1*rand(rng, ComplexF64, M_num, dim, p_num) + velocity = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) pbest = zeros(ComplexF64, M_num, dim, p_num) gbest = [zeros(ComplexF64, dim) for i in 1:M_num] @@ -200,7 +200,7 @@ function update!(opt::Mopt_Projection, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialization - initial_M!(ini_particle, particles, dim, p_num, M_num, rng) + initial_M!(ini_particle, particles, dim, p_num, M_num, opt.rng) M = [particles[1][i]*(particles[1][i])' for i in 1:M_num] obj_copy = set_M(obj, M) @@ -248,8 +248,8 @@ function update!(opt::Mopt_Projection, alg::PSO, obj, dynamics, output) for ck in 1:dim meas_pre[dk][ck] = particles[pk][dk][ck] - velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) - + c2*rand(rng)*(gbest[dk][ck] - particles[pk][dk][ck]) + velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(opt.rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest[dk][ck] - particles[pk][dk][ck]) particles[pk][dk][ck] += velocity[dk, ck, pk] end end @@ -272,7 +272,7 @@ end #### find the optimal linear combination of a given set of POVM #### function update!(opt::Mopt_LinearComb, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg (; B, POVM_basis, M_num) = opt basis_num = length(POVM_basis) if ismissing(ini_particle) @@ -285,7 +285,7 @@ function update!(opt::Mopt_LinearComb, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity = 0.1*rand(rng, Float64, M_num, basis_num, p_num) + velocity = 0.1*rand(opt.rng, Float64, M_num, basis_num, p_num) pbest = zeros(Float64, M_num, basis_num, p_num) gbest = zeros(Float64, M_num, basis_num) @@ -293,7 +293,7 @@ function update!(opt::Mopt_LinearComb, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialization - initial_LinearComb!(ini_particle, particles, basis_num, M_num, p_num, rng) + initial_LinearComb!(ini_particle, particles, basis_num, M_num, p_num, opt.rng) obj_QFIM = QFIM_obj(obj) f_opt, f_comp = objective(obj_QFIM, dynamics) @@ -343,12 +343,12 @@ function update!(opt::Mopt_LinearComb, alg::PSO, obj, dynamics, output) for ck in 1:basis_num meas_pre[dk][ck] = particles[pk][dk][ck] - velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) - + c2*rand(rng)*(gbest[dk, ck] - particles[pk][dk][ck]) + velocity[dk, ck, pk] = c0*velocity[dk, ck, pk] + c1*rand(opt.rng)*(pbest[dk, ck, pk] - particles[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest[dk, ck] - particles[pk][dk][ck]) particles[pk][dk][ck] += velocity[dk, ck, pk] end end - bound_LC_coeff!(particles[pk]) + bound_LC_coeff!(particles[pk], opt.rng) for dm in 1:M_num for cm in 1:basis_num @@ -367,7 +367,7 @@ end #### find the optimal rotated measurement of a given set of POVM #### function update!(opt::Mopt_Rotation, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.s], ) end @@ -392,7 +392,7 @@ function update!(opt::Mopt_Rotation, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity = 0.1*rand(rng, Float64, dim^2, p_num) + velocity = 0.1*rand(opt.rng, Float64, dim^2, p_num) pbest = zeros(Float64, dim^2, p_num) gbest = zeros(Float64, dim^2) @@ -401,7 +401,7 @@ function update!(opt::Mopt_Rotation, alg::PSO, obj, dynamics, output) # initialization particles = [zeros(dim^2) for i in 1:p_num] - initial_Rotation!(ini_particle, particles, dim, p_num, rng) + initial_Rotation!(ini_particle, particles, dim, p_num, opt.rng) obj_QFIM = QFIM_obj(obj) f_opt, f_comp = objective(obj_QFIM, dynamics) @@ -448,7 +448,7 @@ function update!(opt::Mopt_Rotation, alg::PSO, obj, dynamics, output) for ck in 1:dim^2 meas_pre[ck] = particles[pk][ck] - velocity[ck, pk] = c0*velocity[ck, pk] + c1*rand(rng)*(pbest[ck, pk] - particles[pk][ck]) + c2*rand(rng)*(gbest[ck] - particles[pk][ck]) + velocity[ck, pk] = c0*velocity[ck, pk] + c1*rand(opt.rng)*(pbest[ck, pk] - particles[pk][ck]) + c2*rand(opt.rng)*(gbest[ck] - particles[pk][ck]) particles[pk][ck] += velocity[ck, pk] end @@ -470,7 +470,7 @@ end #### state and control optimization #### function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.psi], [opt.ctrl,]) end @@ -484,10 +484,10 @@ function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity_state = 0.1.*rand(rng, ComplexF64, dim, p_num) + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) pbest_state = zeros(ComplexF64, dim, p_num) gbest_state = zeros(ComplexF64, dim) - velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, rng) + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) gbest_ctrl = zeros(ctrl_num, ctrl_length) @@ -495,8 +495,8 @@ function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialization - initial_state!(psi0, particles, p_num, rng) - initial_ctrl!(opt, ctrl0, particles, p_num, rng) + initial_state!(psi0, particles, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) dynamics_copy = set_ctrl(dynamics, [zeros(ctrl_length) for i=1:ctrl_num]) f_noctrl, f_comp = objective(obj, dynamics_copy) @@ -545,8 +545,8 @@ function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) psi_pre = zeros(ComplexF64, dim) for dk in 1:dim psi_pre[dk] = particles[pk].data.ψ0[dk] - velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + - c2*rand(rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] end particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) @@ -558,8 +558,8 @@ function update!(opt::StateControlOpt, alg::PSO, obj, dynamics, output) for dk in 1:ctrl_num for ck in 1:ctrl_length control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] - velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) - + c2*rand(rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] end end @@ -581,7 +581,7 @@ end #### state and measurement optimization #### function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.psi], [opt.M]) end @@ -594,10 +594,10 @@ function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity_state = 0.1.*rand(rng, ComplexF64, dim, p_num) + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) pbest_state = zeros(ComplexF64, dim, p_num) gbest_state = zeros(ComplexF64, dim) - velocity_meas = 0.1*rand(rng, ComplexF64, M_num, dim, p_num) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) pbest_meas = zeros(ComplexF64, M_num, dim, p_num) gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] @@ -605,9 +605,9 @@ function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) fit, fit_out = 0.0, 0.0 # initialization - initial_state!(psi0, particles, p_num, rng) + initial_state!(psi0, particles, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] obj_copy = set_M(obj, M) @@ -658,8 +658,8 @@ function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) psi_pre = zeros(ComplexF64, dim) for dk in 1:dim psi_pre[dk] = particles[pk].data.ψ0[dk] - velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + - c2*rand(rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] end particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) @@ -672,8 +672,8 @@ function update!(opt::StateMeasurementOpt, alg::PSO, obj, dynamics, output) for ck in 1:dim meas_pre[dk][ck] = C_all[pk][dk][ck] - velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) - + c2*rand(rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] end end @@ -696,7 +696,7 @@ end #### control and measurement optimization #### function update!(opt::ControlMeasurementOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.ctrl,], [opt.M]) end @@ -711,19 +711,19 @@ function update!(opt::ControlMeasurementOpt, alg::PSO, obj, dynamics, output) max_episode = [max_episode, max_episode] end - velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, rng) + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) gbest_ctrl = zeros(ctrl_num, ctrl_length) - velocity_meas = 0.1*rand(rng, ComplexF64, M_num, dim, p_num) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) pbest_meas = zeros(ComplexF64, M_num, dim, p_num) gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] p_fit, p_out = zeros(p_num), zeros(p_num) fit, fit_out = 0.0, 0.0 - initial_ctrl!(opt, ctrl0, particles, p_num, rng) + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] obj_copy = set_M(obj, M) @@ -777,8 +777,8 @@ function update!(opt::ControlMeasurementOpt, alg::PSO, obj, dynamics, output) for dk in 1:ctrl_num for ck in 1:ctrl_length control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] - velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) - + c2*rand(rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] end end @@ -795,8 +795,8 @@ function update!(opt::ControlMeasurementOpt, alg::PSO, obj, dynamics, output) for ck in 1:dim meas_pre[dk][ck] = C_all[pk][dk][ck] - velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) - + c2*rand(rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] end end @@ -819,7 +819,7 @@ end #### state, control and measurement optimization #### function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, output) - (; max_episode, p_num, ini_particle, c0, c1, c2, rng) = alg + (; max_episode, p_num, ini_particle, c0, c1, c2) = alg if ismissing(ini_particle) ini_particle = ([opt.psi], [opt.ctrl,], [opt.M]) end @@ -834,13 +834,13 @@ function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, outpu max_episode = [max_episode, max_episode] end - velocity_state = 0.1.*rand(rng, ComplexF64, dim, p_num) + velocity_state = 0.1.*rand(opt.rng, ComplexF64, dim, p_num) pbest_state = zeros(ComplexF64, dim, p_num) gbest_state = zeros(ComplexF64, dim) - velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, rng) + velocity_ctrl = initial_velocity_ctrl(opt, ctrl_length, ctrl_num, p_num, opt.rng) pbest_ctrl = zeros(ctrl_num, ctrl_length, p_num) gbest_ctrl = zeros(ctrl_num, ctrl_length) - velocity_meas = 0.1*rand(rng, ComplexF64, M_num, dim, p_num) + velocity_meas = 0.1*rand(opt.rng, ComplexF64, M_num, dim, p_num) pbest_meas = zeros(ComplexF64, M_num, dim, p_num) gbest_meas = [zeros(ComplexF64, dim) for i in 1:M_num] @@ -848,10 +848,10 @@ function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, outpu fit, fit_out = 0.0, 0.0 # initialization - initial_state!(psi0, particles, p_num, rng) - initial_ctrl!(opt, ctrl0, particles, p_num, rng) + initial_state!(psi0, particles, p_num, opt.rng) + initial_ctrl!(opt, ctrl0, particles, p_num, opt.rng) C_all = [[zeros(ComplexF64, dim) for j in 1:M_num] for i in 1:p_num] - initial_M!(measurement0, C_all, dim, p_num, M_num, rng) + initial_M!(measurement0, C_all, dim, p_num, M_num, opt.rng) M = [C_all[1][i]*(C_all[1][i])' for i in 1:M_num] obj_copy = set_M(obj, M) @@ -910,8 +910,8 @@ function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, outpu psi_pre = zeros(ComplexF64, dim) for dk in 1:dim psi_pre[dk] = particles[pk].data.ψ0[dk] - velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + - c2*rand(rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) + velocity_state[dk, pk] = c0*velocity_state[dk, pk] + c1*rand(opt.rng)*(pbest_state[dk, pk] - particles[pk].data.ψ0[dk]) + + c2*rand(opt.rng)*(gbest_state[dk] - particles[pk].data.ψ0[dk]) particles[pk].data.ψ0[dk] = particles[pk].data.ψ0[dk] + velocity_state[dk, pk] end particles[pk].data.ψ0 = particles[pk].data.ψ0/norm(particles[pk].data.ψ0) @@ -923,8 +923,8 @@ function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, outpu for dk in 1:ctrl_num for ck in 1:ctrl_length control_coeff_pre[dk][ck] = particles[pk].data.ctrl[dk][ck] - velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) - + c2*rand(rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) + velocity_ctrl[dk, ck, pk] = c0*velocity_ctrl[dk, ck, pk] + c1*rand(opt.rng)*(pbest_ctrl[dk, ck, pk] - particles[pk].data.ctrl[dk][ck]) + + c2*rand(opt.rng)*(gbest_ctrl[dk, ck] - particles[pk].data.ctrl[dk][ck]) particles[pk].data.ctrl[dk][ck] += velocity_ctrl[dk, ck, pk] end end @@ -941,8 +941,8 @@ function update!(opt::StateControlMeasurementOpt, alg::PSO, obj, dynamics, outpu for ck in 1:dim meas_pre[dk][ck] = C_all[pk][dk][ck] - velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) - + c2*rand(rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) + velocity_meas[dk, ck, pk] = c0*velocity_meas[dk, ck, pk] + c1*rand(opt.rng)*(pbest_meas[dk, ck, pk] - C_all[pk][dk][ck]) + + c2*rand(opt.rng)*(gbest_meas[dk][ck] - C_all[pk][dk][ck]) C_all[pk][dk][ck] += velocity_meas[dk, ck, pk] end end diff --git a/src/algorithm/algorithm.jl b/src/algorithm/algorithm.jl index 6919662..5c66970 100644 --- a/src/algorithm/algorithm.jl +++ b/src/algorithm/algorithm.jl @@ -1,117 +1,196 @@ abstract type AbstractAlgorithm end abstract type AbstractGRAPE <: AbstractAlgorithm end -Base.@kwdef struct GRAPE <: AbstractGRAPE - max_episode::Int = 300 - epsilon::Number = 0.01 + +struct GRAPE <: AbstractGRAPE + max_episode::Int + epsilon::Number end -Base.@kwdef struct GRAPE_Adam <: AbstractGRAPE - max_episode::Int = 300 - epsilon::Number = 0.01 - beta1::Number = 0.90 - beta2::Number = 0.99 +struct GRAPE_Adam <: AbstractGRAPE + max_episode::Int + epsilon::Number + beta1::Number + beta2::Number end + GRAPE(max_episode, epsilon, beta1, beta2) = GRAPE_Adam(max_episode, epsilon, beta1, beta2) + +""" + + GRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Control optimization algorithm: GRAPE. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" GRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? GRAPE_Adam(max_episode, epsilon, beta1, beta2) : GRAPE(max_episode, epsilon) abstract type AbstractautoGRAPE <: AbstractAlgorithm end -Base.@kwdef struct autoGRAPE <: AbstractautoGRAPE - max_episode::Int = 300 - epsilon::Number = 0.01 +struct autoGRAPE <: AbstractautoGRAPE + max_episode::Int + epsilon::Number end -Base.@kwdef struct autoGRAPE_Adam <: AbstractautoGRAPE - max_episode::Int = 300 - epsilon::Number = 0.01 - beta1::Number = 0.90 - beta2::Number = 0.99 +struct autoGRAPE_Adam <: AbstractautoGRAPE + max_episode::Int + epsilon::Number + beta1::Number + beta2::Number end autoGRAPE(max_episode, epsilon, beta1, beta2) = autoGRAPE_Adam(max_episode, epsilon, beta1, beta2) + +""" + + autoGRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Control optimization algorithm: auto-GRAPE. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" autoGRAPE(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? autoGRAPE_Adam(max_episode, epsilon, beta1, beta2) : autoGRAPE(max_episode, epsilon) abstract type AbstractAD <: AbstractAlgorithm end -Base.@kwdef struct AD <: AbstractAD - max_episode::Number = 300 - epsilon::Number = 0.01 +struct AD <: AbstractAD + max_episode::Number + epsilon::Number end -Base.@kwdef struct AD_Adam <: AbstractAD - max_episode::Number = 300 - epsilon::Number = 0.01 - beta1::Number = 0.90 - beta2::Number = 0.99 +struct AD_Adam <: AbstractAD + max_episode::Number + epsilon::Number + beta1::Number + beta2::Number end AD(max_episode, epsilon, beta1, beta2) = AD_Adam(max_episode=max_episode, epsilon=epsilon, beta1=beta1, beta2=beta2) +""" + + AD(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) + +Optimization algorithm: AD. +- `max_episode`: The number of episodes. +- `epsilon`: Learning rate. +- `beta1`: The exponential decay rate for the first moment estimates. +- `beta2`: The exponential decay rate for the second moment estimates. +- `Adam`: Whether or not to use Adam for updating control coefficients. +""" AD(;max_episode=300, epsilon=0.01, beta1=0.90, beta2=0.99, Adam::Bool=true) = Adam ? AD_Adam(max_episode, epsilon, beta1, beta2) : AD(max_episode, epsilon) -Base.@kwdef struct PSO <: AbstractAlgorithm - max_episode::Union{T,Vector{T}} where {T<:Int} = [1000, 100] - p_num::Int = 10 - ini_particle::Union{Tuple, Missing} = missing - c0::Number = 1.0 - c1::Number = 2.0 - c2::Number = 2.0 - rng::AbstractRNG = GLOBAL_RNG +mutable struct PSO <: AbstractAlgorithm + max_episode::Union{T,Vector{T}} where {T<:Int} + p_num::Int + ini_particle::Union{Tuple, Missing} + c0::Number + c1::Number + c2::Number end -PSO(max_episode, p_num, ini_particle, c0, c1, c2) = - PSO(max_episode, p_num, ini_particle, c0, c1, c2, GLOBAL_RNG) -PSO(max_episode, p_num, ini_particle, c0, c1, c2, seed::Number) = - PSO(max_episode, p_num, ini_particle, c0, c1, c2, MersenneTwister(seed)) -PSO(;max_episode::Union{T,Vector{T}} where {T<:Int}=[1000, 100], p_num::Number=10, ini_particle=missing, c0::Number=1.0, c1::Number=2.0, c2::Number=2.0, seed::Number=1234) = - PSO(max_episode, p_num, ini_particle, c0, c1, c2, MersenneTwister(seed)) - -Base.@kwdef struct DE <: AbstractAlgorithm - max_episode::Number = 1000 - p_num::Number = 10 - ini_population::Union{Tuple, Missing} = missing - c::Number = 1.0 - cr::Number = 0.5 - rng::AbstractRNG = GLOBAL_RNG +""" + + PSO(;max_episode::Union{T,Vector{T}} where {T<:Int}=[1000, 100], p_num::Number=10, ini_particle=missing, c0::Number=1.0, c1::Number=2.0, c2::Number=2.0, seed::Number=1234) + +Optimization algorithm: PSO. +- `max_episode`: The number of episodes, it accepts both integer and array with two elements. +- `p_num`: The number of particles. +- `ini_particle`: Initial guesses of the optimization variables. +- `c0`: The damping factor that assists convergence, also known as inertia weight. +- `c1`: The exploitation weight that attracts the particle to its best previous position, also known as cognitive learning factor. +- `c2`: The exploitation weight that attracts the particle to the best position in the neighborhood, also known as social learning factor. +""" +PSO(;max_episode::Union{T,Vector{T}} where {T<:Int}=[1000, 100], p_num::Number=10, ini_particle=missing, c0::Number=1.0, c1::Number=2.0, c2::Number=2.0) = + PSO(max_episode, p_num, ini_particle, c0, c1, c2) + +mutable struct DE <: AbstractAlgorithm + max_episode::Number + p_num::Number + ini_population::Union{Tuple, Missing} + c::Number + cr::Number end -DE(max_episode, p_num, ini_population, c, cr) = - DE(max_episode, p_num, ini_population, c, cr, GLOBAL_RNG) -DE(max_episode, p_num, ini_population, c, cr, seed::Number) = - DE(max_episode, p_num, ini_population, c, cr, MersenneTwister(seed)) -DE(;max_episode::Number=1000, p_num::Number=10, ini_population=missing, c::Number=1.0, cr::Number=0.5, seed::Number=1234) = - DE(max_episode, p_num, ini_population, c, cr, MersenneTwister(seed)) - -Base.@kwdef struct DDPG <: AbstractAlgorithm - max_episode::Int = 500 - layer_num::Int = 3 - layer_dim::Int = 200 - rng::AbstractRNG = GLOBAL_RNG +""" + + DE(;max_episode::Number=1000, p_num::Number=10, ini_population=missing, c::Number=1.0, cr::Number=0.5, seed::Number=1234) + +Optimization algorithm: DE. +- `max_episode`: The number of populations. +- `p_num`: The number of particles. +- `ini_population`: Initial guesses of the optimization variables. +- `c`: Mutation constant. +- `cr`: Crossover constant. +""" +DE(;max_episode::Number=1000, p_num::Number=10, ini_population=missing, c::Number=1.0,cr::Number=0.5) = DE(max_episode, p_num, ini_population, c, cr) + +struct DDPG <: AbstractAlgorithm + max_episode::Int + layer_num::Int + layer_dim::Int + rng::AbstractRNG end DDPG(max_episode, layer_num, layer_dim) = - DDPG(max_episode, layer_num, layer_dim, GLOBAL_RNG) + DDPG(max_episode, layer_num, layer_dim, StableRNG(1234)) DDPG(max_episode, layer_num, layer_dim, seed::Number) = DDPG(max_episode, layer_num, layer_dim, StableRNG(seed)) +""" + + DDPG(;max_episode::Int=500, layer_num::Int=3, layer_dim::Int=200, seed::Number=1234) + +Optimization algorithm: DE. +- `max_episode`: The number of populations. +- `layer_num`: The number of layers (include the input and output layer). +- `layer_dim`: The number of neurons in the hidden layer. +- `seed`: Random seed. +""" DDPG(;max_episode::Int=500, layer_num::Int=3, layer_dim::Int=200, seed::Number=1234) = DDPG(max_episode, layer_num, layer_dim, StableRNG(seed)) -Base.@kwdef struct NM <: AbstractAlgorithm - max_episode::Int = 1000 - state_num::Int = 10 - ini_state::Union{AbstractVector, Missing} = missing - ar::Number = 1.0 - ae::Number = 2.0 - ac::Number = 0.5 - as0::Number = 0.5 - rng::AbstractRNG = GLOBAL_RNG +struct NM <: AbstractAlgorithm + max_episode::Int + p_num::Int + ini_state::Union{AbstractVector, Missing} + ar::Number + ae::Number + ac::Number + as0::Number end -NM(max_episode, state_num, nelder_mead, ar, ae, ac, as0) = - NM(max_episode, state_num, nelder_mead, ar, ae, ac, as0, GLOBAL_RNG) -NM(max_episode, state_num, nelder_mead, ar, ae, ac, as0, seed::Number) = - NM(max_episode, state_num, nelder_mead, ar, ae, ac, as0, MersenneTwister(seed)) -NM(;max_episode::Int=1000, state_num::Int=10, nelder_mead=missing, ar::Number=1.0, ae::Number=2.0, ac::Number=0.5, as0::Number=0.5, seed::Number=1234) = - NM(max_episode, state_num, nelder_mead, ar, ae, ac, as0, MersenneTwister(seed)) +""" + + NM(;max_episode::Int=1000, p_num::Int=10, nelder_mead=missing, ar::Number=1.0, ae::Number=2.0, ac::Number=0.5, as0::Number=0.5, seed::Number=1234) + +State optimization algorithm: NM. +- `max_episode`: The number of populations. +- `p_num`: The number of the input states. +- `nelder_mead`: Initial guesses of the optimization variables. +- `ar`: Reflection constant. +- `ae`: Expansion constant. +- `ac`: Constraction constant. +- `as0`: Shrink constant. +""" +NM(;max_episode::Int=1000, p_num::Int=10, nelder_mead=missing, ar::Number=1.0, ae::Number=2.0, ac::Number=0.5, as0::Number=0.5) = NM(max_episode, p_num, nelder_mead, ar, ae, ac, as0) + +struct Iterative <: AbstractAlgorithm + max_episode::Int +end + +""" + + Iterative(;max_episode::Int=300, seed::Number=1234) + +State optimization algorithm: Iterative. +- `max_episode`: The number of episodes. +""" +Iterative(;max_episode::Int=300) = Iterative(max_episode) alg_type(::AD) = :AD alg_type(::AD_Adam) = :AD @@ -123,10 +202,12 @@ alg_type(::PSO) = :PSO alg_type(::DDPG) = :DDPG alg_type(::DE) = :DE alg_type(::NM) = :NM +alg_type(::Iterative) = :Iterative include("AD.jl") include("DDPG.jl") include("DE.jl") include("GRAPE.jl") include("NM.jl") -include("PSO.jl") \ No newline at end of file +include("Iterative.jl") +include("PSO.jl") diff --git a/src/common/BayesEstimation.jl b/src/common/BayesEstimation.jl index f2a7ad4..6981bbb 100644 --- a/src/common/BayesEstimation.jl +++ b/src/common/BayesEstimation.jl @@ -1,39 +1,90 @@ -function Bayes(x, p, rho, y; M=nothing, savefile=false) +""" + + Bayes(x, p, rho, y; M=missing, savefile=false) + +Bayesian estimation. The prior distribution is updated via the posterior distribution obtained by the Bayes’ rule and the estimated value of parameters obtained via the maximum a posteriori probability (MAP). +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `y`: The experimental results obtained in practice. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `savefile`: Whether or not to save all the posterior distributions. +""" +function Bayes(x, p, rho, y; M=missing, estimator="mean", savefile=false) y = y .+ 1 para_num = length(x) max_episode = length(y) if para_num == 1 #### singleparameter senario #### - if M==nothing + if ismissing(M) M = SIC(size(rho[1])[1]) end if savefile == false - for mi in 1:max_episode - res_exp = y[mi] |> Int - pyx = real.(tr.(rho.*[M[res_exp]])) - py = trapz(x[1], pyx.*p) - p_update = pyx.*p/py - p = p_update - end - indx = findmax(p)[2] - x_out = x[1][indx] - return p, x_out + x_out = [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + append!(x_out, trapz(x[1], p.*x[1])) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + indx = findmax(p)[2] + append!(x_out, x[1][indx]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") + end + + open("pout.csv","w") do f + writedlm(f, [p]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] else p_out, x_out = [], [] - for mi in 1:max_episode - res_exp = y[mi] |> Int - pyx = real.(tr.(rho.*[M[res_exp]])) - py = trapz(x[1], pyx.*p) - p_update = pyx.*p/py - p = p_update - - indx = findmax(p)[2] - append!(p_out, [p]) - append!(x_out, x[1][indx]) + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + append!(p_out, [p]) + append!(x_out, trapz(x[1], p.*x[1])) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + py = trapz(x[1], pyx.*p) + p_update = pyx.*p/py + p = p_update + + indx = findmax(p)[2] + append!(p_out, [p]) + append!(x_out, x[1][indx]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") end open("pout.csv","w") do f - writedlm(f, p_out) + writedlm(f, [p_out]) end open("xout.csv","w") do m writedlm(m, x_out) @@ -42,35 +93,77 @@ function Bayes(x, p, rho, y; M=nothing, savefile=false) end else #### multiparameter senario #### - if M==nothing + if ismissing(M) M = SIC(size(vec(rho)[1])[1]) end if savefile == false - for mi in 1:max_episode - res_exp = y[mi] |> Int - pyx = real.(tr.(rho.*[M[res_exp]])) - arr = p.*pyx - py = trapz(tuple(x...), arr) - - p_update = p.*pyx/py - p = p_update + x_out = [] + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + + p_update = p.*pyx/py + p = p_update + append!(x_out, [integ(x, p)]) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + + p_update = p.*pyx/py + p = p_update + + indx = findmax(p)[2] + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") end - indx = findmax(p)[2] - x_out = [x[i][indx[i]] for i in 1:para_num] - return p, x_out + + open("pout.csv","w") do f + writedlm(f, [p]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return p, x_out[end] else p_out, x_out = [], [] - for mi in 1:max_episode - res_exp = y[mi] |> Int - pyx = real.(tr.(rho.*[M[res_exp]])) - arr = p.*pyx - py = trapz(tuple(x...), arr) - p_update = p.*pyx/py - p = p_update - - indx = findmax(p)[2] - append!(p_out, [p]) - append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + if estimator == "mean" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + p_update = p.*pyx/py + p = p_update + + append!(p_out, [p]) + append!(x_out, [integ(x,p)]) + end + elseif estimator == "MAP" + for mi in 1:max_episode + res_exp = y[mi] |> Int + pyx = real.(tr.(rho.*[M[res_exp]])) + arr = p.*pyx + py = trapz(tuple(x...), arr) + p_update = p.*pyx/py + p = p_update + + indx = findmax(p)[2] + append!(p_out, [p]) + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + else + println( + "The input is not a valid value for estimator, supported values are 'mean' and 'MAP'.") end open("pout.csv","w") do f @@ -84,24 +177,43 @@ function Bayes(x, p, rho, y; M=nothing, savefile=false) end end -function MLE(x, rho, y; M::Union{AbstractVector,Nothing}=nothing, savefile=false) +""" + + MLE(x, rho, y; M=missing, savefile=false) + +Bayesian estimation. The estimated value of parameters obtained via the maximum likelihood estimation (MLE). +- `x`: The regimes of the parameters for the integral. +- `rho`: Parameterized density matrix. +- `y`: The experimental results obtained in practice. +- `M`: A set of positive operator-valued measure (POVM). The default measurement is a set of rank-one symmetric informationally complete POVM (SIC-POVM). +- `savefile`: Whether or not to save all the posterior distributions. +""" +function MLE(x, rho, y; M=missing, savefile=false) y = y .+ 1 para_num = length(x) max_episode = length(y) if para_num == 1 - if M==nothing + if ismissing(M) M = SIC(size(rho[1])[1]) end if savefile == false + x_out = [] L_out = ones(length(x[1])) for mi in 1:max_episode res_exp = y[mi] |> Int p_tp = real.(tr.(rho.*[M[res_exp]])) L_out = L_out.*p_tp + indx = findmax(L_out)[2] + append!(x_out, x[1][indx]) end - indx = findmax(L_out)[2] - x_out = x[1][indx] - return L_out, x_out + + open("Lout.csv","w") do f + writedlm(f, [L_out]) + end + open("xout.csv","w") do m + writedlm(m, x_out) + end + return L_out, x_out[end] else L_out, x_out = [], [] L_tp = ones(length(x[1])) @@ -130,20 +242,27 @@ function MLE(x, rho, y; M::Union{AbstractVector,Nothing}=nothing, savefile=false append!(p_shape,length(x[i])) end - if M==nothing + if ismissing(M) M = SIC(size(vec(rho)[1])[1]) end if savefile == false + x_out = [] L_out = ones(p_shape...) for mi in 1:max_episode res_exp = y[mi] |> Int p_tp = real.(tr.(rho.*[M[res_exp]])) L_out = L_out.*p_tp + indx = findmax(L_out)[2] + append!(x_out, [[x[i][indx[i]] for i in 1:para_num]]) + end + open("Lout.csv","w") do f + writedlm(f, [L_out]) + end + open("xout.csv","w") do m + writedlm(m, x_out) end - indx = findmax(L_out)[2] - x_out = [x[i][indx[i]] for i in 1:para_num] - return L_out, x_out + return L_out, x_out[end] else L_out, x_out = [], [] L_tp = ones(p_shape...) @@ -166,3 +285,177 @@ function MLE(x, rho, y; M::Union{AbstractVector,Nothing}=nothing, savefile=false end end end + +function integ(x, p) + para_num = length(x) + mean = [0.0 for i in 1:para_num] + for i in 1:para_num + p_tp = p + if i == para_num + for si = 1:para_num-1 + p_tp = trapz(x[si], p_tp, Val(1)) + end + + elseif i == 1 + for si = para_num:2 + p_tp = trapz(x[si], p_tp) + end + else + p_tp = trapz(x[end], p_tp) + for si = 1:para_num-1 + p_tp = trapz(x[si], p_tp, Val(1)) + end + end + mean[i] = trapz(x[i], x[i].*p_tp) + end + mean +end + +""" + + BayesCost(x, p, xest, rho, M; W=missing, eps=GLOBAL_EPS) + +Calculation of the average Bayesian cost with a quadratic cost function. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `xest`: The estimators. +- `rho`: Parameterized density matrix. +- `M`: A set of POVM. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" +function BayesCost(x, p, xest, rho, M; W=missing, eps=GLOBAL_EPS) + para_num = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if para_num == 1 + # single-parameter scenario + if ismissing(M) + M = SIC(size(rho[1])[1]) + end + + p_num = length(x[1]) + value = [p[i]*sum([tr(rho[i]*M[mi])*(x[1][i]-xest[mi][1])^2 for mi in 1:length(M)]) for i in 1:p_num] + return real(trapz(x[1], value)) + else + # multi-parameter scenario + if ismissing(W) + W = Matrix(I, para_num, para_num) + end + + if ismissing(M) + M = SIC(size(vec(rho)[1])[1]) + end + + x_list = Iterators.product(x...) + p_num = length(x_list) + xCx = [sum([tr(rho_i*M[mi])*([xi...]-xest[mi])'*W*([xi...]-xest[mi]) for mi in 1:length(M)]) for (xi,rho_i) in zip(x_list,rho)] + xCx = reshape(xCx, size(p)) + + value = p.*xCx + for si in reverse(1:para_num) + value = trapz(x[si], value) + end + return real(value) + end +end + +""" + + BCB(x, p, rho; W=missing, eps=GLOBAL_EPS) + +Calculation of the minimum Bayesian cost with a quadratic cost function. +- `x`: The regimes of the parameters for the integral. +- `p`: The prior distribution. +- `rho`: Parameterized density matrix. +- `W`: Weight matrix. +- `eps`: Machine epsilon. +""" +function BCB(x, p, rho; W=missing, eps=GLOBAL_EPS) + para_num = length(x) + trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] + + if para_num == 1 + # single-parameter scenario + dim = size(rho[1])[1] + p_num = length(x[1]) + value = [p[i]*x[1][i]^2 for i in 1:p_num] + delta2_x = trapz(x[1], value) + rho_avg = zeros(ComplexF64, dim, dim) + rho_pri = zeros(ComplexF64, dim, dim) + + for di in 1:dim + for dj in 1:dim + rho_avg_arr = [p[m]*rho[m][di,dj] for m in 1:p_num] + rho_pri_arr = [p[n]*x[1][n]*rho[n][di,dj] for n in 1:p_num] + rho_avg[di,dj] = trapz(x[1], rho_avg_arr) + rho_pri[di,dj] = trapz(x[1], rho_pri_arr) + end + end + + Lambda = Lambda_avg(rho_avg, rho_pri, eps=eps) + minBC = delta2_x-real(tr(rho_avg*Lambda*Lambda)) + return minBC + else + # multi-parameter scenario + if ismissing(W) + W = Matrix(I, para_num, para_num) + end + x_list = Iterators.product(x...) + p_num = length(x_list) + xCx = [[xi...]'*W*[xi...] for xi in x_list] + xCx = reshape(xCx, size(p)) + + delta2_x = p.*xCx + for si in reverse(1:para_num) + delta2_x = trapz(x[si], delta2_x) + end + + term_tp = [pp*rho_i|>vec for (pp, rho_i) in zip(p, rho)] + rho_avg = trapzm(x, term_tp, para_num^2) |> I->reshape(I,para_num,para_num) + + x_re = Vector{Float64}[] + for xj in x_list + append!(x_re, [[_ for _ in xj]]) + end + + rho_pri = [trapzm(x, term_tp.*reshape([x_re[i][para_i] for i in 1:p_num], size(p)), para_num^2) |> I->reshape(I,para_num,para_num) for para_i in 1:para_num] + + Lambda = Lambda_avg(rho_avg, rho_pri, eps=eps) + + Mat = zeros(ComplexF64, para_num, para_num) + for para_m in 1:para_num + for para_n in 1:para_num + Mat += W[para_m, para_n]*(Lambda[para_m]*Lambda[para_n]) + end + end + + minBC = delta2_x-real(tr(rho_avg*Mat)) + return minBC + end +end + + +function Lambda_avg(rho_avg::Matrix{T}, rho_pri::Matrix{T}; eps=GLOBAL_EPS) where {T<:Complex} + dim = size(rho_avg)[1] + Lambda = Matrix{ComplexF64}(undef, dim, dim) + + val, vec = eigen(rho_avg) + val = val |> real + Lambda_eig = zeros(T, dim, dim) + for fi = 1:dim + for fj = 1:dim + if abs(val[fi] + val[fj]) > eps + Lambda_eig[fi, fj] = 2 * (vec[:, fi]' * rho_pri * vec[:, fj]) / (val[fi] + val[fj]) + end + end + end + Lambda_eig[findall(Lambda_eig == Inf)] .= 0.0 + + Lambda = vec * (Lambda_eig * vec') + return Lambda +end + +function Lambda_avg(rho_avg::Matrix{T}, rho_pri::Vector{Matrix{T}}; eps = GLOBAL_EPS) where {T<:Complex} + (x -> SLD(rho_avg, x; eps = eps)).(rho_pri) +end \ No newline at end of file diff --git a/src/common/common.jl b/src/common/common.jl index a1e451d..27fd2f4 100644 --- a/src/common/common.jl +++ b/src/common/common.jl @@ -1,7 +1,7 @@ include("mintime.jl") include("BayesEstimation.jl") -destroy(N) = diagm(1 => [1/sqrt(n) for n in 1:N-1]) +destroy(N) = diagm(1 => [sqrt(n)+0.0im for n in 1:N-1]) bases(dim; T=ComplexF64) = [e for e in I(dim).|>T|>eachrow] @@ -70,7 +70,14 @@ function suN_generatorW(n, k) return spdiagm(n,n,diagw) end -function suN_generator(n) +@doc raw""" + + suN_generator(n::Int64) + +Generation of the SU(``N``) generators with ``N`` the dimension of the system. +- `N`: The dimension of the system. +""" +function suN_generator(n::Int64) result = Vector{SparseMatrixCSC{ComplexF64, Int64}}(undef, n^2-1) idx = 2 itr = 1 @@ -98,10 +105,8 @@ end function sic_povm(fiducial) """ Generate a set of POVMs by applying the d^2 Weyl-Heisenberg displacement operators to a - fiducial state. - The Weyl-Heisenberg displacement operators are constructioned by Fuchs et al. in the article - https://doi.org/10.3390/axioms6030021 and it is realized in QBism. - + fiducial state. The Weyl-Heisenberg displacement operators are constructioned by Fuchs + et al. in the article https://doi.org/10.3390/axioms6030021 and it is realized in QBism. """ d = length(fiducial) w = exp(2.0*pi*1.0im/d) @@ -137,14 +142,22 @@ function sic_povm(fiducial) end return res end - -function SIC(dim) + +""" + + SIC(dim::Int64) + +Generation of a set of rank-one symmetric informationally complete positive operator-valued measure (SIC-POVM). +- `dim`: The dimension of the system. +Note: SIC-POVM is calculated by the Weyl-Heisenberg covariant SIC-POVM fiducial state which can be downloaded from [here](http://www.physics.umb.edu/Research/QBism/solutions.html). +""" +function SIC(dim::Int64) data = readdlm("$(pkgpath)/sic_fiducial_vectors/d$(dim).txt", '\t', Float64, '\n') fiducial = data[:,1]+1.0im*data[:,2] M = sic_povm(fiducial) end -function AdaptiveInput(x, func, dfunc; channel="dynamics") +function BayesInput(x, func, dfunc; channel="dynamics") para_num = length(x) x_size = [x[i] for i in 1:para_num] x_list = Iterators.product(x...) @@ -187,7 +200,7 @@ function Adam(gt, t, para, mt, vt, epsilon, beta1, beta2, eps) end #### bound coefficients of linear combination in Mopt #### -function bound_LC_coeff!(coefficients::Vector{Vector{Float64}}) +function bound_LC_coeff!(coefficients::Vector{Vector{Float64}}, rng) M_num = length(coefficients) basis_num = length(coefficients[1]) for ck in 1:M_num @@ -199,7 +212,7 @@ function bound_LC_coeff!(coefficients::Vector{Vector{Float64}}) Sum_col = [sum([coefficients[m][n] for m in 1:M_num]) for n in 1:basis_num] for si in 1:basis_num if Sum_col[si] == 0.0 - int_num = sample(1:M_num, 1, replace=false)[1] + int_num = sample(rng, 1:M_num, 1, replace=false)[1] coefficients[int_num][si] = 1.0 end end @@ -207,8 +220,8 @@ function bound_LC_coeff!(coefficients::Vector{Vector{Float64}}) Sum_row = [sum([coefficients[m][n] for n in 1:basis_num]) for m in 1:M_num] for mi in 1:M_num if Sum_row[mi] == 0.0 - int_num = sample(1:basis_num, 1, replace=false)[1] - coefficients[mi][int_num] = rand() + int_num = sample(rng, 1:basis_num, 1, replace=false)[1] + coefficients[mi][int_num] = rand(rng) end end @@ -331,12 +344,12 @@ function initial_LinearComb!(measurement0, B_all, basis_num, M_num, p_num, rng) measurement0 = [measurement0[i] for i in 1:p_num] end for pj in 1:length(measurement0) - B_all[pj] = measurement0[pj] isa AbstractVector ? deepcopy(measurement0[pj]) : [[measurement0[pj][i,j] for j in 1:dim] for i in 1:M_num] + B_all[pj] = measurement0[pj] isa AbstractVector ? deepcopy(measurement0[pj]) : [[measurement0[pj][i,j] for j in 1:basis_num] for i in 1:M_num] end for pj in (length(measurement0)+1):p_num B_all[pj] = [rand(rng, basis_num) for i in 1:M_num] - bound_LC_coeff!(B_all[pj]) + bound_LC_coeff!(B_all[pj], rng) end end diff --git a/src/common/mintime.jl b/src/common/mintime.jl index 0d72dde..c4c0650 100644 --- a/src/common/mintime.jl +++ b/src/common/mintime.jl @@ -1,6 +1,6 @@ ###################### mintime opt ############################# -function mintime(::Val{:binary}, f, system) - (; dynamics, output, obj) = system +function mintime(::Val{:binary}, f::Number, system) + (; dynamics, output, obj, optim, algorithm) = system (; tspan, ctrl) = deepcopy(dynamics.data) low, high = 1, length(tspan) mid = 0 @@ -11,7 +11,12 @@ function mintime(::Val{:binary}, f, system) dynamics.data.tspan = tspan[1:mid] dynamics.data.ctrl = [c[1:mid-1] for c in ctrl] - + if algorithm isa DE + algorithm.ini_population = ([dynamics.data.ctrl],) + elseif algorithm isa PSO + algorithm.ini_particle = ([dynamics.data.ctrl],) + end + f_ini = objective(obj, dynamics)[2] if f > f_ini @@ -38,8 +43,8 @@ function mintime(::Val{:binary}, f, system) println("The minimum time to reach target is ", dynamics.data.tspan[end],", data saved.") end -function mintime(::Val{:forward}, f, system) - (; dynamics, output, obj) = system +function mintime(::Val{:forward}, f::Number, system) + (; dynamics, output, obj, algorithm) = system (; tspan, ctrl) = deepcopy(dynamics.data) idx = 2 f_now = 0.0 @@ -47,6 +52,12 @@ function mintime(::Val{:forward}, f, system) while f_now < f && idx "quantum ", :CFIM => "classical ", :HCRB => "") + +const IO_opt = Dict( + :Copt => "control optimization", + :Sopt => "state optimization", + :Mopt => "measurement optimization", + :Mopt_input => "measurement optimization", + :SCopt => "comprehensive optimization", + :SMopt => "comprehensive optimization", + :CMopt => "comprehensive optimization", + :SCMopt => "comprehensive optimization", +) + +const IO_para = Dict( + :single_para => "single parameter scenario", + :multi_para => "multiparameter scenario", +) + +const IO_alg = Dict( + :GRAPE => "optimization algorithm: GRAPE", + :autoGRAPE => "optimization algorithm: auto-GRAPE", + :AD => "optimization algorithm: Automatic Differentiation (AD)", + :PSO => "optimization algorithm: Particle Swarm Optimization (PSO)", + :DE => "optimization algorithm: Differential Evolution (DE)", + :DDPG => "optimization algorithm: Deep Deterministic Policy Gradient (DDPG)", + :NM => "optimization algorithm: Nelder-Mead (NM)", + :Iterative => "optimization algorithm: Iterative", +) + +const IO_ini = Dict( + #### control optimization #### + ( + :Copt, + :QFIM, + :single_para, + ) => "non-controlled value of QFI is %f\ninitial value of QFI is %f\n", + ( + :Copt, + :QFIM, + :multi_para, + ) => "non-controlled value of tr(WF^{-1}) is %f\ninitial value of tr(WF^{-1}) is %f\n", + ( + :Copt, + :CFIM, + :single_para, + ) => "non-controlled value of CFI is %f\ninitial value of CFI is %f\n", + ( + :Copt, + :CFIM, + :multi_para, + ) => "non-controlled value of tr(WI^{-1}) is %f\ninitial value of tr(WI^{-1}) is %f\n", + ( + :Copt, + :HCRB, + :multi_para, + ) => "non-controlled value of HCRB is %f\ninitial value of HCRB is %f\n", + #### state optimization #### + ( + :Sopt, + :QFIM, + :single_para, + ) => "initial value of QFI is %f\n", + ( + :Sopt, + :QFIM, + :multi_para, + ) => "initial value of tr(WF^{-1}) is %f\n", + ( + :Sopt, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\n", + ( + :Sopt, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\n", + ( + :Sopt, + :HCRB, + :multi_para, + ) => "initial value of HCRB is %f\n", + + #### projective measurement optimization #### + ( + :Mopt, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\nQFI is %f\n", + ( + :Mopt, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\ninitial value of tr(WF^{-1}) is %f\n", + + #### measurement optimization for LinearComb and Rotation #### + ( + :Mopt_input, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\nCFI under the given POVM is %f\nQFI is %f\n", + ( + :Mopt_input, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\ntr(WI^{-1}) under the given POVM is %f\ntr(WF^{-1}) is %f\n", + + #### state and control optimization #### + ( + :SCopt, + :QFIM, + :single_para, + ) => "non-controlled value of QFI is %f\ninitial value of QFI is %f\n", + ( + :SCopt, + :QFIM, + :multi_para, + ) => "non-controlled value of tr(WF^{-1}) is %f\ninitial value of tr(WF^{-1}) is %f\n", + ( + :SCopt, + :CFIM, + :single_para, + ) => "non-controlled value of CFI is %f\ninitial value of CFI is %f\n", + ( + :SCopt, + :CFIM, + :multi_para, + ) => "non-controlled value of tr(WI^{-1}) is %f\ninitial value of tr(WI^{-1}) is %f\n", + ( + :SCopt, + :HCRB, + :multi_para, + ) => "non-controlled value of HCRB is %f\ninitial value of HCRB is %f\n", + #### state and measurement optimization #### + ( + :SMopt, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\n", + ( + :SMopt, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\n", + #### control and measurement optimization #### + ( + :CMopt, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\n", + ( + :CMopt, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\n", + #### state, control and measurement optimization #### + ( + :SCMopt, + :CFIM, + :single_para, + ) => "initial value of CFI is %f\n", + ( + :SCMopt, + :CFIM, + :multi_para, + ) => "initial value of tr(WI^{-1}) is %f\n", + +) + +const IO_current = Dict( + (:QFIM, :single_para) => "current value of QFI is %f (%i episodes)\r", + (:QFIM, :multi_para) => "current value of tr(WF^{-1}) is %f (%i episodes)\r", + (:CFIM, :single_para) => "current value of CFI is %f (%i episodes)\r", + (:CFIM, :multi_para) => "current value of of tr(WI^{-1}) is %f (%i episodes)\r", + (:HCRB, :multi_para) => "current value of of HCRB is %f (%i episodes)\r", +) + +const IO_final = Dict( + (:QFIM, :single_para) => "\e[2KIteration over, data saved.\nFinal value of QFI is %f\n", + ( + :QFIM, + :multi_para, + ) => "\e[2KIteration over, data saved.\nFinal value of tr(WF^{-1}) is %f\n", + (:CFIM, :single_para) => "\e[2KIteration over, data saved.\nFinal value of CFI is %f\n", + ( + :CFIM, + :multi_para, + ) => "\e[2KIteration over, data saved.\nFinal value of tr(WI^{-1}) is %f\n", + (:HCRB, :multi_para) => "\e[2KIteration over, data saved.\nFinal value of HCRB is %f\n", +) + +## io info +function show(system::QuanEstSystem) + (; optim, algorithm, obj) = system + println( + (optim isa ControlOpt ? IO_obj[obj_type(obj)] : "") * + IO_opt[opt_target(optim)], + ) + println(IO_para[para_type(obj)]) + println(IO_alg[alg_type(algorithm)]) +end + +## io initialization +function show(opt::AbstractOpt, output::Output, obj::AbstractObj) + (; io_buffer) = output + @eval @printf $(IO_ini[opt_target(opt), obj_type(obj), para_type(obj)]) $(io_buffer...) + SaveCurrent(output) +end + +## io current +function show(output::Output, obj::AbstractObj) + (; io_buffer) = output + @eval @printf $(IO_current[obj_type(obj), para_type(obj)]) $(io_buffer...) + SaveCurrent(output) +end + +## io final +function show(obj::AbstractObj, output::AbstractOutput) + (; io_buffer) = output + @eval @printf $(IO_final[obj_type(obj), para_type(obj)]) $(io_buffer...) + SaveFile(output) +end diff --git a/src/objective/BayesianBound/BayesianCramerRao.jl b/src/objective/BayesianBound/BayesianCramerRao.jl deleted file mode 100644 index 8c4c834..0000000 --- a/src/objective/BayesianBound/BayesianCramerRao.jl +++ /dev/null @@ -1,352 +0,0 @@ -########## Bayesian version of CFIM ########## -function BCFIM(x, p, rho, drho; M::Union{AbstractVector,Nothing}=nothing, eps=1e-8) - para_num = length(x) - if para_num == 1 - #### singleparameter scenario #### - p_num = length(p) - if M==nothing - M = SIC(size(rho[1])[1]) - end - F_tp = zeros(p_num) - for i in 1:p_num - F_tp[i] = CFIM(rho[i], drho[i], M; eps=eps) - end - F = 0.0 - arr = [p[i]*F_tp[i] for i in 1:p_num] - F = trapz(x[1], arr) - else - #### multiparameter scenario #### - if M==nothing - M = SIC(size(vec(rho)[1])[1]) - end - - xnum = length(x) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - end -end -########## Bayesian version of QFIM ########## -function BQFIM(x, p, rho, drho; LDtype=:SLD, eps=1e-8) - para_num = length(x) - if para_num == 1 - #### singleparameter scenario #### - p_num = length(p) - F_tp = zeros(p_num) - for i in 1:p_num - F_tp[i] = QFIM(rho[i], drho[i]; LDtype=LDtype, eps=eps) - end - F = 0.0 - arr = [p[i]*F_tp[i] for i in 1:p_num] - F = trapz(x[1], arr) - else - #### multiparameter scenario #### - xnum = length(x) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - Fs = [p*QFIM(rho,drho;LDtype=LDtype,eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - end -end - -########## Bayesian quantum Cramer-Rao bound ########## -function BQCRB(x, p, rho, drho; b=nothing, db=nothing, LDtype=:SLD, btype=1, eps=1e-8) - para_num = length(x) - - if b==nothing - b = [zero(x) for x in x] - db = [zero(x) for x in x] - end - if b!=nothing && db==nothing - db = [zero(x) for x in x] - end - - if para_num == 1 - - #### singleparameter scenario #### - p_num = length(p) - - if typeof(drho[1]) == Vector{Matrix{ComplexF64}} - drho = [drho[i][1] for i in 1:p_num] - end - if typeof(b[1]) == Vector{Float64} || typeof(b[1]) == Vector{Int64} - b = b[1] - end - if typeof(db[1]) == Vector{Float64} || typeof(db[1]) == Vector{Int64} - db = db[1] - end - F_tp = zeros(p_num) - for i in 1:p_num - f = QFIM(rho[i], drho[i]; LDtype=LDtype, eps=eps) - F_tp[i] = f - end - F = 0.0 - if btype == 1 - arr = [p[i]*((1+db[i])^2/F_tp[i]+b[i]^2) for i in 1:p_num] - F = trapz(x[1], arr) - elseif btype == 2 - arr = [p[i]*F_tp[i] for i in 1:p_num] - F1 = trapz(x[1], arr) - arr2 = [p[j]*(1+db[j]) for j in 1:p_num] - B = trapz(x[1], arr2) - arr3 = [p[k]*b[k]^2 for k in 1:p_num] - bb = trapz(x[1], arr3) - F = B^2/F1+bb - end - return F - else - #### multiparameter scenario #### - - xnum = length(x) - bs = Iterators.product(b...) - dbs = Iterators.product(db...) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - - if btype == 1 - integrand(p,rho,drho,b,db)=p*diagm(1 .+db)*pinv(QFIM(rho,drho;eps=eps))*diagm(1 .+db)+b*b' - integrands = [integrand(p,rho,drho,[b...],[db...])|>vec for (p,rho,drho,b,db) in zip(p,rho,drho,bs,dbs)] - I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) - elseif btype == 2 - Bs = [p*(1 .+[db...]) for (p,db) in zip(p,dbs)] - B = trapzm(x, Bs, xnum)|> diagm - Fs = [p*QFIM(rho,drho;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - bbts = [p*[b...]*[b...]'|>vec for (p,b) in zip(p,bs)] - I = B*pinv(F)*B + (trapzm(x, bbts, xnum^2) |> I->reshape(I,xnum,xnum)) - end - return I - end -end - -function BCRB(x, p, rho, drho; M::Union{AbstractVector,Nothing}=nothing, b=nothing, db=nothing, btype=1, eps=1e-8) - para_num = length(x) - - if b==nothing - b = [zero(x) for x in x] - db = [zero(x) for x in x] - end - if b!=nothing && db==nothing - db = [zero(x) for x in x] - end - - if para_num == 1 - #### singleparameter scenario #### - p_num = length(p) - if M==nothing - M = SIC(size(rho[1])[1]) - end - if typeof(drho[1]) == Vector{Matrix{ComplexF64}} - drho = [drho[i][1] for i in 1:p_num] - end - if typeof(b[1]) == Vector{Float64} || typeof(b[1]) == Vector{Int64} - b = b[1] - end - if typeof(db[1]) == Vector{Float64} || typeof(db[1]) == Vector{Int64} - db = db[1] - end - F_tp = zeros(p_num) - for i in 1:p_num - f = CFIM(rho[i], drho[i], M; eps=eps) - F_tp[i] = f - end - F = 0.0 - if btype == 1 - arr = [p[i]*((1+db[i])^2/F_tp[i]+b[i]^2) for i in 1:p_num] - F = trapz(x[1], arr) - elseif btype == 2 - arr = [p[i]*F_tp[i] for i in 1:p_num] - F1 = trapz(x[1], arr) - arr2 = [p[j]*(1+db[j]) for j in 1:p_num] - B = trapz(x[1], arr2) - arr3 = [p[k]*b[k]^2 for k in 1:p_num] - bb = trapz(x[1], arr3) - F = B^2/F1+bb - end - return F - else - #### multiparameter scenario #### - if M==nothing - M = SIC(size(vec(rho)[1])[1]) - end - - xnum = length(x) - bs = Iterators.product(b...) - dbs = Iterators.product(db...) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - - if btype == 1 - integrand(p,rho,drho,b,db)=p*diagm(1 .+db)*pinv(CFIM(rho,drho,M;eps=eps))*diagm(1 .+db)+b*b' - integrands = [integrand(p,rho,drho,[b...],[db...])|>vec for (p,rho,drho,b,db) in zip(p,rho,drho,bs,dbs)] - I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) - elseif btype == 2 - Bs = [p*(1 .+[db...]) for (p,db) in zip(p,dbs)] - B = trapzm(x, Bs, xnum)|> diagm - Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - bbts = [p*[b...]*[b...]'|>vec for (p,b) in zip(p,bs)] - I = B*pinv(F)*B + (trapzm(x, bbts, xnum^2) |> I->reshape(I,xnum,xnum)) - end - return I - end -end - -function QVTB(x, p, dp, rho, drho; LDtype=:SLD, btype=1, eps=1e-8) - para_num = length(x) - if para_num == 1 - #### singleparameter scenario #### - p_num = length(p) - if typeof(drho[1]) == Vector{Matrix{ComplexF64}} - drho = [drho[i][1] for i in 1:p_num] - end - if typeof(dp[1]) == Vector{Float64} - dp = [dp[i][1] for i in 1:p_num] - end - F_tp = zeros(p_num) - for m in 1:p_num - F_tp[m] = QFIM(rho[m], drho[m]; LDtype=LDtype, eps=eps) - end - I = 0.0 - if btype==1 - I_tp = [real(dp[i]*dp[i]/p[i]^2) for i in 1:p_num] - arr = [p[j]/(I_tp[j]+F_tp[j]) for j in 1:p_num] - I = trapz(x[1], arr) - elseif btype==2 - I, F = 0.0, 0.0 - arr1 = [real(dp[i]*dp[i]/p[i]) for i in 1:p_num] - I = trapz(x[1], arr1) - arr2 = [real(F_tp[j]*p[j]) for j in 1:p_num] - F = trapz(x[1], arr2) - I = 1.0/(I+F) - end - return I - else - #### multiparameter scenario #### - xnum = length(x) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - Ip(p,dp) = dp*dp'/p^2 - - if btype == 1 - integrand(p,dp,rho,drho)=p*pinv(Ip(p,dp)+QFIM(rho,drho;eps=eps)) - integrands = [integrand(p,dp,rho,drho)|>vec for (p,dp,rho,drho) in zip(p,dp,rho,drho)] - I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) - elseif btype == 2 - Iprs = [p*Ip(p,dp)|>vec for (p,dp) in zip(p,dp)] - Ipr = trapzm(x, Iprs, xnum^2)|> I->reshape(I,xnum,xnum) - Fs = [p*QFIM(rho,drho;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - I = pinv(Ipr+F) - end - return I - end -end - -function VTB(x, p, dp, rho, drho; M::Union{AbstractVector,Nothing}=nothing, btype=1, eps=1e-8) - para_num = length(x) - if para_num == 1 - #### singleparameter scenario #### - p_num = length(p) - if M==nothing - M = SIC(size(rho[1])[1]) - end - if typeof(drho[1]) == Vector{Matrix{ComplexF64}} - drho = [drho[i][1] for i in 1:p_num] - end - if typeof(dp[1]) == Vector{Float64} - dp = [dp[i][1] for i in 1:p_num] - end - F_tp = zeros(p_num) - for m in 1:p_num - F_tp[m] = CFIM(rho[m], drho[m], M; eps=eps) - end - res = 0.0 - if btype==1 - I_tp = [real(dp[i]*dp[i]/p[i]^2) for i in 1:p_num] - arr = [p[j]/(I_tp[j]+F_tp[j]) for j in 1:p_num] - res = trapz(x[1], arr) - elseif btype==2 - arr1 = [real(dp[i]*dp[i]/p[i]) for i in 1:p_num] - I = trapz(x[1], arr1) - arr2 = [real(F_tp[j]*p[j]) for j in 1:p_num] - F = trapz(x[1], arr2) - res = 1.0/(I+F) - end - return res - else - #### multiparameter scenario #### - if M==nothing - M = SIC(size(vec(rho)[1])[1]) - end - xnum = length(x) - trapzm(x, integrands, slice_dim) = [trapz(tuple(x...), I) for I in [reshape(hcat(integrands...)[i,:], length.(x)...) for i in 1:slice_dim]] - Ip(p,dp) = dp*dp'/p^2 - if btype == 1 - integrand(p,dp,rho,drho)=p*pinv(Ip(p,dp)+CFIM(rho,drho,M;eps=eps)) - integrands = [integrand(p,dp,rho,drho)|>vec for (p,dp,rho,drho) in zip(p,dp,rho,drho)] - I = trapzm(x, integrands, xnum^2) |> I->reshape(I,xnum,xnum) - elseif btype == 2 - Iprs = [p*Ip(p,dp)|>vec for (p,dp) in zip(p,dp)] - Ipr = trapzm(x, Iprs, xnum^2)|> I->reshape(I,xnum,xnum) - Fs = [p*CFIM(rho,drho,M;eps=eps)|>vec for (p,rho,drho) in zip(p,rho,drho)] - F = trapzm(x, Fs, xnum^2) |> I->reshape(I,xnum,xnum) - I = pinv(Ipr+F) - end - return I - end -end - -########## optimal biased bound ########## -function OBB_func(du, u, para, t) - F, J, x = para - J_tp = interp1(x, J, t) - F_tp = interp1(x, F, t) - bias = u[1] - dbias = u[2] - du[1] = dbias - du[2] = -J_tp*dbias + F_tp*bias - J_tp -end - -function boundary_condition(residual, u, p, t) - residual[1] = u[1][2] + 1.0 - residual[2] = u[end][2] + 1.0 -end - -function interp1(xspan, yspan, x) - idx = (x .>= xspan[1]) .& (x .<= xspan[end]) - intf = interpolate((xspan,), yspan, Gridded(Linear())) - y = intf[x[idx]] - return y -end - -function OBB(x, p, dp, rho, drho, d2rho; LDtype=:SLD, eps=1e-8) - p_num = length(p) - - if typeof(drho[1]) == Vector{Matrix{ComplexF64}} - drho = [drho[i][1] for i in 1:p_num] - end - if typeof(d2rho[1]) == Vector{Matrix{ComplexF64}} - d2rho = [d2rho[i][1] for i in 1:p_num] - end - if typeof(dp[1]) == Vector{Float64} - dp = [dp[i][1] for i in 1:p_num] - end - if typeof(x[1]) != Float64 || typeof(x[1]) != Int64 - x = x[1] - end - - delta = x[2] - x[1] - F, J = zeros(p_num), zeros(p_num) - for m in 1:p_num - f, LD = QFIM(Val{:exportLD}(),rho[m], drho[m]; LDtype=Symbol(LDtype), eps=eps) - dF = real(tr(2*d2rho[m]*d2rho[m]*LD - LD*LD*drho[m])) - J[m] = dp[m]/p[m] - dF/f - F[m] = f - end - - prob = BVProblem(OBB_func, boundary_condition, [0.0, 0.0], (x[1], x[end]), (F, J, x)) - sol = solve(prob, GeneralMIRK4(), dt=delta) - - bias = [sol.u[i][1] for i in 1:p_num] - dbias = [sol.u[i][2] for i in 1:p_num] - - value = [p[i]*((1+dbias[i])^2/F[i] + bias[i]^2) for i in 1:p_num] - return trapz(x, value) -end diff --git a/src/optim/optim.jl b/src/optim/optim.jl deleted file mode 100644 index c91f135..0000000 --- a/src/optim/optim.jl +++ /dev/null @@ -1,121 +0,0 @@ -abstract type AbstractOpt end - -abstract type AbstractMeasurementType end -abstract type Projection <: AbstractMeasurementType end -abstract type LC <: AbstractMeasurementType end -abstract type Rotation <: AbstractMeasurementType end - -abstract type Opt <: AbstractOpt end - -Base.@kwdef mutable struct ControlOpt <: Opt - ctrl::Union{AbstractVector, Missing} = missing - ctrl_bound::AbstractVector = [-Inf, Inf] -end - -Copt = ControlOpt -ControlOpt(ctrl::Matrix{R}, ctrl_bound::AbstractVector) where R<:Number = ControlOpt([c[:] for c in eachrow(ctrl)], ctrl_bound) - -Base.@kwdef mutable struct StateOpt <: Opt - psi::Union{AbstractVector, Missing} = missing -end - -Sopt = StateOpt - -abstract type AbstractMopt <: Opt end - -Base.@kwdef mutable struct Mopt_Projection <: AbstractMopt - M::Union{AbstractVector, Missing} = missing -end -Base.@kwdef mutable struct Mopt_LinearComb <: AbstractMopt - B::Union{AbstractVector, Missing} = missing - POVM_basis::Union{AbstractVector, Missing} = missing - M_num::Int = 1 -end -Base.@kwdef mutable struct Mopt_Rotation <: AbstractMopt - s::Union{AbstractVector, Missing} = missing - POVM_basis::Union{AbstractVector, Missing} = missing - Lambda::Union{AbstractVector, Missing} = missing -end - -function MeasurementOpt(;mtype=:Projection, kwargs...) - if mtype==:Projection - return Mopt_Projection(;kwargs...) - elseif mtype==:LC - return Mopt_LinearComb(;kwargs...) - elseif mtype==:Rotation - return Mopt_Rotation(;kwargs...) - end -end - -Mopt = MeasurementOpt - -abstract type CompOpt <: Opt end - -Base.@kwdef mutable struct StateControlOpt <: CompOpt - psi::Union{AbstractVector, Missing} = missing - ctrl::Union{AbstractVector, Missing} = missing - ctrl_bound::AbstractVector = [-Inf, Inf] -end - -SCopt = StateControlOpt - -Base.@kwdef mutable struct ControlMeasurementOpt <: CompOpt - ctrl::Union{AbstractVector, Missing} = missing - M::Union{AbstractVector, Missing} = missing - ctrl_bound::AbstractVector = [-Inf, Inf] -end - -CMopt = ControlMeasurementOpt - -Base.@kwdef mutable struct StateMeasurementOpt <: CompOpt - psi::Union{AbstractVector, Missing} = missing - M::Union{AbstractVector, Missing} = missing -end - -SMopt = StateMeasurementOpt - -Base.@kwdef mutable struct StateControlMeasurementOpt <: CompOpt - ctrl::Union{AbstractVector, Missing} = missing - psi::Union{AbstractVector, Missing} = missing - M::Union{AbstractVector, Missing} = missing - ctrl_bound::AbstractVector = [-Inf, Inf] -end - -SCMopt = StateControlMeasurementOpt - -opt_target(::ControlOpt) = :Copt -opt_target(::StateOpt) = :Sopt -opt_target(::Mopt_Projection) = :Mopt -opt_target(::Mopt_LinearComb) = :Mopt_input -opt_target(::Mopt_Rotation) = :Mopt_input -opt_target(::CompOpt) = :CompOpt -opt_target(::StateControlOpt) = :SCopt -opt_target(::ControlMeasurementOpt) = :CMopt -opt_target(::StateMeasurementOpt) = :SMopt -opt_target(::StateControlMeasurementOpt) = :SCMopt - -result(opt::ControlOpt) = [opt.ctrl] -result(opt::StateOpt) = [opt.psi] -result(opt::Mopt_Projection) = [opt.M] -result(opt::Mopt_LinearComb) = [opt.B, opt.POVM_basis, opt.M_num] -result(opt::Mopt_Rotation) = [opt.s] -result(opt::StateControlOpt) = [opt.psi, opt.ctrl] -result(opt::ControlMeasurementOpt) = [opt.ctrl, opt.M] -result(opt::StateMeasurementOpt) = [opt.psi, opt.M] -result(opt::StateControlMeasurementOpt) = [opt.psi, opt.ctrl, opt.M] - -#with reward -result(opt, ::Type{Val{:save_reward}}) = [result(opt)..., [0.0]] - -const res_file_name = Dict( - :Copt => ["controls.csv"], - :Sopt => ["states.csv"], - :Mopt => ["measurements.csv"], - :Mopt_input => ["measurements.csv"], - :SCopt => ["states.csv", "controls.csv"], - :CMopt => ["controls.csv", "measurements.csv"], - :SMopt => ["states.csv", "measurements.csv"], - :SCMopt => ["states.csv", "controls.csv", "measurements.csv"], -) - -res_file(opt::AbstractOpt) = res_file_name[opt_target(opt)] diff --git a/src/run.jl b/src/run.jl index 84bc9c2..7e043d6 100644 --- a/src/run.jl +++ b/src/run.jl @@ -21,11 +21,59 @@ function run(system::QuanEstSystem) show(obj, output) #io4 end -function run(opt::AbstractOpt, alg::AbstractAlgorithm, obj::AbstractObj,dynamics::AbstractDynamics;savefile::Bool=false) - output = Output(opt;save=savefile) +@doc raw""" + + run(opt::AbstractOpt, alg::AbstractAlgorithm, obj::AbstractObj, dynamics::AbstractDynamics; savefile::Bool=false) + +Run the optimization problem. +- `opt`: Types of optimization, options are `ControlOpt`, `StateOpt`, `MeasurementOpt`, `SMopt`, `SCopt`, `CMopt` and `SCMopt`. +- `alg`: Optimization algorithms, options are `auto-GRAPE`, `GRAPE`, `AD`, `PSO`, `DE`, 'NM' and `DDPG`. +- `obj`: Objective function, options are `QFIM_obj`, `CFIM_obj` and `HCRB_obj`. +- `dynamics`: Lindblad or Kraus parameterization process. +- `savefile`: Whether or not to save all the control coeffients. + +""" +function run(opt::AbstractOpt, alg::AbstractAlgorithm, obj::AbstractObj, dynamics::AbstractDynamics; savefile::Bool=false) + output = Output(opt; save=savefile) + obj = Objective(dynamics, obj) + + if obj isa HCRB_obj + if alg isa AD || alg isa AD_Adam + println("AD is not available when the objective function is HCRB.") + elseif alg isa GRAPE || alg isa GRAPE_Adam || alg isa autoGRAPE || alg isa autoGRAPE_Adam + println("GRAPE is not available when the objective function is HCRB.") + elseif obj isa HCRB_obj{single_para} + println("Program exit. In the single-parameter scenario, the HCRB is equivalent to the QFI. Please choose 'QFIM_obj()' as the objective function.") + else + system = QuanEstSystem(opt, alg, obj, dynamics, output) + run(system) + end + else + system = QuanEstSystem(opt, alg, obj, dynamics, output) + run(system) + end +end + +@doc raw""" + + mintime(f::Number, opt::ControlOpt, alg::AbstractAlgorithm, obj::AbstractObj, dynamics::AbstractDynamics; savefile::Bool=false, method::String="binary") + +Search of the minimum time to reach a given value of the objective function. +- `f`: The given value of the objective function. +- `opt`: Control Optimization. +- `alg`: Optimization algorithms, options are `auto-GRAPE`, `GRAPE`, `PSO`, `DE` and `DDPG`. +- `obj`: Objective function, options are `QFIM_obj`, `CFIM_obj` and `HCRB_obj`. +- `dynamics`: Lindblad dynamics. +- `savefile`: Whether or not to save all the control coeffients. +- `method`: Methods for searching the minimum time to reach the given value of the objective function. Options are `binary` and `forward`. + +- `system`: control system. +""" +function mintime(f::Number, opt::ControlOpt, alg::AbstractAlgorithm, obj::AbstractObj, dynamics::AbstractDynamics;savefile::Bool=false, method::String="binary") + output = Output(opt; save=savefile) obj = Objective(dynamics, obj) system = QuanEstSystem(opt, alg, obj, dynamics, output) - run(system) + mintime(method, f, system) end # function run(opt::AbstractOpt, alg::AbstractAlgorithm, dynamics::AbstractDynamics; objective::Symbol, W=missing, M=missing, LD_type=:SLD, eps=GLOBAL_EPS, save::Bool=false)