From 50701bbf3298cd720525febe98dc5b02b69d8d8b Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Thu, 28 Mar 2024 23:26:12 +0900 Subject: [PATCH 1/5] Use SafeTestsets and reorganize runtests --- Project.toml | 4 +- test/correlations_and_spectrum.jl | 18 + test/dynamical-shifted-fock.jl | 98 +++ test/dynamical_fock_dimension_mesolve.jl | 108 ++++ test/eigenvalues_and_operators.jl | 53 ++ test/entanglement.jl | 7 + test/generalized_master_equation.jl | 44 ++ test/low_rank_dynamics.jl | 79 +++ test/negativity_and_partial_transpose.jl | 30 + test/permutation.jl | 27 + test/quantum_objects.jl | 166 +++++ test/runtests.jl | 762 +---------------------- test/steady_state.jl | 24 + test/time_evolution_and_partial_trace.jl | 51 ++ test/wigner.jl | 23 + 15 files changed, 746 insertions(+), 748 deletions(-) create mode 100644 test/correlations_and_spectrum.jl create mode 100644 test/dynamical-shifted-fock.jl create mode 100644 test/dynamical_fock_dimension_mesolve.jl create mode 100644 test/eigenvalues_and_operators.jl create mode 100644 test/entanglement.jl create mode 100644 test/generalized_master_equation.jl create mode 100644 test/low_rank_dynamics.jl create mode 100644 test/negativity_and_partial_transpose.jl create mode 100644 test/permutation.jl create mode 100644 test/quantum_objects.jl create mode 100644 test/steady_state.jl create mode 100644 test/time_evolution_and_partial_trace.jl create mode 100644 test/wigner.jl diff --git a/Project.toml b/Project.toml index f8d37f49..09274c64 100644 --- a/Project.toml +++ b/Project.toml @@ -27,11 +27,13 @@ LinearMaps = "3" LinearSolve = "2" OrdinaryDiffEq = "6.30" Reexport = "1" +SafeTestsets = "0.1" SpecialFunctions = "2.2" julia = "1.7" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" [targets] -test = ["Test"] +test = ["Test", "SafeTestsets"] diff --git a/test/correlations_and_spectrum.jl b/test/correlations_and_spectrum.jl new file mode 100644 index 00000000..ded38a06 --- /dev/null +++ b/test/correlations_and_spectrum.jl @@ -0,0 +1,18 @@ +using QuantumToolbox + +a = destroy(10) +H = a' * a +c_ops = [sqrt(0.1 * (0.01 + 1)) * a, sqrt(0.1 * (0.01)) * a'] + +ω_l = range(0, 3, length=1000) +ω_l1, spec1 = spectrum(H, ω_l, a', a, c_ops, solver=FFTCorrelation(), progress=false) +ω_l2, spec2 = spectrum(H, ω_l, a', a, c_ops) +spec1 = spec1 ./ maximum(spec1) +spec2 = spec2 ./ maximum(spec2) + +test_func1 = maximum(real.(spec1)) * (0.1/2)^2 ./ ((ω_l1 .- 1).^2 .+ (0.1/2)^2) +test_func2 = maximum(real.(spec2)) * (0.1/2)^2 ./ ((ω_l2 .- 1).^2 .+ (0.1/2)^2) +idxs1 = test_func1 .> 0.05 +idxs2 = test_func2 .> 0.05 +@test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < 0.01 +@test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < 0.01 \ No newline at end of file diff --git a/test/dynamical-shifted-fock.jl b/test/dynamical-shifted-fock.jl new file mode 100644 index 00000000..a5b59afb --- /dev/null +++ b/test/dynamical-shifted-fock.jl @@ -0,0 +1,98 @@ +using QuantumToolbox + +F = 3 +Δ = 0.25 +κ = 1 +U = 0.01 + +tlist = LinRange(0,25,300) + +# Single cavity case +N0 = 100 +a0 = destroy(N0) +H0 = Δ*a0'*a0 + F*(a0+a0') + U * a0'^2 * a0^2 +c_ops0 = [√(κ)*a0] + +α0 = 1.5 +ρ0 = coherent(N0, α0) +sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a0'*a0, a0], progress=false) + +N = 5 +a = destroy(N) +function H_dsf(op_list, p) + Δ = p.Δ + F = p.F + U = p.U + a = op_list[1] + Δ*a'*a + F*(a + a') + U * a'^2 * a^2 +end +function c_ops_dsf(op_list, p) + κ = p.κ + a = op_list[1] + [√κ * a] +end +function e_ops_dsf(op_list, p) + a = op_list[1] + [a' * a, a] +end +op_list = [a] +ψ0 = fock(N, 0) +α0_l = [α0] +dsf_params = (Δ=Δ, F=F, κ=κ, U=U) + +sol_dsf_me = dsf_mesolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress=false) +sol_dsf_mc = dsf_mcsolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress=false, n_traj=500) +val_ss = abs2(sol0.expect[1,end]) +@test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.1 +@test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.1 + +# Two cavities case +F = 2 +Δ = 0.25 +κ = 1 +U = 0.01 +J = 0.5 +tlist = LinRange(0,15,300) + +N0 = 20 +a10 = kron(destroy(N0), qeye(N0)) +a20 = kron(qeye(N0), destroy(N0)) +H0 = Δ*a10'*a10 + Δ*a20'*a20 + U*a10'^2*a10^2 + U*a20'^2*a20^2 + F*(a10+a10') + J*(a10'*a20 + a10*a20') +c_ops0 = [√κ*a10, √κ*a20] + +ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) +sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a10'*a10, a20'*a20], progress=false) + +N = 5 +a1 = kron(destroy(N), qeye(N)) +a2 = kron(qeye(N), destroy(N)) +function H_dsf2(op_list, p) + Δ = p.Δ + F = p.F + U = p.U + J = p.J + a1, a2 = op_list + Δ*a1'*a1 + Δ*a2'*a2 + U*a1'^2*a1^2 + U*a2'^2*a2^2 + F*(a1 + a1') + J*(a1'*a2 + a1*a2') +end +function c_ops_dsf2(op_list, p) + κ = p.κ + a1, a2 = op_list + [√κ * a1, √κ * a2] +end +function e_ops_dsf2(op_list, p) + a1, a2 = op_list + [a1' * a1, a2' * a2] +end +op_list = [a1, a2] +ψ0 = kron(fock(N, 0), fock(N, 0)) +α0_l = [α0, α0] +dsf_params = (Δ=Δ, F=F, κ=κ, U=U, J=J) + +sol_dsf_me = dsf_mesolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress=false) +sol_dsf_mc = dsf_mcsolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress=false, n_traj=500) + +val_ss = abs2(sol0.expect[1,end]) +@test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.6 +@test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.6 +@test sum(abs2.(sol0.expect[2,:] .- sol_dsf_me.expect[2,:])) / (val_ss * length(tlist)) < 0.6 +@test sum(abs2.(sol0.expect[2,:] .- sol_dsf_mc.expect[2,:])) / (val_ss * length(tlist)) < 0.6 \ No newline at end of file diff --git a/test/dynamical_fock_dimension_mesolve.jl b/test/dynamical_fock_dimension_mesolve.jl new file mode 100644 index 00000000..56a965c8 --- /dev/null +++ b/test/dynamical_fock_dimension_mesolve.jl @@ -0,0 +1,108 @@ +using Test +using QuantumToolbox + +### DYNAMICAL FOCK DIMENSION ### +F, Δ, κ = 5, 0.25, 1 +t_l = range(0, 15, length=100) + +N0 = 140 +a0 = destroy(N0) +H0 = Δ * a0' * a0 + F * (a0 + a0') +c_ops0 = [√κ * a0] +e_ops0 = [a0' * a0] +ψ00 = fock(N0, 0) +sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) + +function H_dfd0(dims, p) + Δ = p.Δ + F = p.F + a = destroy(dims[1]) + Δ * a' * a + F * (a + a') +end +function c_ops_dfd0(dims, p) + κ = p.κ + a = destroy(dims[1]) + [√κ * a] +end +function e_ops_dfd0(dims, p) + a = destroy(dims[1]) + [a' * a] +end +maxdims = [150] +ψ0 = fock(3, 0) +dfd_params = (Δ=Δ, F=F, κ=κ) +sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops=e_ops_dfd0, progress=false); + +@test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 + +###################### + +F = 0 +H0 = Δ * a0' * a0 + F * (a0 + a0') +c_ops0 = [√κ * a0] +e_ops0 = [a0' * a0] +ψ00 = fock(N0, 50) +sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) + +function H_dfd1(dims, p) + Δ = p.Δ + F = p.F + a = destroy(dims[1]) + Δ * a' * a + F * (a + a') +end +function c_ops_dfd1(dims, p) + κ = p.κ + a = destroy(dims[1]) + [√κ * a] +end +function e_ops_dfd1(dims, p) + a = destroy(dims[1]) + [a' * a] +end +maxdims = [150] +ψ0 = fock(70, 50) +dfd_params = (Δ=Δ, F=F, κ=κ) +sol = dfd_mesolve(H_dfd1, ψ0, t_l, c_ops_dfd1, maxdims, dfd_params, e_ops=e_ops_dfd1, progress=false) + +@test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 + + +###################### + +F, Δ, κ, J = 1.5, 0.25, 1, 0.05 +N0 = 25 +N1 = 20 +a0 = kron(destroy(N0), qeye(N1)) +a1 = kron(qeye(N0), destroy(N1)) +H0 = Δ * a0' * a0 + F * (a0 + a0') + Δ * a1' * a1 + J * (a0' * a1 + a0 * a1') +c_ops0 = [√κ * a0, √κ * a1] +e_ops0 = [a0' * a0, a1' * a1] +ψ00 = kron(fock(N0, 0), fock(N1, 15)) +sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) + +function H_dfd2(dims, p) + Δ = p.Δ + F = p.F + J = p.J + a = kron(destroy(dims[1]), qeye(dims[2])) + b = kron(qeye(dims[1]), destroy(dims[2])) + Δ * a' * a + F * (a + a') + Δ * b' * b + J * (a' * b + a * b') +end +function c_ops_dfd2(dims, p) + κ = p.κ + a = kron(destroy(dims[1]), qeye(dims[2])) + b = kron(qeye(dims[1]), destroy(dims[2])) + [√κ * a, √κ * b] +end +function e_ops_dfd2(dims, p) + a = kron(destroy(dims[1]), qeye(dims[2])) + b = kron(qeye(dims[1]), destroy(dims[2])) + [a' * a, b' * b] +end +maxdims = [50, 50] +ψ0 = kron(fock(3, 0), fock(20, 15)) +dfd_params = (Δ=Δ, F=F, κ=κ, J=J) +sol = dfd_mesolve(H_dfd2, ψ0, t_l, c_ops_dfd2, maxdims, dfd_params, e_ops=e_ops_dfd2, progress=false) + +@test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) + + sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 \ No newline at end of file diff --git a/test/eigenvalues_and_operators.jl b/test/eigenvalues_and_operators.jl new file mode 100644 index 00000000..d9a4d1b7 --- /dev/null +++ b/test/eigenvalues_and_operators.jl @@ -0,0 +1,53 @@ +using QuantumToolbox + +N = 30 +a = kron(destroy(N), qeye(2)) +a_d = a' + +sm = kron(qeye(N), sigmam()) +sp = sm' +sx = kron(qeye(N), sigmax()) +sy = kron(qeye(N), sigmay()) +sz = kron(qeye(N), sigmaz()) + +η = 0.2 +H_d = a_d * a + 0.5 * sz - 1im * η * (a - a_d) * sx + η^2 +H_c = a_d * a + 0.5 * (sz * cosm(2 * η * (a + a_d)) + sy * sinm(2 * η * (a + a_d))) + +vals_d, vecs_d = eigen(H_d) +vals_c, vecs_c = eigen((H_c)) +vals2, vecs2 = eigsolve(H_d, sigma=-0.9, k=10, krylovdim=30) +sort!(vals_c, by=real) +sort!(vals2, by=real) + +@test sum(real.(vals_d[1:20]) .- real.(vals_c[1:20])) / 20 < 1e-3 +@test sum(real.(vals_d[1:10]) .- real.(vals2[1:10])) / 20 < 1e-3 + + +N = 5 +a = kron(destroy(N), qeye(N)) +a_d = a' +b = kron(qeye(N), destroy(N)) +b_d = b' + +ωc = 1 +ωb = 1 +g = 0.01 +κ = 0.1 +n_thermal = 0.01 + +H = ωc * a_d * a + ωb * b_d * b + g * (a + a_d) * (b + b_d) +c_ops = [√((1+n_thermal)*κ) * a, √κ * b, √(n_thermal*κ) * a_d] +L = liouvillian(H, c_ops).data + +vals, vecs = eigsolve(L, sigma=0.01, k=10, krylovdim=50) +vals2, vecs2 = eigen(sparse_to_dense(L)) +vals3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1\(40*κ), k=10, krylovdim=50) +idxs = sortperm(vals2, by=abs) +vals2 = vals2[idxs][1:10] +vecs2 = vecs2[:, idxs][:, 1:10] + +@test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) +@test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) +@test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs2[:, 1]), atol=1e-7) +@test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs3[:, 1]), atol=1e-5) \ No newline at end of file diff --git a/test/entanglement.jl b/test/entanglement.jl new file mode 100644 index 00000000..8b608542 --- /dev/null +++ b/test/entanglement.jl @@ -0,0 +1,7 @@ +using QuantumToolbox + +g = fock(2, 1) +e = fock(2, 0) +state = normalize(kron(g, e) + kron(e, g)) +rho = state * state' +@test entanglement(state, 1) / log(2) ≈ 1 \ No newline at end of file diff --git a/test/generalized_master_equation.jl b/test/generalized_master_equation.jl new file mode 100644 index 00000000..d2c98eb9 --- /dev/null +++ b/test/generalized_master_equation.jl @@ -0,0 +1,44 @@ +using QuantumToolbox + +N_c = 30 +N_trunc = 10 +tol=1e-14 + +a = kron(destroy(N_c), qeye(2)) +sm = kron(qeye(N_c), sigmam()) +sp = sm' +sx = sm + sp +sz = sp * sm - sm * sp + +H = 1 * a' * a + 1 * sz / 2 + 0.5 * (a + a') * sx + +fields = [sqrt(0.01) * (a + a'), sqrt(0.01) * sx] +Tlist = [0, 0.0] + +E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) +Ω = dense_to_sparse((E' .- E)[1:N_trunc,1:N_trunc], tol) + +H_d = Qobj(dense_to_sparse((U' * H * U)[1:N_trunc,1:N_trunc], tol)) +Xp = Qobj( Ω .* dense_to_sparse(triu((U' * (a + a') * U).data[1:N_trunc,1:N_trunc], 1), tol)) +a2 = Qobj( dense_to_sparse((U' * a * U).data[1:N_trunc,1:N_trunc], tol)) +sm2 = Qobj( dense_to_sparse((U' * sm * U).data[1:N_trunc,1:N_trunc], tol)) + +# Standard liouvillian case +c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] +L2 = liouvillian(H_d, c_ops) + +@test (expect(Xp'*Xp, steadystate(L1)) < 1e-10 && expect(Xp'*Xp, steadystate(L2)) > 1e-3) + +H = 1 * a' * a + 1 * sz / 2 + 1e-5 * (a * sp + a' * sm) + +Tlist = [0.2, 0.0] + +E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) +Ω = dense_to_sparse((E' .- E)[1:N_trunc,1:N_trunc], tol) + +H_d = Qobj(dense_to_sparse((U' * H * U)[1:N_trunc,1:N_trunc], tol)) +Xp = Qobj( Ω .* dense_to_sparse(triu((U' * (a + a') * U).data[1:N_trunc,1:N_trunc], 1), tol)) +a2 = Qobj( dense_to_sparse((U' * a * U).data[1:N_trunc,1:N_trunc], tol)) +sm2 = Qobj( dense_to_sparse((U' * sm * U).data[1:N_trunc,1:N_trunc], tol)) + +@test abs(expect(Xp'*Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 \ No newline at end of file diff --git a/test/low_rank_dynamics.jl b/test/low_rank_dynamics.jl new file mode 100644 index 00000000..60ea8c33 --- /dev/null +++ b/test/low_rank_dynamics.jl @@ -0,0 +1,79 @@ +using QuantumToolbox + +# Define lattice +Nx,Ny = 2, 3 +latt = Lattice(Nx=Nx, Ny=Ny) +N_cut = 2 +N_modes = latt.N +N = N_cut^N_modes +M = Nx*Ny+1 + +# Define initial state +ϕ = Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject}}(undef, M) +ϕ[1] = tensor(repeat([basis(2,0)], N_modes)...) +global i=1 +for j in 1:N_modes + global i+=1 + i<=M && (ϕ[i] = mb(sp, j, latt) * ϕ[1]) +end +for k in 1:N_modes-1 + for l=k+1:N_modes + global i+=1 + i<=M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1]) + end +end +for i in i+1:M + ϕ[i] = Qobj(rand(ComplexF64,size(ϕ[1])[1]), dims=ϕ[1].dims) + normalize!(ϕ[i]) +end +z = hcat(broadcast(x->x.data, ϕ)...) +B = Matrix(Diagonal([1+0im; zeros(M-1)])) +S = z'*z +B = B / tr(S*B) +ρ = Qobj(z*B*z', dims=ones(Int,N_modes)*N_cut) + +# Define Hamiltonian and collapse operators +Jx = 0.9 +Jy = 1.02 +Jz = 1. +hx = 0. +γ = 1 +Sz = sum([mb(sz, i, latt) for i in 1:latt.N]) +tl = LinRange(0,10,100) + +H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc=pbc, order=1) +e_ops = (Sz,) + +# Full solution +mesol = mesolve(H, ρ, tl, c_ops; e_ops=[e_ops...]); +A = Matrix(mesol.states[end].data) +λ = eigvals(Hermitian(A)) +Strue = -sum(λ.*log2.(λ)) + +# Low rank solution +function f_entropy(p,z,B) + C = p.A0 + σ = p.Bi + mul!(C, z, sqrt(B)) + mul!(σ, C', C) + λ = eigvals(Hermitian(σ)) + λ = λ[λ.>1e-10] + return -sum(λ .* log2.(λ)) +end + +opt = LRMesolveOptions( + alg = Tsit5(), + err_max = 1e-3, + p0 = 0., + atol_inv = 1e-6, + adj_condition="variational", + Δt = 0.2, ) +lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops=e_ops, f_ops=(f_entropy,), opt=opt) + +# Test +m_me = real(mesol.expect[1,:]) +m_lr = real(lrsol.expvals[1,:]) +@test all(abs.((m_me .- m_lr)./m_me).<0.1) + +S_lr = real(lrsol.funvals[1,end]) +@test abs((S_lr - Strue)/Strue) < 0.5 \ No newline at end of file diff --git a/test/negativity_and_partial_transpose.jl b/test/negativity_and_partial_transpose.jl new file mode 100644 index 00000000..6f9074de --- /dev/null +++ b/test/negativity_and_partial_transpose.jl @@ -0,0 +1,30 @@ +using QuantumToolbox + +# tests for negativity +rho = (1 / 40) * Qobj([ + 15 1 1 15; + 1 5 -3 1; + 1 -3 5 1; + 15 1 1 15]; + dims = [2, 2] +) +Neg = negativity(rho, 1) +@test Neg ≈ 0.25 +@test negativity(rho, 2) ≈ Neg +@test negativity(rho, 1; logarithmic=true) ≈ log2(2 * Neg + 1) +@test_throws ErrorException negativity(rho, 3) + +# tests for partial transpose (PT) +# A (24 * 24)-matrix which contains number 1 ~ 576 +A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims = [2, 3, 4]) +A_sparse = dense_to_sparse(A_dense) +PT = (true, false) +for s1 in PT + for s2 in PT + for s3 in PT + mask = [s1, s2, s3] + @test partial_transpose(A_dense, mask) == partial_transpose(A_sparse, mask) + end + end +end +@test_throws ErrorException partial_transpose(rho, [true]) \ No newline at end of file diff --git a/test/permutation.jl b/test/permutation.jl new file mode 100644 index 00000000..b0adb322 --- /dev/null +++ b/test/permutation.jl @@ -0,0 +1,27 @@ +using QuantumToolbox + +# Block Diagonal Form +N = 20 +Δ = 0 +G = 5 +tg = 0 +θ = atan(tg) +U = sin(θ) +κ2 = cos(θ) +κ1 = 0. +κϕ = 1e-3 +nth = 0. + +a = destroy(N) +ad = create(N) +H = -Δ*ad*a + G/2*(ad^2 + a^2) + U/2*(ad^2*a^2) +c_ops = [√(κ2)*a^2, √(κ1*(nth+1))*a, √(κ1*nth)*ad, √(κϕ)*ad*a] +L = liouvillian(H,c_ops) + +P, L_bd, block_sizes = bdf(L) +blocks_list, block_indices = get_bdf_blocks(L_bd, block_sizes) +@test size(L_bd) == size(L) +@test length(block_sizes) == 4 +@test length(blocks_list) == 4 +@test length(block_indices) == 4 +@test sum(block_sizes .== 100) == 4 \ No newline at end of file diff --git a/test/quantum_objects.jl b/test/quantum_objects.jl new file mode 100644 index 00000000..c4148cab --- /dev/null +++ b/test/quantum_objects.jl @@ -0,0 +1,166 @@ +using QuantumToolbox + +N = 10 +a = rand(ComplexF64, 10) +# @test_logs (:warn, "The norm of the input data is not one.") QuantumObject(a) +a2 = Qobj(a, type=BraQuantumObject) +a3 = Qobj(a, type=KetQuantumObject) +@test isket(a2) == false +@test isbra(a2) == true +@test isoper(a2) == false +@test issuper(a2) == false +@test isket(a3) == true +@test isbra(a3) == false +@test isoper(a3) == false +@test issuper(a3) == false +@test Qobj(a3) == a3 +@test !(Qobj(a3) === a3) + +a = sprand(ComplexF64, 100, 100, 0.1) +a2 = Qobj(a, type=OperatorQuantumObject) +a3 = Qobj(a, type=SuperOperatorQuantumObject) + +@test isket(a2) == false +@test isbra(a2) == false +@test isoper(a2) == true +@test issuper(a2) == false +@test isket(a3) == false +@test isbra(a3) == false +@test isoper(a3) == false +@test issuper(a3) == true + +a = Array(a) +a4 = Qobj(a) +a5 = sparse(a4) +@test isequal(a5, a2) +@test (a5 == a3) == false +@test a5 ≈ a2 + +@test +a2 == a2 +@test -(-a2) == a2 +@test a2^3 ≈ a2 * a2 * a2 +@test a2 + 2 == 2 + a2 +@test (a2 + 2).data == a2.data + 2 * I +@test a2 * 2 == 2 * a2 + +@test transpose(transpose(a2)) == a2 +@test transpose(a2).data == transpose(a2.data) +@test adjoint(adjoint(a2)) == a2 +@test adjoint(a2).data == adjoint(a2.data) + +N = 10 +a = fock(N, 3) +@test sparse(ket2dm(a)) ≈ projection(N, 3, 3) +@test isket(a') == false +@test isbra(a') == true +@test size(a) == (N,) +@test size(a') == (1, N) +@test norm(a) ≈ 1 +@test norm(a') ≈ 1 + +ψ = Qobj(normalize(rand(ComplexF64, N))) +@test dot(ψ, ψ) ≈ norm(ψ) +@test dot(ψ, ψ) ≈ ψ' * ψ + +a = Qobj(rand(ComplexF64, N)) +@test (norm(a) ≈ 1) == false +@test (norm(normalize(a)) ≈ 1) == true +@test (norm(a) ≈ 1) == false # Again, to be sure that it is still non-normalized +normalize!(a) +@test (norm(a) ≈ 1) == true + +a = destroy(N) +a_d = a' +X = a + a_d +Y = 1im * (a - a_d) +Z = a + transpose(a) +@test ishermitian(X) == true +@test ishermitian(Y) == true +@test issymmetric(Y) == false +@test issymmetric(Z) == true + +@test Y[1, 2] == conj(Y[2, 1]) + +@test triu(X) == a +@test tril(X) == a_d + +triu!(X) +@test X == a +tril!(X) +@test nnz(X) == 0 + +# Eigenvalues +@test eigvals(a_d * a) ≈ 0:9 + +# Random density matrix +ρ = rand_dm(10) +@test tr(ρ) ≈ 1 +@test isposdef(ρ) == true + +# Expectation value +a = destroy(10) +ψ = normalize(fock(10, 3) + 1im * fock(10, 4)) +@test expect(a, ψ) ≈ expect(a, ψ') +ψ = fock(10, 3) +@test norm(ψ' * a) ≈ 2 +@test expect(a' * a, ψ' * a) ≈ 16 + +# REPL show +a = destroy(N) +ψ = fock(N, 3) + +opstring = sprint((t, s) -> show(t, "text/plain", s), a) +datastring = sprint((t, s) -> show(t, "text/plain", s), a.data) +a_dims = a.dims +a_size = size(a) +a_isherm = ishermitian(a) +@test opstring == "Quantum Object: type=Operator dims=$a_dims size=$a_size ishermitian=$a_isherm\n$datastring" + +a = spre(a) +opstring = sprint((t, s) -> show(t, "text/plain", s), a) +datastring = sprint((t, s) -> show(t, "text/plain", s), a.data) +a_dims = a.dims +a_size = size(a) +a_isherm = ishermitian(a) +@test opstring == "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" + +opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) +datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) +ψ_dims = ψ.dims +ψ_size = size(ψ) +@test opstring == "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" + +ψ = ψ' +opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) +datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) +ψ_dims = ψ.dims +ψ_size = size(ψ) +@test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" + +ψ = coherent(30, 3) +α, δψ = get_coherence(ψ) +@test isapprox(abs(α), 3, atol=1e-5) && abs2(δψ[1]) > 0.999 + +# Broadcasting +a = destroy(20) +for op in ((+), (-), (*), (^)) + A = broadcast(op, a, a) + @test A.data == broadcast(op, a.data, a.data) && A.type == a.type && A.dims == a.dims + + A = broadcast(op, 2.1, a) + @test A.data == broadcast(op, 2.1, a.data) && A.type == a.type && A.dims == a.dims + + A = broadcast(op, a, 2.1) + @test A.data == broadcast(op, a.data, 2.1) && A.type == a.type && A.dims == a.dims +end + +# tidyup tests +ρ1 = rand_dm(20) +ρ2 = dense_to_sparse(ρ1) +@test tidyup!(ρ2, 0.1) == ρ2 != ρ1 +@test dense_to_sparse(tidyup!(ρ1, 0.1)) == ρ2 + +ρ1 = rand_dm(20) +ρ2 = dense_to_sparse(ρ1) +@test tidyup(ρ2, 0.1) != ρ2 +@test dense_to_sparse(tidyup(ρ1, 0.1)) == tidyup(ρ2, 0.1) \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index beae23cb..adbfa363 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,747 +1,15 @@ -using QuantumToolbox -using Test - - -@testset "QuantumObjects" begin - a = rand(ComplexF64, 10) - # @test_logs (:warn, "The norm of the input data is not one.") QuantumObject(a) - a2 = Qobj(a, type=BraQuantumObject) - a3 = Qobj(a, type=KetQuantumObject) - @test isket(a2) == false - @test isbra(a2) == true - @test isoper(a2) == false - @test issuper(a2) == false - @test isket(a3) == true - @test isbra(a3) == false - @test isoper(a3) == false - @test issuper(a3) == false - @test Qobj(a3) == a3 - @test !(Qobj(a3) === a3) - - a = sprand(ComplexF64, 100, 100, 0.1) - a2 = Qobj(a, type=OperatorQuantumObject) - a3 = Qobj(a, type=SuperOperatorQuantumObject) - - @test isket(a2) == false - @test isbra(a2) == false - @test isoper(a2) == true - @test issuper(a2) == false - @test isket(a3) == false - @test isbra(a3) == false - @test isoper(a3) == false - @test issuper(a3) == true - - a = Array(a) - a4 = Qobj(a) - a5 = sparse(a4) - @test isequal(a5, a2) - @test (a5 == a3) == false - @test a5 ≈ a2 - - @test +a2 == a2 - @test -(-a2) == a2 - @test a2^3 ≈ a2 * a2 * a2 - @test a2 + 2 == 2 + a2 - @test (a2 + 2).data == a2.data + 2 * I - @test a2 * 2 == 2 * a2 - - @test transpose(transpose(a2)) == a2 - @test transpose(a2).data == transpose(a2.data) - @test adjoint(adjoint(a2)) == a2 - @test adjoint(a2).data == adjoint(a2.data) - - N = 10 - a = fock(N, 3) - @test sparse(ket2dm(a)) ≈ projection(N, 3, 3) - @test isket(a') == false - @test isbra(a') == true - @test size(a) == (N,) - @test size(a') == (1, N) - @test norm(a) ≈ 1 - @test norm(a') ≈ 1 - - ψ = Qobj(normalize(rand(ComplexF64, N))) - @test dot(ψ, ψ) ≈ norm(ψ) - @test dot(ψ, ψ) ≈ ψ' * ψ - - a = Qobj(rand(ComplexF64, N)) - @test (norm(a) ≈ 1) == false - @test (norm(normalize(a)) ≈ 1) == true - @test (norm(a) ≈ 1) == false # Again, to be sure that it is still non-normalized - normalize!(a) - @test (norm(a) ≈ 1) == true - - a = destroy(N) - a_d = a' - X = a + a_d - Y = 1im * (a - a_d) - Z = a + transpose(a) - @test ishermitian(X) == true - @test ishermitian(Y) == true - @test issymmetric(Y) == false - @test issymmetric(Z) == true - - @test Y[1, 2] == conj(Y[2, 1]) - - @test triu(X) == a - @test tril(X) == a_d - - triu!(X) - @test X == a - tril!(X) - @test nnz(X) == 0 - - # Eigenvalues - @test eigvals(a_d * a) ≈ 0:9 - - # Random density matrix - ρ = rand_dm(10) - @test tr(ρ) ≈ 1 - @test isposdef(ρ) == true - - # Expectation value - a = destroy(10) - ψ = normalize(fock(10, 3) + 1im * fock(10, 4)) - @test expect(a, ψ) ≈ expect(a, ψ') - ψ = fock(10, 3) - @test norm(ψ' * a) ≈ 2 - @test expect(a' * a, ψ' * a) ≈ 16 - - # REPL show - a = destroy(N) - ψ = fock(N, 3) - - opstring = sprint((t, s) -> show(t, "text/plain", s), a) - datastring = sprint((t, s) -> show(t, "text/plain", s), a.data) - a_dims = a.dims - a_size = size(a) - a_isherm = ishermitian(a) - @test opstring == "Quantum Object: type=Operator dims=$a_dims size=$a_size ishermitian=$a_isherm\n$datastring" - - a = spre(a) - opstring = sprint((t, s) -> show(t, "text/plain", s), a) - datastring = sprint((t, s) -> show(t, "text/plain", s), a.data) - a_dims = a.dims - a_size = size(a) - a_isherm = ishermitian(a) - @test opstring == "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" - - opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) - datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) - ψ_dims = ψ.dims - ψ_size = size(ψ) - @test opstring == "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" - - ψ = ψ' - opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) - datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) - ψ_dims = ψ.dims - ψ_size = size(ψ) - @test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" - - ψ = coherent(30, 3) - α, δψ = get_coherence(ψ) - @test isapprox(abs(α), 3, atol=1e-5) && abs2(δψ[1]) > 0.999 - - # Broadcasting - a = destroy(20) - for op in ((+), (-), (*), (^)) - A = broadcast(op, a, a) - @test A.data == broadcast(op, a.data, a.data) && A.type == a.type && A.dims == a.dims - - A = broadcast(op, 2.1, a) - @test A.data == broadcast(op, 2.1, a.data) && A.type == a.type && A.dims == a.dims - - A = broadcast(op, a, 2.1) - @test A.data == broadcast(op, a.data, 2.1) && A.type == a.type && A.dims == a.dims - end - - # tidyup tests - ρ1 = rand_dm(20) - ρ2 = dense_to_sparse(ρ1) - @test tidyup!(ρ2, 0.1) == ρ2 != ρ1 - @test dense_to_sparse(tidyup!(ρ1, 0.1)) == ρ2 - - ρ1 = rand_dm(20) - ρ2 = dense_to_sparse(ρ1) - @test tidyup(ρ2, 0.1) != ρ2 - @test dense_to_sparse(tidyup(ρ1, 0.1)) == tidyup(ρ2, 0.1) -end - -@testset "Time Evolution and partial trace" begin - N = 10 - - a_d = kron(create(N), qeye(2)) - a = a_d' - sm = kron(qeye(N), sigmam()) - sp = sm' - sx = kron(qeye(N), sigmax()) - sy = tensor(qeye(N), sigmay()) - sz = qeye(N) ⊗ sigmaz() - η = 0.01 - H = a_d * a + 0.5 * sz - 1im * η * (a - a_d) * sx - psi0 = kron(fock(N, 0), fock(2, 0)) - t_l = LinRange(0, 1000, 1000) - e_ops = [a_d * a] - # sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=LinearExponential(krylov=:adaptive, m=15), progress=false) - # @test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 - sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=Vern7(), progress=false) - @test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 - - a = destroy(N) - a_d = a' - H = a_d * a - c_ops = [sqrt(0.1) * a] - e_ops = [a_d * a] - psi0 = basis(N, 3) - t_l = LinRange(0, 100, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, alg=Vern7(), progress=false) - sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=e_ops, progress=false) - @test sum(abs.(sol_mc.expect .- sol_me.expect)) / length(t_l) < 0.1 - - sp1 = kron(sigmap(), qeye(2)) - sm1 = sp1' - sx1 = sm1 + sp1 - sy1 = 1im * (sm1 - sp1) - sz1 = sp1 * sm1 - sm1 * sp1 - sp2 = kron(qeye(2), sigmap()) - sm2 = sp2' - sx2 = sm2 + sp2 - sy2 = 1im * (sm2 - sp2) - sz2 = sp2 * sm2 - sm2 * sp2 - ωq1, ωq2 = 1, 1 - γ1, γ2 = 0.05, 0.1 - H = 0.5 * ωq1 * sz1 + 0.5 * ωq2 * sz2 - c_ops = [sqrt(γ1) * sm1, sqrt(γ2) * sm2] - psi0_1 = normalize(fock(2, 0) + fock(2, 1)) - psi0_2 = normalize(fock(2, 0) + fock(2, 1)) - psi0 = kron(psi0_1, psi0_2) - t_l = LinRange(0, 20 / γ1, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=[sp1 * sm1, sp2 * sm2], progress=false) - sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=[sp1 * sm1, sp2 * sm2], progress=false) - @test sum(abs.(sol_mc.expect[1:2, :] .- sol_me.expect[1:2, :])) / length(t_l) < 0.1 - @test expect(sp1 * sm1, sol_me.states[end]) ≈ expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) -end - -@testset "Dynamical Fock Dimension mesolve" begin - ### DYNAMICAL FOCK DIMENSION ### - F, Δ, κ = 5, 0.25, 1 - t_l = range(0, 15, length=100) - - N0 = 140 - a0 = destroy(N0) - H0 = Δ * a0' * a0 + F * (a0 + a0') - c_ops0 = [√κ * a0] - e_ops0 = [a0' * a0] - ψ00 = fock(N0, 0) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) - - function H_dfd0(dims, p) - Δ = p.Δ - F = p.F - a = destroy(dims[1]) - Δ * a' * a + F * (a + a') - end - function c_ops_dfd0(dims, p) - κ = p.κ - a = destroy(dims[1]) - [√κ * a] - end - function e_ops_dfd0(dims, p) - a = destroy(dims[1]) - [a' * a] - end - maxdims = [150] - ψ0 = fock(3, 0) - dfd_params = (Δ=Δ, F=F, κ=κ) - sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops=e_ops_dfd0, progress=false); - - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 - - ###################### - - F = 0 - H0 = Δ * a0' * a0 + F * (a0 + a0') - c_ops0 = [√κ * a0] - e_ops0 = [a0' * a0] - ψ00 = fock(N0, 50) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) - - function H_dfd1(dims, p) - Δ = p.Δ - F = p.F - a = destroy(dims[1]) - Δ * a' * a + F * (a + a') - end - function c_ops_dfd1(dims, p) - κ = p.κ - a = destroy(dims[1]) - [√κ * a] - end - function e_ops_dfd1(dims, p) - a = destroy(dims[1]) - [a' * a] - end - maxdims = [150] - ψ0 = fock(70, 50) - dfd_params = (Δ=Δ, F=F, κ=κ) - sol = dfd_mesolve(H_dfd1, ψ0, t_l, c_ops_dfd1, maxdims, dfd_params, e_ops=e_ops_dfd1, progress=false) - - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 - - - ###################### - - F, Δ, κ, J = 1.5, 0.25, 1, 0.05 - N0 = 25 - N1 = 20 - a0 = kron(destroy(N0), qeye(N1)) - a1 = kron(qeye(N0), destroy(N1)) - H0 = Δ * a0' * a0 + F * (a0 + a0') + Δ * a1' * a1 + J * (a0' * a1 + a0 * a1') - c_ops0 = [√κ * a0, √κ * a1] - e_ops0 = [a0' * a0, a1' * a1] - ψ00 = kron(fock(N0, 0), fock(N1, 15)) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress=false) - - function H_dfd2(dims, p) - Δ = p.Δ - F = p.F - J = p.J - a = kron(destroy(dims[1]), qeye(dims[2])) - b = kron(qeye(dims[1]), destroy(dims[2])) - Δ * a' * a + F * (a + a') + Δ * b' * b + J * (a' * b + a * b') - end - function c_ops_dfd2(dims, p) - κ = p.κ - a = kron(destroy(dims[1]), qeye(dims[2])) - b = kron(qeye(dims[1]), destroy(dims[2])) - [√κ * a, √κ * b] - end - function e_ops_dfd2(dims, p) - a = kron(destroy(dims[1]), qeye(dims[2])) - b = kron(qeye(dims[1]), destroy(dims[2])) - [a' * a, b' * b] - end - maxdims = [50, 50] - ψ0 = kron(fock(3, 0), fock(20, 15)) - dfd_params = (Δ=Δ, F=F, κ=κ, J=J) - sol = dfd_mesolve(H_dfd2, ψ0, t_l, c_ops_dfd2, maxdims, dfd_params, e_ops=e_ops_dfd2, progress=false) - - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) + - sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 -end - -@testset "Dynamical Shifted Fock" begin - F = 3 - Δ = 0.25 - κ = 1 - U = 0.01 - - tlist = LinRange(0,25,300) - - # Single cavity case - N0 = 100 - a0 = destroy(N0) - H0 = Δ*a0'*a0 + F*(a0+a0') + U * a0'^2 * a0^2 - c_ops0 = [√(κ)*a0] - - α0 = 1.5 - ρ0 = coherent(N0, α0) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a0'*a0, a0], progress=false) - - N = 5 - a = destroy(N) - function H_dsf(op_list, p) - Δ = p.Δ - F = p.F - U = p.U - a = op_list[1] - Δ*a'*a + F*(a + a') + U * a'^2 * a^2 - end - function c_ops_dsf(op_list, p) - κ = p.κ - a = op_list[1] - [√κ * a] - end - function e_ops_dsf(op_list, p) - a = op_list[1] - [a' * a, a] - end - op_list = [a] - ψ0 = fock(N, 0) - α0_l = [α0] - dsf_params = (Δ=Δ, F=F, κ=κ, U=U) - - sol_dsf_me = dsf_mesolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress=false) - sol_dsf_mc = dsf_mcsolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress=false, n_traj=500) - val_ss = abs2(sol0.expect[1,end]) - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.1 - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.1 - - # Two cavities case - F = 2 - Δ = 0.25 - κ = 1 - U = 0.01 - J = 0.5 - tlist = LinRange(0,15,300) - - N0 = 20 - a10 = kron(destroy(N0), qeye(N0)) - a20 = kron(qeye(N0), destroy(N0)) - H0 = Δ*a10'*a10 + Δ*a20'*a20 + U*a10'^2*a10^2 + U*a20'^2*a20^2 + F*(a10+a10') + J*(a10'*a20 + a10*a20') - c_ops0 = [√κ*a10, √κ*a20] - - ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a10'*a10, a20'*a20], progress=false) - - N = 5 - a1 = kron(destroy(N), qeye(N)) - a2 = kron(qeye(N), destroy(N)) - function H_dsf2(op_list, p) - Δ = p.Δ - F = p.F - U = p.U - J = p.J - a1, a2 = op_list - Δ*a1'*a1 + Δ*a2'*a2 + U*a1'^2*a1^2 + U*a2'^2*a2^2 + F*(a1 + a1') + J*(a1'*a2 + a1*a2') - end - function c_ops_dsf2(op_list, p) - κ = p.κ - a1, a2 = op_list - [√κ * a1, √κ * a2] - end - function e_ops_dsf2(op_list, p) - a1, a2 = op_list - [a1' * a1, a2' * a2] - end - op_list = [a1, a2] - ψ0 = kron(fock(N, 0), fock(N, 0)) - α0_l = [α0, α0] - dsf_params = (Δ=Δ, F=F, κ=κ, U=U, J=J) - - sol_dsf_me = dsf_mesolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress=false) - sol_dsf_mc = dsf_mcsolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress=false, n_traj=500) - - val_ss = abs2(sol0.expect[1,end]) - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2,:] .- sol_dsf_me.expect[2,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2,:] .- sol_dsf_mc.expect[2,:])) / (val_ss * length(tlist)) < 0.6 -end - -@testset "Generalized Master Equation" begin - N_c = 30 - N_trunc = 10 - tol=1e-14 - - a = kron(destroy(N_c), qeye(2)) - sm = kron(qeye(N_c), sigmam()) - sp = sm' - sx = sm + sp - sz = sp * sm - sm * sp - - H = 1 * a' * a + 1 * sz / 2 + 0.5 * (a + a') * sx - - fields = [sqrt(0.01) * (a + a'), sqrt(0.01) * sx] - Tlist = [0, 0.0] - - E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) - Ω = dense_to_sparse((E' .- E)[1:N_trunc,1:N_trunc], tol) - - H_d = Qobj(dense_to_sparse((U' * H * U)[1:N_trunc,1:N_trunc], tol)) - Xp = Qobj( Ω .* dense_to_sparse(triu((U' * (a + a') * U).data[1:N_trunc,1:N_trunc], 1), tol)) - a2 = Qobj( dense_to_sparse((U' * a * U).data[1:N_trunc,1:N_trunc], tol)) - sm2 = Qobj( dense_to_sparse((U' * sm * U).data[1:N_trunc,1:N_trunc], tol)) - - # Standard liouvillian case - c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] - L2 = liouvillian(H_d, c_ops) - - @test (expect(Xp'*Xp, steadystate(L1)) < 1e-10 && expect(Xp'*Xp, steadystate(L2)) > 1e-3) - - H = 1 * a' * a + 1 * sz / 2 + 1e-5 * (a * sp + a' * sm) - - Tlist = [0.2, 0.0] - - E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) - Ω = dense_to_sparse((E' .- E)[1:N_trunc,1:N_trunc], tol) - - H_d = Qobj(dense_to_sparse((U' * H * U)[1:N_trunc,1:N_trunc], tol)) - Xp = Qobj( Ω .* dense_to_sparse(triu((U' * (a + a') * U).data[1:N_trunc,1:N_trunc], 1), tol)) - a2 = Qobj( dense_to_sparse((U' * a * U).data[1:N_trunc,1:N_trunc], tol)) - sm2 = Qobj( dense_to_sparse((U' * sm * U).data[1:N_trunc,1:N_trunc], tol)) - - @test abs(expect(Xp'*Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 -end - -@testset "Eigenvalues and Operators" begin - N = 30 - a = kron(destroy(N), qeye(2)) - a_d = a' - - sm = kron(qeye(N), sigmam()) - sp = sm' - sx = kron(qeye(N), sigmax()) - sy = kron(qeye(N), sigmay()) - sz = kron(qeye(N), sigmaz()) - - η = 0.2 - H_d = a_d * a + 0.5 * sz - 1im * η * (a - a_d) * sx + η^2 - H_c = a_d * a + 0.5 * (sz * cosm(2 * η * (a + a_d)) + sy * sinm(2 * η * (a + a_d))) - - vals_d, vecs_d = eigen(H_d) - vals_c, vecs_c = eigen((H_c)) - vals2, vecs2 = eigsolve(H_d, sigma=-0.9, k=10, krylovdim=30) - sort!(vals_c, by=real) - sort!(vals2, by=real) - - @test sum(real.(vals_d[1:20]) .- real.(vals_c[1:20])) / 20 < 1e-3 - @test sum(real.(vals_d[1:10]) .- real.(vals2[1:10])) / 20 < 1e-3 - - - N = 5 - a = kron(destroy(N), qeye(N)) - a_d = a' - b = kron(qeye(N), destroy(N)) - b_d = b' - - ωc = 1 - ωb = 1 - g = 0.01 - κ = 0.1 - n_th = 0.01 - - H = ωc * a_d * a + ωb * b_d * b + g * (a + a_d) * (b + b_d) - c_ops = [√((1+n_th)*κ) * a, √κ * b, √(n_th*κ) * a_d] - L = liouvillian(H, c_ops).data - - vals, vecs = eigsolve(L, sigma=0.01, k=10, krylovdim=50) - vals2, vecs2 = eigen(sparse_to_dense(L)) - vals3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1\(40*κ), k=10, krylovdim=50) - idxs = sortperm(vals2, by=abs) - vals2 = vals2[idxs][1:10] - vecs2 = vecs2[:, idxs][:, 1:10] - - @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) - @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs2[:, 1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs3[:, 1]), atol=1e-5) -end - -@testset "Steadystate" begin - N = 10 - - a = destroy(N) - a_d = a' - H = a_d * a + 0.1 * (a + a_d) - c_ops = [sqrt(0.1) * a] - e_ops = [a_d * a] - psi0 = fock(N, 3) - t_l = LinRange(0, 200, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, progress=false) - ρ_ss = steadystate(H, c_ops) - @test abs(sol_me.expect[1, end] - expect(e_ops[1], ρ_ss)) < 1e-3 - - H = a_d * a - H_t = 0.1 * (a + a_d) - c_ops = [sqrt(0.1) * a] - e_ops = [a_d * a] - psi0 = fock(N, 3) - t_l = LinRange(0, 200, 1000) - H_t_f = TimeDependentOperatorSum([(t,p) -> sin(t)], [liouvillian(H_t)]) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, H_t=H_t_f, alg=Vern7(), progress=false) - ρ_ss = steadystate_floquet(H, c_ops, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1) - @test abs(sum(sol_me.expect[1, end-100:end]) / 101 - expect(e_ops[1], ρ_ss)) < 1e-2 -end - -@testset "Entanglement" begin - g = fock(2, 1) - e = fock(2, 0) - state = normalize(kron(g, e) + kron(e, g)) - rho = state * state' - @test entanglement(state, 1) / log(2) ≈ 1 -end - -@testset "Negativity and Partial Transpose" begin - # tests for negativity - rho = (1 / 40) * Qobj([ - 15 1 1 15; - 1 5 -3 1; - 1 -3 5 1; - 15 1 1 15]; - dims = [2, 2] - ) - Neg = negativity(rho, 1) - @test Neg ≈ 0.25 - @test negativity(rho, 2) ≈ Neg - @test negativity(rho, 1; logarithmic=true) ≈ log2(2 * Neg + 1) - @test_throws ErrorException negativity(rho, 3) - - # tests for partial transpose (PT) - # A (24 * 24)-matrix which contains number 1 ~ 576 - A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims = [2, 3, 4]) - A_sparse = dense_to_sparse(A_dense) - PT = (true, false) - for s1 in PT - for s2 in PT - for s3 in PT - mask = [s1, s2, s3] - @test partial_transpose(A_dense, mask) == partial_transpose(A_sparse, mask) - end - end - end - @test_throws ErrorException partial_transpose(rho, [true]) -end - -@testset "Wigner" begin - α = 0.5 + 0.8im - ψ = coherent(30, α) - ρ = dense_to_sparse(ket2dm(ψ), 1e-6) - xvec = LinRange(-3, 3, 300) - yvec = LinRange(-3, 3, 300) - - wig = wigner(ψ, xvec, yvec, solver=WignerLaguerre(tol=1e-6)) - wig2 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=false)) - wig3 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=true)) - wig4 = wigner(ψ, xvec, yvec, solver=WignerClenshaw()) - - @test sqrt(sum(abs.(wig2 .- wig)) / length(wig)) < 1e-3 - @test sqrt(sum(abs.(wig3 .- wig)) / length(wig)) < 1e-3 - @test sqrt(sum(abs.(wig4 .- wig)) / length(wig)) < 1e-3 - - X, Y = meshgrid(xvec, yvec) - wig_tmp1 = gaussian.(xvec / √2, real(α), 1 / 2) - wig_tmp2 = gaussian.(yvec / √2, imag(α), 1 / 2) - wig2 = maximum(wig) * reshape(kron(wig_tmp1, wig_tmp2), 300, 300) - - @test sqrt(sum(abs.(wig2 .- wig)) / length(wig)) < 0.1 -end - -@testset "Permutation" begin - # Block Diagonal Form - N = 20 - Δ = 0 - G = 5 - tg = 0 - θ = atan(tg) - U = sin(θ) - κ2 = cos(θ) - κ1 = 0. - κϕ = 1e-3 - nth = 0. - - a = destroy(N) - ad = create(N) - H = -Δ*ad*a + G/2*(ad^2 + a^2) + U/2*(ad^2*a^2) - c_ops = [√(κ2)*a^2, √(κ1*(nth+1))*a, √(κ1*nth)*ad, √(κϕ)*ad*a] - L = liouvillian(H,c_ops) - - P, L_bd, block_sizes = bdf(L) - blocks_list, block_indices = get_bdf_blocks(L_bd, block_sizes) - @test size(L_bd) == size(L) - @test length(block_sizes) == 4 - @test length(blocks_list) == 4 - @test length(block_indices) == 4 - @test sum(block_sizes .== 100) == 4 -end - -@testset "Correlations and Spectrum" begin - a = destroy(10) - H = a' * a - c_ops = [sqrt(0.1 * (0.01 + 1)) * a, sqrt(0.1 * (0.01)) * a'] - - ω_l = range(0, 3, length=1000) - ω_l1, spec1 = spectrum(H, ω_l, a', a, c_ops, solver=FFTCorrelation(), progress=false) - ω_l2, spec2 = spectrum(H, ω_l, a', a, c_ops) - spec1 = spec1 ./ maximum(spec1) - spec2 = spec2 ./ maximum(spec2) - - test_func1 = maximum(real.(spec1)) * (0.1/2)^2 ./ ((ω_l1 .- 1).^2 .+ (0.1/2)^2) - test_func2 = maximum(real.(spec2)) * (0.1/2)^2 ./ ((ω_l2 .- 1).^2 .+ (0.1/2)^2) - idxs1 = test_func1 .> 0.05 - idxs2 = test_func2 .> 0.05 - @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < 0.01 - @test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < 0.01 -end - - -@testset "LowRankDynamics" begin - # Define lattice - Nx,Ny = 2, 3 - latt = Lattice(Nx=Nx, Ny=Ny) - N_cut = 2 - N_modes = latt.N - N = N_cut^N_modes - M = Nx*Ny+1 - - # Define initial state - ϕ = Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject}}(undef, M) - ϕ[1] = tensor(repeat([basis(2,0)],N_modes)...) - global i=1 - for j in 1:N_modes - global i+=1 - i<=M && (ϕ[i] = mb(sp, j, latt) * ϕ[1]) - end - for k in 1:N_modes-1 - for l=k+1:N_modes - global i+=1 - i<=M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1]) - end - end - for i in i+1:M - ϕ[i] = Qobj(rand(ComplexF64,size(ϕ[1])[1]), dims=ϕ[1].dims) - normalize!(ϕ[i]) - end - z = hcat(broadcast(x->x.data, ϕ)...) - B = Matrix(Diagonal([1+0im; zeros(M-1)])) - S = z'*z - B = B / tr(S*B) - ρ = Qobj(z*B*z', dims=ones(Int,N_modes)*N_cut) - - # Define Hamiltonian and collapse operators - Jx = 0.9 - Jy = 1.02 - Jz = 1. - hx = 0. - γ = 1 - Sz = sum([mb(sz, i, latt) for i in 1:latt.N]) - tl = LinRange(0,10,100) - - H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc=pbc, order=1) - e_ops = (Sz,) - - # Full solution - mesol = mesolve(H, ρ, tl, c_ops; e_ops=[e_ops...]); - A = Matrix(mesol.states[end].data) - λ = eigvals(Hermitian(A)) - Strue = -sum(λ.*log2.(λ)) - - # Low rank solution - function f_entropy(p,z,B) - C = p.A0 - σ = p.Bi - mul!(C, z, sqrt(B)) - mul!(σ, C', C) - λ = eigvals(Hermitian(σ)) - λ = λ[λ.>1e-10] - return -sum(λ .* log2.(λ)) - end - - opt = LRMesolveOptions( - alg = Tsit5(), - err_max = 1e-3, - p0 = 0., - atol_inv = 1e-6, - adj_condition="variational", - Δt = 0.2, ) - lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops=e_ops, f_ops=(f_entropy,), opt=opt) - - # Test - m_me = real(mesol.expect[1,:]) - m_lr = real(lrsol.expvals[1,:]) - @test all(abs.((m_me .- m_lr)./m_me).<0.1) - - S_lr = real(lrsol.funvals[1,end]) - @test abs((S_lr - Strue)/Strue) < 0.5 -end \ No newline at end of file +using SafeTestsets + +@time @safetestset "QuantumObjects" include("quantum_objects.jl") +@time @safetestset "Time Evolution and partial trace" include("time_evolution_and_partial_trace.jl") +@time @safetestset "Dynamical Fock Dimension mesolve" include("dynamical_fock_dimension_mesolve.jl") +@time @safetestset "Dynamical Shifted Fock" include("dynamical-shifted-fock.jl") +@time @safetestset "Generalized Master Equation" include("generalized_master_equation.jl") +@time @safetestset "Eigenvalues and Operators" include("eigenvalues_and_operators.jl") +@time @safetestset "Steady State" include("steady_state.jl") +@time @safetestset "Entanglement" include("entanglement.jl") +@time @safetestset "Negativity and Partial Transpose" include("negativity_and_partial_transpose.jl") +@time @safetestset "Wigner" include("Wigner.jl") +@time @safetestset "Permutation" include("permutation.jl") +@time @safetestset "Correlations and Spectrum" include("correlations_and_spectrum.jl") +@time @safetestset "LowRankDynamics" include("low_rank_dynamics.jl") \ No newline at end of file diff --git a/test/steady_state.jl b/test/steady_state.jl new file mode 100644 index 00000000..c4ce6d39 --- /dev/null +++ b/test/steady_state.jl @@ -0,0 +1,24 @@ +using QuantumToolbox + +N = 10 +a = destroy(N) +a_d = a' +H = a_d * a + 0.1 * (a + a_d) +c_ops = [sqrt(0.1) * a] +e_ops = [a_d * a] +psi0 = fock(N, 3) +t_l = LinRange(0, 200, 1000) +sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, progress=false) +ρ_ss = steadystate(H, c_ops) +@test abs(sol_me.expect[1, end] - expect(e_ops[1], ρ_ss)) < 1e-3 + +H = a_d * a +H_t = 0.1 * (a + a_d) +c_ops = [sqrt(0.1) * a] +e_ops = [a_d * a] +psi0 = fock(N, 3) +t_l = LinRange(0, 200, 1000) +H_t_f = TimeDependentOperatorSum([(t,p) -> sin(t)], [liouvillian(H_t)]) +sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, H_t=H_t_f, alg=Vern7(), progress=false) +ρ_ss = steadystate_floquet(H, c_ops, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1) +@test abs(sum(sol_me.expect[1, end-100:end]) / 101 - expect(e_ops[1], ρ_ss)) < 1e-2 \ No newline at end of file diff --git a/test/time_evolution_and_partial_trace.jl b/test/time_evolution_and_partial_trace.jl new file mode 100644 index 00000000..c00d5fdf --- /dev/null +++ b/test/time_evolution_and_partial_trace.jl @@ -0,0 +1,51 @@ +using QuantumToolbox + +N = 10 +a_d = kron(create(N), qeye(2)) +a = a_d' +sx = kron(qeye(N), sigmax()) +sy = tensor(qeye(N), sigmay()) +sz = qeye(N) ⊗ sigmaz() +η = 0.01 +H = a_d * a + 0.5 * sz - 1im * η * (a - a_d) * sx +psi0 = kron(fock(N, 0), fock(2, 0)) +t_l = LinRange(0, 1000, 1000) +e_ops = [a_d * a] +# sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=LinearExponential(krylov=:adaptive, m=15), progress=false) +# @test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 +sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=Vern7(), progress=false) +@test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 + +a = destroy(N) +a_d = a' +H = a_d * a +c_ops = [sqrt(0.1) * a] +e_ops = [a_d * a] +psi0 = basis(N, 3) +t_l = LinRange(0, 100, 1000) +sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, alg=Vern7(), progress=false) +sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=e_ops, progress=false) +@test sum(abs.(sol_mc.expect .- sol_me.expect)) / length(t_l) < 0.1 + +sp1 = kron(sigmap(), qeye(2)) +sm1 = sp1' +sx1 = sm1 + sp1 +sy1 = 1im * (sm1 - sp1) +sz1 = sp1 * sm1 - sm1 * sp1 +sp2 = kron(qeye(2), sigmap()) +sm2 = sp2' +sx2 = sm2 + sp2 +sy2 = 1im * (sm2 - sp2) +sz2 = sp2 * sm2 - sm2 * sp2 +ωq1, ωq2 = 1, 1 +γ1, γ2 = 0.05, 0.1 +H = 0.5 * ωq1 * sz1 + 0.5 * ωq2 * sz2 +c_ops = [sqrt(γ1) * sm1, sqrt(γ2) * sm2] +psi0_1 = normalize(fock(2, 0) + fock(2, 1)) +psi0_2 = normalize(fock(2, 0) + fock(2, 1)) +psi0 = kron(psi0_1, psi0_2) +t_l = LinRange(0, 20 / γ1, 1000) +sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=[sp1 * sm1, sp2 * sm2], progress=false) +sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=[sp1 * sm1, sp2 * sm2], progress=false) +@test sum(abs.(sol_mc.expect[1:2, :] .- sol_me.expect[1:2, :])) / length(t_l) < 0.1 +@test expect(sp1 * sm1, sol_me.states[end]) ≈ expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) \ No newline at end of file diff --git a/test/wigner.jl b/test/wigner.jl new file mode 100644 index 00000000..f2414c0f --- /dev/null +++ b/test/wigner.jl @@ -0,0 +1,23 @@ +using QuantumToolbox + +α = 0.5 + 0.8im +ψ = coherent(30, α) +ρ = dense_to_sparse(ket2dm(ψ), 1e-6) +xvec = LinRange(-3, 3, 300) +yvec = LinRange(-3, 3, 300) + +wig = wigner(ψ, xvec, yvec, solver=WignerLaguerre(tol=1e-6)) +wig2 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=false)) +wig3 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=true)) +wig4 = wigner(ψ, xvec, yvec, solver=WignerClenshaw()) + +@test sqrt(sum(abs.(wig2 .- wig)) / length(wig)) < 1e-3 +@test sqrt(sum(abs.(wig3 .- wig)) / length(wig)) < 1e-3 +@test sqrt(sum(abs.(wig4 .- wig)) / length(wig)) < 1e-3 + +X, Y = meshgrid(xvec, yvec) +wig_tmp1 = gaussian.(xvec / √2, real(α), 1 / 2) +wig_tmp2 = gaussian.(yvec / √2, imag(α), 1 / 2) +wig2 = maximum(wig) * reshape(kron(wig_tmp1, wig_tmp2), 300, 300) + +@test sqrt(sum(abs.(wig2 .- wig)) / length(wig)) < 0.1 \ No newline at end of file From 106cc627806631d290cdb1d8e3924786b0bd4b50 Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Thu, 28 Mar 2024 23:44:36 +0900 Subject: [PATCH 2/5] improve CI --- .github/workflows/CI.yml | 54 ++++++++++++----------------- .github/workflows/documentation.yml | 38 ++++++++++++++++++++ test/runtests.jl | 30 +++++++++------- 3 files changed, 78 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/documentation.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a1ea6c49..973e1309 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,19 +1,23 @@ -name: CI +name: Runtests + on: push: branches: - - main - tags: ['*'] + - 'main' pull_request: -concurrency: - # Skip intermediate builds: always. - # Cancel intermediate builds: only if it is a pull request build. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + branches: + - 'main' + types: + - opened + - reopened + - synchronize + - ready_for_review + jobs: test: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} ( ${{ matrix.group }} ) runs-on: ${{ matrix.os }} + if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false matrix: @@ -23,10 +27,14 @@ jobs: - '1.10' os: - ubuntu-latest + - macOS-latest + - windows-latest arch: - x64 + group: + - Core steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} @@ -34,27 +42,11 @@ jobs: - uses: julia-actions/cache@v1 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 + env: + GROUP: ${{ matrix.group }} - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v2 with: - files: lcov.info - docs: - name: Documentation - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + directories: src, ext + - uses: codecov/codecov-action@v4 with: - version: '1' - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-docdeploy@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: | - julia --project=docs -e ' - using Documenter: DocMeta, doctest - using QuantumToolbox - DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, :(using QuantumToolbox); recursive=true) - doctest(QuantumToolbox)' + verbose: true \ No newline at end of file diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..7e28aa7a --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,38 @@ +name: Documentation + +on: + push: + branches: + - 'main' + tags: + - '*' + pull_request: + branches: + - 'main' + types: + - opened + - reopened + - synchronize + - ready_for_review + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + if: ${{ !github.event.pull_request.draft }} + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v1 + with: + version: '1' + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: | + julia --project=docs -e ' + using Documenter: DocMeta, doctest + using QuantumToolbox + DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, :(using QuantumToolbox); recursive=true) + doctest(QuantumToolbox)' diff --git a/test/runtests.jl b/test/runtests.jl index adbfa363..1f207c13 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,15 +1,19 @@ using SafeTestsets -@time @safetestset "QuantumObjects" include("quantum_objects.jl") -@time @safetestset "Time Evolution and partial trace" include("time_evolution_and_partial_trace.jl") -@time @safetestset "Dynamical Fock Dimension mesolve" include("dynamical_fock_dimension_mesolve.jl") -@time @safetestset "Dynamical Shifted Fock" include("dynamical-shifted-fock.jl") -@time @safetestset "Generalized Master Equation" include("generalized_master_equation.jl") -@time @safetestset "Eigenvalues and Operators" include("eigenvalues_and_operators.jl") -@time @safetestset "Steady State" include("steady_state.jl") -@time @safetestset "Entanglement" include("entanglement.jl") -@time @safetestset "Negativity and Partial Transpose" include("negativity_and_partial_transpose.jl") -@time @safetestset "Wigner" include("Wigner.jl") -@time @safetestset "Permutation" include("permutation.jl") -@time @safetestset "Correlations and Spectrum" include("correlations_and_spectrum.jl") -@time @safetestset "LowRankDynamics" include("low_rank_dynamics.jl") \ No newline at end of file +const GROUP = get(ENV, "GROUP", "All") + +if (GROUP == "All") || (GROUP == "Core") + @time @safetestset "QuantumObjects" include("quantum_objects.jl") + @time @safetestset "Time Evolution and partial trace" include("time_evolution_and_partial_trace.jl") + @time @safetestset "Dynamical Fock Dimension mesolve" include("dynamical_fock_dimension_mesolve.jl") + @time @safetestset "Dynamical Shifted Fock" include("dynamical-shifted-fock.jl") + @time @safetestset "Generalized Master Equation" include("generalized_master_equation.jl") + @time @safetestset "Eigenvalues and Operators" include("eigenvalues_and_operators.jl") + @time @safetestset "Steady State" include("steady_state.jl") + @time @safetestset "Entanglement" include("entanglement.jl") + @time @safetestset "Negativity and Partial Transpose" include("negativity_and_partial_transpose.jl") + @time @safetestset "Wigner" include("Wigner.jl") + @time @safetestset "Permutation" include("permutation.jl") + @time @safetestset "Correlations and Spectrum" include("correlations_and_spectrum.jl") + @time @safetestset "LowRankDynamics" include("low_rank_dynamics.jl") +end \ No newline at end of file From 8a02b2fc309b7ef8c207702abf630f371bcbbc34 Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Fri, 29 Mar 2024 00:17:52 +0900 Subject: [PATCH 3/5] fix typo in runtests --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 1f207c13..ae268981 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,7 +12,7 @@ if (GROUP == "All") || (GROUP == "Core") @time @safetestset "Steady State" include("steady_state.jl") @time @safetestset "Entanglement" include("entanglement.jl") @time @safetestset "Negativity and Partial Transpose" include("negativity_and_partial_transpose.jl") - @time @safetestset "Wigner" include("Wigner.jl") + @time @safetestset "Wigner" include("wigner.jl") @time @safetestset "Permutation" include("permutation.jl") @time @safetestset "Correlations and Spectrum" include("correlations_and_spectrum.jl") @time @safetestset "LowRankDynamics" include("low_rank_dynamics.jl") From 4521f43b29f7ec76b8d670a8e3b5d49850e2055f Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Fri, 29 Mar 2024 00:31:52 +0900 Subject: [PATCH 4/5] fix runtests CI --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 973e1309..1f366162 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -46,7 +46,7 @@ jobs: GROUP: ${{ matrix.group }} - uses: julia-actions/julia-processcoverage@v1 with: - directories: src, ext + directories: src - uses: codecov/codecov-action@v4 with: verbose: true \ No newline at end of file From 93687f877a5f478306939f9381dc905bc1f2c6a9 Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Fri, 29 Mar 2024 00:45:26 +0900 Subject: [PATCH 5/5] optimize runtests CI --- .github/workflows/CI.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1f366162..bf12b40b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -17,6 +17,9 @@ jobs: test: name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} ( ${{ matrix.group }} ) runs-on: ${{ matrix.os }} + permissions: # needed to allow julia-actions/cache to delete old caches that it has created + actions: write + contents: read if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false @@ -49,4 +52,6 @@ jobs: directories: src - uses: codecov/codecov-action@v4 with: - verbose: true \ No newline at end of file + verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file