using NamedTrajectories
using PiccoloQuantumObjects
using QuantumCollocation

Quantum State Smooth Pulse Problem

QuantumCollocation.ProblemTemplates.QuantumStateSmoothPulseProblemFunction
QuantumStateSmoothPulseProblem(system, ψ_inits, ψ_goals, T, Δt; kwargs...)
QuantumStateSmoothPulseProblem(system, ψ_init, ψ_goal, T, Δt; kwargs...)
QuantumStateSmoothPulseProblem(H_drift, H_drives, args...; kwargs...)

Create a quantum state smooth pulse problem. The goal is to find a control pulse a(t) that drives all of the initial states ψ_inits to the corresponding target states ψ_goals using T timesteps of size Δt. This problem also controls the first and second derivatives of the control pulse, da(t) and dda(t), to ensure smoothness.

Arguments

  • system::AbstractQuantumSystem: The quantum system.

or

  • H_drift::AbstractMatrix{<:Number}: The drift Hamiltonian.
  • H_drives::Vector{<:AbstractMatrix{<:Number}}: The control Hamiltonians.

with

  • ψ_inits::Vector{<:AbstractVector{<:ComplexF64}}: The initial states.
  • ψ_goals::Vector{<:AbstractVector{<:ComplexF64}}: The target states.

or

  • ψ_init::AbstractVector{<:ComplexF64}: The initial state.
  • ψ_goal::AbstractVector{<:ComplexF64}: The target state.

with

  • T::Int: The number of timesteps.
  • Δt::Float64: The timestep size.

Keyword Arguments

  • state_name::Symbol=:ψ̃: The name of the state variable.
  • control_name::Symbol=:a: The name of the control variable.
  • timestep_name::Symbol=:Δt: The name of the timestep variable.
  • init_trajectory::Union{NamedTrajectory, Nothing}=nothing: The initial trajectory.
  • a_bound::Float64=1.0: The bound on the control pulse.
  • a_bounds::Vector{Float64}=fill(a_bound, length(system.G_drives)): The bounds on the control pulse.
  • a_guess::Union{Matrix{Float64}, Nothing}=nothing: The initial guess for the control pulse.
  • da_bound::Float64=Inf: The bound on the first derivative of the control pulse.
  • da_bounds::Vector{Float64}=fill(da_bound, length(system.G_drives)): The bounds on the first derivative of the control pulse.
  • dda_bound::Float64=1.0: The bound on the second derivative of the control pulse.
  • dda_bounds::Vector{Float64}=fill(dda_bound, length(system.G_drives)): The bounds on the second derivative of the control pulse.
  • Δt_min::Float64=0.5 * Δt: The minimum timestep size.
  • Δt_max::Float64=1.5 * Δt: The maximum timestep size.
  • drive_derivative_σ::Float64=0.01: The standard deviation of the drive derivative random initialization.
  • Q::Float64=100.0: The weight on the state objective.
  • R=1e-2: The weight on the control pulse and its derivatives.
  • R_a::Union{Float64, Vector{Float64}}=R: The weight on the control pulse.
  • R_da::Union{Float64, Vector{Float64}}=R: The weight on the first derivative of the control pulse.
  • R_dda::Union{Float64, Vector{Float64}}=R: The weight on the second derivative of the control pulse.
  • constraints::Vector{<:AbstractConstraint}=AbstractConstraint[]: The constraints.
  • piccolo_options::PiccoloOptions=PiccoloOptions(): The Piccolo options.
source

Each problem starts with a QuantumSystem object, which is used to define the system's Hamiltonian and control operators. The goal is to find a control pulse that drives the intial state, ψ_init, to a target state, ψ_goal.

define the quantum system

system = QuantumSystem(0.1 * PAULIS.Z, [PAULIS.X, PAULIS.Y])
ψ_init = Vector{ComplexF64}([1.0, 0.0])
ψ_goal = Vector{ComplexF64}([0.0, 1.0])
T = 51
Δt = 0.2
0.2

create the smooth pulse problem

state_prob = QuantumStateSmoothPulseProblem(system, ψ_init, ψ_goal, T, Δt);
    constructing QuantumStateSmoothPulseProblem...
	using integrator: typeof(KetIntegrator)
	using 1 initial state(s)
	applying timesteps_all_equal constraint: Δt

check the fidelity before solving

println("Before: ", rollout_fidelity(state_prob.trajectory, system))
Before: 0.7490901970252036

solve the problem

solve!(state_prob, max_iter=100, verbose=true, print_level=1);
    initializing optimizer...
        applying constraint: timesteps all equal constraint
        applying constraint: initial value of ψ̃
        applying constraint: initial value of a
        applying constraint: initial value of da
        applying constraint: final value of a
        applying constraint: final value of da
        applying constraint: bounds on a
        applying constraint: bounds on da
        applying constraint: bounds on dda
        applying constraint: bounds on Δt

******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit https://github.com/coin-or/Ipopt
******************************************************************************

check the fidelity after solving

println("After: ", rollout_fidelity(state_prob.trajectory, system))
After: 0.9998330589147368

extract the control pulses

state_prob.trajectory.a |> size
(2, 51)

Quantum State Minimum Time Problem

QuantumCollocation.ProblemTemplates.QuantumStateMinimumTimeProblemFunction
QuantumStateMinimumTimeProblem(traj, sys, obj, integrators, constraints; kwargs...)
QuantumStateMinimumTimeProblem(prob; kwargs...)

Construct a DirectTrajOptProblem for the minimum time problem of reaching a target state.

Keyword Arguments

  • state_name::Symbol=:ψ̃: The symbol for the state variables.
  • final_fidelity::Union{Real, Nothing}=nothing: The final fidelity.
  • D=1.0: The cost weight on the time.
  • piccolo_options::PiccoloOptions=PiccoloOptions(): The Piccolo options.
source

create the minimum time problem

min_state_prob = QuantumStateMinimumTimeProblem(state_prob, ψ_goal);
    constructing QuantumStateMinimumTimeProblem...
	final fidelity: 1.0

check the previous duration

println("Duration before: ", get_duration(state_prob.trajectory))
Duration before: 10.073668926847914

solve the minimum time problem

solve!(min_state_prob, max_iter=100, verbose=true, print_level=1);
    initializing optimizer...
        applying constraint: timesteps all equal constraint
        applying constraint: initial value of ψ̃
        applying constraint: initial value of a
        applying constraint: initial value of da
        applying constraint: final value of a
        applying constraint: final value of da
        applying constraint: bounds on a
        applying constraint: bounds on da
        applying constraint: bounds on dda
        applying constraint: bounds on Δt

check the new duration

println("Duration after: ", get_duration(min_state_prob.trajectory))
Duration after: 3.646083459509302

the fidelity is preserved by a constraint

println("Fidelity after: ", rollout_fidelity(min_state_prob.trajectory, system))
Fidelity after: 0.9999512780484473

Quantum State Sampling Problem

create a sampling problem

driftless_system = QuantumSystem([PAULIS.X, PAULIS.Y])
sampling_state_prob = QuantumStateSamplingProblem([system, driftless_system], ψ_init, ψ_goal, T, Δt);
    constructing QuantumStateSamplingProblem...
	using integrator: typeof(KetIntegrator)
	using 2 initial state(s)
	applying timesteps_all_equal constraint: Δt

new keys are added to the trajectory for the new states

println(sampling_state_prob.trajectory.state_names)
(:ψ̃1_system_1, :a, :da, :ψ̃1_system_2)

solve the sampling problem for a few iterations

solve!(sampling_state_prob, max_iter=25, verbose=true, print_level=1);
    initializing optimizer...
        applying constraint: timesteps all equal constraint
        applying constraint: initial value of ψ̃1_system_1
        applying constraint: initial value of a
        applying constraint: initial value of da
        applying constraint: initial value of ψ̃1_system_2
        applying constraint: final value of a
        applying constraint: final value of da
        applying constraint: bounds on a
        applying constraint: bounds on da
        applying constraint: bounds on dda
        applying constraint: bounds on Δt

check the fidelity of the sampling problem (use the updated key to get the initial and goal)

println("After (original system): ", rollout_fidelity(sampling_state_prob.trajectory, system, state_name=:ψ̃1_system_1))
println("After (new system): ", rollout_fidelity(sampling_state_prob.trajectory, driftless_system, state_name=:ψ̃1_system_1))
After (original system): 0.9870064823995764
After (new system): 0.9881008761597339

compare this to using the original problem on the new system

println("After (new system, original `prob`): ", rollout_fidelity(state_prob.trajectory, driftless_system))
After (new system, original `prob`): 0.7986343691645029


This page was generated using Literate.jl.