PiccoloOptions Reference

PiccoloOptions provides advanced configuration for problem templates. This page documents all available options and their effects.

using QuantumCollocation
using PiccoloQuantumObjects

Creating PiccoloOptions

Default options:

opts = PiccoloOptions()
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, false, false, 0.01, 0.01)

Custom options:

opts_custom = PiccoloOptions(
    verbose = true,
    leakage_constraint = true,
    bound_state = true
)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, true, true, 0.01, 0.01)

Pass to any problem template:

system = QuantumSystem(0.1 * PAULIS.Z, [PAULIS.X, PAULIS.Y], [1.0, 1.0])
U_goal = EmbeddedOperator(GATES.H, system)

T = 10.0
qtraj = UnitaryTrajectory(system, U_goal, T)

N = 51
prob = SmoothPulseProblem(
    qtraj, N;
    piccolo_options = opts_custom
)
QuantumControlProblem{PiccoloQuantumObjects.QuantumTrajectories.UnitaryTrajectory{PiccoloQuantumObjects.Pulses.ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}, SciMLBase.ODESolution{ComplexF64, 3, Vector{Matrix{ComplexF64}}, Nothing, Nothing, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, SciMLBase.ODEProblem{Matrix{ComplexF64}, Tuple{Float64, Float64}, true, SciMLBase.NullParameters, SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{PiccoloQuantumObjects.Rollouts.var"#update!#_construct_operator##2"{PiccoloQuantumObjects.QuantumSystems.QuantumSystem{PiccoloQuantumObjects.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, PiccoloQuantumObjects.QuantumSystems.var"#28#29"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, PiccoloQuantumObjects.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Base.Pairs{Symbol, Vector{Float64}, Nothing, @NamedTuple{tstops::Vector{Float64}, saveat::Vector{Float64}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEqLinear.MagnusGL4, OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{PiccoloQuantumObjects.Rollouts.var"#update!#_construct_operator##2"{PiccoloQuantumObjects.QuantumSystems.QuantumSystem{PiccoloQuantumObjects.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, PiccoloQuantumObjects.QuantumSystems.var"#28#29"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}}}, Val{()}}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, PiccoloQuantumObjects.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}, Vector{Matrix{ComplexF64}}, Vector{Float64}, Vector{Vector{Matrix{ComplexF64}}}, Nothing, OrdinaryDiffEqLinear.MagnusGL4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing, Nothing}, PiccoloQuantumObjects.EmbeddedOperators.EmbeddedOperator{ComplexF64}}}
  System: PiccoloQuantumObjects.QuantumSystems.QuantumSystem{PiccoloQuantumObjects.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, PiccoloQuantumObjects.QuantumSystems.var"#28#29"{Vector{SparseArrays.SparseMatrixCSC{Float64, Int64}}, Int64, SparseArrays.SparseMatrixCSC{Float64, Int64}}, @NamedTuple{}}
  Goal: PiccoloQuantumObjects.EmbeddedOperators.EmbeddedOperator{ComplexF64}
  Trajectory: 51 knots
  State: Ũ⃗
  Controls: u

General Options

verbose::Bool = false

Print detailed information during problem setup.

opts_verbose = PiccoloOptions(verbose = true)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, false, false, 0.01, 0.01)

Shows: constraint counts, objective terms, trajectory initialization details

free_time::Bool = false

Allow timesteps to vary (used internally by minimum time problems). Typically not set directly by users.

State and Unitary Options

bound_state::Bool = false

Constrain state/unitary to lie on unit sphere (for numerical stability). Recommended for difficult convergence.

opts_bounded = PiccoloOptions(bound_state = true)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, true, false, 0.01, 0.01)

Adds constraint: ||ψ||² = 1 (ket) or ||U||² = N (unitary)

geodesic::Bool = true

Use geodesic interpolation for initial trajectory.

  • true: States evolve along shortest path on manifold (better initial guess)
  • false: Linear interpolation (simpler but often worse)
opts_linear = PiccoloOptions(geodesic = false)
PiccoloOptions(true, true, ExponentialAction.expv, false, false, nothing, 1.0, false, false, 0.01, 0.01)

Control Initialization

init_trajectory::Union{NamedTrajectory, Nothing} = nothing

Provide custom initial trajectory instead of automatic initialization.

trajcustom = initializetrajectory(...) optsinit = PiccoloOptions(inittrajectory = traj_custom)

build_trajectory_constraints::Bool = true

Automatically extract constraints from trajectory bounds. Set to false if manually managing constraints.

Leakage Suppression (Multilevel Systems)

leakage_constraint::Bool = false

Add constraint to limit leakage population.

leakage_constraint_value::Float64 = 1e-3

Maximum allowed leakage: ∑ᵢ |⟨i|ψ⟩|² ≤ leakageconstraintvalue

leakage_cost::Float64 = 1.0

Penalty weight for leakage in objective (soft constraint).

opts_leakage = PiccoloOptions(
    leakage_constraint = true,
    leakage_constraint_value = 1e-2,  # 1% max leakage
    leakage_cost = 1e-1
)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, false, true, 0.01, 0.1)

Example with embedded operator: systransmon = TransmonSystem(levels=5, δ=0.2) op = EmbeddedOperator(:X, systransmon) probleakage = UnitarySmoothPulseProblem( systransmon, op, T, Δt; piccolooptions = optsleakage )

Control Constraints

complex_control_norm_constraint_name::Union{Symbol, Nothing} = nothing

Apply norm constraint to complex control amplitudes.

For systems with complex drives (e.g., rotating frame): optsnorm = PiccoloOptions( complexcontrolnormconstraintname = :u, complexcontrolnormconstraintradius = 0.2 ) Enforces: |ureal + i*u_imag| ≤ radius

complex_control_norm_constraint_radius::Float64 = 1.0

Radius for complex control norm constraint.

Timestep Options

timesteps_all_equal::Bool = false

Force all timesteps to be equal: Δt[k] = Δt[1] ∀k. Useful for hardware with fixed sampling rates.

opts_equal_dt = PiccoloOptions(timesteps_all_equal = true)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, false, false, 0.01, 0.01)

Derivative Constraints

zero_initial_and_final_derivative::Bool = false

Force derivatives to zero at boundaries: u̇[1] = u̇[T] = 0, ü[1] = ü[T] = 0. Creates "smooth ramp" pulses that start and end at zero derivative.

opts_smooth_edges = PiccoloOptions(zero_initial_and_final_derivative = true)
PiccoloOptions(true, true, ExponentialAction.expv, true, true, nothing, 1.0, false, false, 0.01, 0.01)

Common Configuration Patterns

Quick and dirty optimization

opts_quick = PiccoloOptions(
    verbose = false,
    geodesic = true
)
PiccoloOptions(false, true, ExponentialAction.expv, true, false, nothing, 1.0, false, false, 0.01, 0.01)

High-fidelity gate

opts_hifi = PiccoloOptions(
    verbose = true,
    bound_state = true,
    geodesic = true,
)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, true, false, 0.01, 0.01)

Multilevel system with leakage suppression

opts_multilevel = PiccoloOptions(
    bound_state = true,
    leakage_constraint = true,
    leakage_constraint_value = 1e-2,
    leakage_cost = 1e-1,
    verbose = true
)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, true, true, 0.01, 0.1)

Smooth pulses for hardware

opts_hardware = PiccoloOptions(
    zero_initial_and_final_derivative = true,
    timesteps_all_equal = true,
    bound_state = true
)
PiccoloOptions(true, true, ExponentialAction.expv, true, true, nothing, 1.0, true, false, 0.01, 0.01)

Robust optimization

opts_robust = PiccoloOptions(
    bound_state = true,
    geodesic = true,
    verbose = true
)
PiccoloOptions(true, true, ExponentialAction.expv, true, false, nothing, 1.0, true, false, 0.01, 0.01)

Tips and Tricks

When to use bound_state=true:

  • Optimization struggling to converge
  • Fidelity stuck below 0.99
  • Numerical instabilities in state evolution
  • Working with large Hilbert spaces

Leakage vs bounds:

  • Leakage constraint enforces hard limit (may fail to converge)
  • Leakage cost adds soft penalty (more forgiving)
  • Use both for best results

Geodesic initialization:

  • Almost always better than linear
  • Only disable for debugging or special cases
  • Particularly important for large T

Rollout integrator:

  • :pade is fast and usually sufficient
  • :exp more accurate for sensitive systems
  • Both give same result for well-conditioned problems

This page was generated using Literate.jl.