Custom Objectives
While Piccolo.jl provides standard objectives for fidelity and regularization, you may need custom objectives for specialized optimization goals. This guide shows how to create and use them.
Setup
We'll work with a simple single-qubit X gate problem:
using Piccolo
using DirectTrajOpt
using LinearAlgebra
using Random
Random.seed!(42)
# Define system
H_drift = 0.5 * PAULIS[:Z]
H_drives = [PAULIS[:X], PAULIS[:Y]]
drive_bounds = [1.0, 1.0]
sys = QuantumSystem(H_drift, H_drives, drive_bounds)
# Create initial pulse and trajectory
T = 10.0
N = 50
times = collect(range(0, T, length = N))
initial_controls = 0.1 * randn(2, N)
pulse = ZeroOrderPulse(initial_controls, times)
U_goal = GATES[:X]
qtraj = UnitaryTrajectory(sys, pulse, U_goal)UnitaryTrajectory{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{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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}, Matrix{ComplexF64}}(QuantumSystem: levels = 2, n_drives = 2, ZeroOrderPulse{DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}}(DataInterpolations.ConstantInterpolation{Matrix{Float64}, Vector{Float64}, Vector{Union{}}, Float64}([-0.03633574814517775 -0.031498797116895606 … -0.020661311448119266 -0.00404734002483549; 0.02517372155742292 -0.03112524013244207 … -0.031074387308373416 0.010477079178892111], [0.0, 0.20408163265306123, 0.40816326530612246, 0.6122448979591837, 0.8163265306122449, 1.0204081632653061, 1.2244897959183674, 1.4285714285714286, 1.6326530612244898, 1.836734693877551 … 8.16326530612245, 8.36734693877551, 8.571428571428571, 8.775510204081632, 8.979591836734693, 9.183673469387756, 9.387755102040817, 9.591836734693878, 9.795918367346939, 10.0], Union{}[], nothing, :left, DataInterpolations.ExtrapolationType.None, DataInterpolations.ExtrapolationType.None, FindFirstFunctions.Guesser{Vector{Float64}}([0.0, 0.20408163265306123, 0.40816326530612246, 0.6122448979591837, 0.8163265306122449, 1.0204081632653061, 1.2244897959183674, 1.4285714285714286, 1.6326530612244898, 1.836734693877551 … 8.16326530612245, 8.36734693877551, 8.571428571428571, 8.775510204081632, 8.979591836734693, 9.183673469387756, 9.387755102040817, 9.591836734693878, 9.795918367346939, 10.0], Base.RefValue{Int64}(50), true), false, false), 10.0, 2, :u, [0.0, 0.0], [0.0, 0.0]), ComplexF64[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], ComplexF64[0.0 + 0.0im 1.0 + 0.0im; 1.0 + 0.0im 0.0 + 0.0im], 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{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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}(Matrix{ComplexF64}[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], [0.9987404944669499 - 0.049979006477971294im -0.002516315185586171 + 0.003632049183859544im; 0.0025163151855861713 + 0.003632049183859544im 0.9987404944669498 + 0.04997900647797128im], [0.9949651505761753 - 0.09983211528555189im -0.005026291745374055 + 0.007254949195632325im; 0.005026291745374055 + 0.007254949195632325im 0.9949651505761751 + 0.09983211528555185im], [0.9887152372777896 - 0.14939534455615436im -0.0018761402879584588 + 0.01094032436868276im; 0.001876140287958457 + 0.01094032436868276im 0.9887152372777893 + 0.1493953445561543im], [0.9799746706494219 - 0.198582234919078im 0.0012787373179774988 + 0.014598139983336013im; -0.0012787373179775014 + 0.014598139983336013im 0.9799746706494215 + 0.1985822349190779im], [0.9689065695145163 - 0.2473619109215686im -0.0010428845248709336 + 0.005572877955798115im; 0.0010428845248709332 + 0.005572877955798113im 0.9689065695145159 + 0.24736191092156848im], [0.9553301582696501 - 0.2955012151880159im -0.0033618065431134034 - 0.0034668111657010824im; 0.003361806543113405 - 0.003466811165701085im 0.9553301582696498 + 0.2955012151880158im], [0.9393088601165602 - 0.34285545370350246im 0.007960833755982026 + 0.00925355597616057im; -0.007960833755982027 + 0.00925355597616057im 0.93930886011656 + 0.34285545370350234im], [0.9206677207586047 - 0.3892534286479057im 0.019261270367680737 + 0.021948113878625865im; -0.01926127036768074 + 0.02194811387862587im 0.9206677207586046 + 0.3892534286479056im], [0.8994028302467633 - 0.4351073890497396im 0.011700795934541623 + 0.04023928817622323im; -0.011700795934541616 + 0.04023928817622324im 0.8994028302467629 + 0.4351073890497394im] … [-0.162330310516659 + 0.9776863530921438im -0.09211288008898694 + 0.09640271047361523im; 0.09211288008898716 + 0.0964027104736151im -0.1623303105166594 - 0.9776863530921454im], [-0.11340823665747114 + 0.9851691121988067im -0.08375996985188089 + 0.09779907810439306im; 0.08375996985188111 + 0.09779907810439291im -0.11340823665747142 - 0.985169112198808im], [-0.06302380855624713 + 0.9886998445737325im -0.08882662794492435 + 0.10300702433754506im; 0.08882662794492457 + 0.10300702433754493im -0.06302380855624735 - 0.9886998445737339im], [-0.012475275886258899 + 0.9896561504684319im -0.09366199478776101 + 0.10794675568975075im; 0.09366199478776124 + 0.10794675568975064im -0.012475275886259036 - 0.9896561504684335im], [0.03513659061109398 + 0.9900493229410063im -0.07326064774684647 + 0.11489401914805875im; 0.07326064774684674 + 0.11489401914805865im 0.035136590611093935 - 0.990049322941008im], [0.0826524806733045 + 0.9877381520786593im -0.05265918749959422 + 0.12152744685323233im; 0.05265918749959453 + 0.12152744685323226im 0.08265248067330455 - 0.9877381520786611im], [0.130070131900829 + 0.9815639330511405im -0.036893893781669025 + 0.1351030966414246im; 0.03689389378166935 + 0.13510309664142456im 0.13007013190082917 - 0.9815639330511423im], [0.17713407075222337 + 0.9727204516340926im -0.021028270905592263 + 0.14831134742234833im; 0.021028270905592603 + 0.14831134742234828im 0.17713407075222368 - 0.9727204516340944im], [0.22528612812725657 + 0.9631491457480755im -0.011030255227385374 + 0.146520363730776im; 0.011030255227385717 + 0.14652036373077593im 0.22528612812725693 - 0.9631491457480771im], [0.2728719516934668 + 0.9511570622767048im -0.0010045161226115143 + 0.14436111598178003im; 0.0010045161226118673 + 0.14436111598177992im 0.2728719516934672 - 0.9511570622767062im]], nothing, nothing, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 … 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0], Vector{Matrix{ComplexF64}}[[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im]]], 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{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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}(SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}(MatrixOperator(2 × 2), LinearAlgebra.UniformScaling{Bool}(true), nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, SciMLBase.DEFAULT_OBSERVED, nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(Dict{Symbol, Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(:U => CartesianIndices((2, 2)), :U_2_2 => CartesianIndex(2, 2), :U_1_1 => CartesianIndex(1, 1), :U_2_1 => CartesianIndex(2, 1), :U_1_2 => CartesianIndex(1, 2)), :t, Dict{Symbol, Float64}()), nothing, nothing), ComplexF64[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], (0.0, 10.0), SciMLBase.NullParameters(), Base.Pairs(:tstops => [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 … 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0], :saveat => [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 … 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0]), SciMLBase.StandardODEProblem()), OrdinaryDiffEqLinear.MagnusGL4(false, 30, 0), OrdinaryDiffEqCore.InterpolationData{SciMLBase.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.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.ODEFunction{true, SciMLBase.FullSpecialize, SciMLOperators.MatrixOperator{ComplexF64, Matrix{ComplexF64}, SciMLOperators.FilterKwargs{Nothing, Val{()}}, SciMLOperators.FilterKwargs{Piccolo.Quantum.Rollouts.var"#update!#_construct_operator##2"{QuantumSystem{Piccolo.Quantum.QuantumSystems.var"#26#27"{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}, Vector{SparseArrays.SparseMatrixCSC{ComplexF64, Int64}}, Int64}, Piccolo.Quantum.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, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}, Nothing, Nothing}(MatrixOperator(2 × 2), LinearAlgebra.UniformScaling{Bool}(true), nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, SciMLBase.DEFAULT_OBSERVED, nothing, Piccolo.Quantum.Rollouts.PiccoloRolloutSystem{Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(Dict{Symbol, Union{Int64, AbstractVector{Int64}, CartesianIndex, CartesianIndices}}(:U => CartesianIndices((2, 2)), :U_2_2 => CartesianIndex(2, 2), :U_1_1 => CartesianIndex(1, 1), :U_2_1 => CartesianIndex(2, 1), :U_1_2 => CartesianIndex(1, 2)), :t, Dict{Symbol, Float64}()), nothing, nothing), Matrix{ComplexF64}[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im], [0.9987404944669499 - 0.049979006477971294im -0.002516315185586171 + 0.003632049183859544im; 0.0025163151855861713 + 0.003632049183859544im 0.9987404944669498 + 0.04997900647797128im], [0.9949651505761753 - 0.09983211528555189im -0.005026291745374055 + 0.007254949195632325im; 0.005026291745374055 + 0.007254949195632325im 0.9949651505761751 + 0.09983211528555185im], [0.9887152372777896 - 0.14939534455615436im -0.0018761402879584588 + 0.01094032436868276im; 0.001876140287958457 + 0.01094032436868276im 0.9887152372777893 + 0.1493953445561543im], [0.9799746706494219 - 0.198582234919078im 0.0012787373179774988 + 0.014598139983336013im; -0.0012787373179775014 + 0.014598139983336013im 0.9799746706494215 + 0.1985822349190779im], [0.9689065695145163 - 0.2473619109215686im -0.0010428845248709336 + 0.005572877955798115im; 0.0010428845248709332 + 0.005572877955798113im 0.9689065695145159 + 0.24736191092156848im], [0.9553301582696501 - 0.2955012151880159im -0.0033618065431134034 - 0.0034668111657010824im; 0.003361806543113405 - 0.003466811165701085im 0.9553301582696498 + 0.2955012151880158im], [0.9393088601165602 - 0.34285545370350246im 0.007960833755982026 + 0.00925355597616057im; -0.007960833755982027 + 0.00925355597616057im 0.93930886011656 + 0.34285545370350234im], [0.9206677207586047 - 0.3892534286479057im 0.019261270367680737 + 0.021948113878625865im; -0.01926127036768074 + 0.02194811387862587im 0.9206677207586046 + 0.3892534286479056im], [0.8994028302467633 - 0.4351073890497396im 0.011700795934541623 + 0.04023928817622323im; -0.011700795934541616 + 0.04023928817622324im 0.8994028302467629 + 0.4351073890497394im] … [-0.162330310516659 + 0.9776863530921438im -0.09211288008898694 + 0.09640271047361523im; 0.09211288008898716 + 0.0964027104736151im -0.1623303105166594 - 0.9776863530921454im], [-0.11340823665747114 + 0.9851691121988067im -0.08375996985188089 + 0.09779907810439306im; 0.08375996985188111 + 0.09779907810439291im -0.11340823665747142 - 0.985169112198808im], [-0.06302380855624713 + 0.9886998445737325im -0.08882662794492435 + 0.10300702433754506im; 0.08882662794492457 + 0.10300702433754493im -0.06302380855624735 - 0.9886998445737339im], [-0.012475275886258899 + 0.9896561504684319im -0.09366199478776101 + 0.10794675568975075im; 0.09366199478776124 + 0.10794675568975064im -0.012475275886259036 - 0.9896561504684335im], [0.03513659061109398 + 0.9900493229410063im -0.07326064774684647 + 0.11489401914805875im; 0.07326064774684674 + 0.11489401914805865im 0.035136590611093935 - 0.990049322941008im], [0.0826524806733045 + 0.9877381520786593im -0.05265918749959422 + 0.12152744685323233im; 0.05265918749959453 + 0.12152744685323226im 0.08265248067330455 - 0.9877381520786611im], [0.130070131900829 + 0.9815639330511405im -0.036893893781669025 + 0.1351030966414246im; 0.03689389378166935 + 0.13510309664142456im 0.13007013190082917 - 0.9815639330511423im], [0.17713407075222337 + 0.9727204516340926im -0.021028270905592263 + 0.14831134742234833im; 0.021028270905592603 + 0.14831134742234828im 0.17713407075222368 - 0.9727204516340944im], [0.22528612812725657 + 0.9631491457480755im -0.011030255227385374 + 0.146520363730776im; 0.011030255227385717 + 0.14652036373077593im 0.22528612812725693 - 0.9631491457480771im], [0.2728719516934668 + 0.9511570622767048im -0.0010045161226115143 + 0.14436111598178003im; 0.0010045161226118673 + 0.14436111598177992im 0.2728719516934672 - 0.9511570622767062im]], [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 … 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0], Vector{Matrix{ComplexF64}}[[[1.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 1.0 + 0.0im]]], nothing, false, OrdinaryDiffEqLinear.MagnusGL4Cache{Matrix{ComplexF64}, Matrix{ComplexF64}, Matrix{ComplexF64}, Nothing}(ComplexF64[0.2728719516934668 + 0.9511570622767048im -0.0010045161226115143 + 0.14436111598178003im; 0.0010045161226118673 + 0.14436111598177992im 0.2728719516934672 - 0.9511570622767062im], ComplexF64[0.22528612812725657 + 0.9631491457480755im -0.011030255227385374 + 0.146520363730776im; 0.011030255227385717 + 0.14652036373077593im 0.22528612812725693 - 0.9631491457480771im], ComplexF64[0.22528612812725657 + 0.9631491457480755im -0.011030255227385374 + 0.146520363730776im; 0.011030255227385717 + 0.14652036373077593im 0.22528612812725693 - 0.9631491457480771im], ComplexF64[0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im], ComplexF64[0.4788900284285505 - 0.10786213399388914im 0.10016073473730927 - 0.0197594351188339im; -0.10016073473730917 - 0.019759435118833688im 0.4788900284285512 + 0.10786213399388933im], ComplexF64[0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im], ComplexF64[0.4749837282206564 - 0.1379443930709191im 0.07317131299535619 + 0.011572011486085169im; -0.07317131299535613 + 0.011572011486085328im 0.47498372822065704 + 0.1379443930709193im], nothing), nothing, false), false, 0, SciMLBase.DEStats(101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0.0), nothing, SciMLBase.ReturnCode.Success, nothing, nothing, nothing))Objective Types
Piccolo uses two objective types from DirectTrajOpt.jl:
| Type | When Evaluated | Constructor |
|---|---|---|
TerminalObjective | At final timestep only | TerminalObjective(loss, name, traj; Q=weight) |
KnotPointObjective | At specified timesteps | KnotPointObjective(loss, name, traj; Qs=weights) |
Both take a loss function as their first argument — a regular Julia function that maps a component vector to a scalar cost.
Creating a Custom Terminal Objective
A terminal objective evaluates a loss function on a trajectory component at the final timestep. Let's create one that penalizes trace distance from the target:
# Build the problem to get the internal NamedTrajectory
qcp = SmoothPulseProblem(qtraj, N; Q = 100.0, R = 1e-2, ddu_bound = 1.0)
traj = get_trajectory(qcp)
# Define a custom loss: trace distance penalty on the isomorphic unitary vector
trace_distance_loss(Ũ⃗) =
let
U = iso_vec_to_operator(Ũ⃗)
n = size(U, 1)
diff = U - U_goal
real(tr(diff' * diff)) / n
end
# Wrap it in a TerminalObjective (evaluated on :Ũ⃗ at the final timestep)
custom_terminal_obj = TerminalObjective(trace_distance_loss, :Ũ⃗, traj; Q = 50.0)KnotPointObjective(DirectTrajOpt.Objectives.var"#14#15"{typeof(Main.trace_distance_loss)}(Main.trace_distance_loss), [:Ũ⃗], [50], [nothing], [50.0])Creating a Custom Knotpoint Objective
A knotpoint objective evaluates at every (or selected) timesteps. Let's penalize control energy:
# Loss function: squared norm of control values
control_energy_loss(u) = dot(u, u)
# Applied at all timesteps on the :u component
custom_knotpoint_obj =
KnotPointObjective(control_energy_loss, :u, traj; Qs = fill(0.1, N), times = 1:N)KnotPointObjective(DirectTrajOpt.Objectives.var"#14#15"{typeof(Main.control_energy_loss)}(Main.control_energy_loss), [:u], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing … nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 … 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])Adding Custom Objectives to a Problem
Building the objective manually
Combine objective terms with +:
# Start with the standard infidelity objective
J = UnitaryInfidelityObjective(U_goal, :Ũ⃗, traj; Q = 100.0)
# Add standard regularization
J += QuadraticRegularizer(:u, traj, 1e-2)
J += QuadraticRegularizer(:du, traj, 1e-2)
J += QuadraticRegularizer(:ddu, traj, 1e-2)
# Add our custom objective
J += custom_knotpoint_obj
typeof(J)CompositeObjectiveAdding to an existing problem
qcp = SmoothPulseProblem(qtraj, N; Q = 100.0, R = 1e-2, ddu_bound = 1.0)
qcp.prob.objective += custom_knotpoint_objCompositeObjectiveSolving and Comparing
Solve with the extra control energy penalty:
cached_solve!(
qcp,
"custom_objectives_with_penalty";
max_iter = 50,
verbose = false,
print_level = 1,
)
fidelity(qcp)0.9993769104306977Compare against the standard problem:
qcp_standard = SmoothPulseProblem(qtraj, N; Q = 100.0, R = 1e-2, ddu_bound = 1.0)
cached_solve!(
qcp_standard,
"custom_objectives_standard";
max_iter = 50,
verbose = false,
print_level = 1,
)
fidelity(qcp_standard)0.9996342448080662Example: Leakage-Style Penalty
Here's how the built-in LeakageObjective works under the hood — it's just a KnotPointObjective with a custom loss function:
leakage_indices = [3, 4] # Indices of leakage states in the isomorphic vector
leakage_loss(x) = sum(abs2, x[leakage_indices]) / length(leakage_indices)
leakage_obj = KnotPointObjective(leakage_loss, :Ũ⃗, traj; Qs = fill(1.0, N), times = 1:N)KnotPointObjective(DirectTrajOpt.Objectives.var"#14#15"{typeof(Main.leakage_loss)}(Main.leakage_loss), [:Ũ⃗], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing … nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 … 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])Tips for Custom Objectives
1. Scale Appropriately
Match the scale of built-in objectives:
- Built-in fidelity uses
Q ~ 100 - Custom objectives should use similar magnitude
custom_obj = TerminalObjective(my_loss, :Ũ⃗, traj; Q = 50.0)2. Ensure Smoothness
Avoid discontinuities that can cause optimization issues:
## Bad: discontinuous
penalty = x > 0 ? x^2 : 0
## Good: smooth approximation
penalty = max(0, x)^2
## Also good: softplus
penalty = log(1 + exp(k * x)) / k3. Test Independently
Verify your objective computes expected values:
## Evaluate the full objective on a trajectory
value = objective_value(custom_obj, traj)
println("Objective value: ", value)
## Check gradient
∇ = zeros(traj.dim * traj.N + traj.global_dim)
gradient!(∇, custom_obj, traj)4. Start Simple
Add custom objectives incrementally:
## Step 1: Solve with standard objectives
qcp = SmoothPulseProblem(qtraj, N)
solve!(qcp)
## Step 2: Check if solution needs improvement
println("Fidelity: ", fidelity(qcp))
## Step 3: Add custom objective with small weight
custom_obj = KnotPointObjective(my_loss, :u, traj; Qs = fill(0.1, N))
qcp.prob.objective += custom_obj
solve!(qcp)
## Step 4: Increase weight if needed5. Gradients are Automatic
DirectTrajOpt uses ForwardDiff for automatic differentiation, so gradients are computed automatically for any loss function you provide. No need to implement gradient methods manually.
See Also
- Objectives - Built-in objectives
- Constraints - Hard constraints (vs soft objective penalties)
- Problem Templates - Using objectives in problems
This page was generated using Literate.jl.