Configuration Options
Quandary supports TOML configuration files (recommended) and legacy CFG format.
TOML Configuration
TOML is the recommended configuration format. It provides a clear, hierarchical structure and better validation.
Note that some parameter names differ between TOML and the Python interface. For a complete cross-reference of all parameters, see the Parameter Reference.
Configuration Template
Below is the complete template with comments explaining each parameter:
[system]
# Number of levels per subsystem
nlevels = [2, 2]
# Number of essential levels per subsystem. Either a single value (same for all) or one per subsystem. (Default: same as nlevels)
nessential = [2, 2]
# Number of time steps used for time-integration
ntime = 1000
# Time step size (ns). Determines final time: T=ntime*dt
dt = 0.1
# Fundamental transition frequencies (|0> to |1> transition) for each subsystem ("\omega_k", multiplying a_k^d a_k, GHz).
# Either a single value (same for all) or one per subsystem.
transition_frequency = [4.10595, 4.81526]
# transition_frequency = 4.1 # single value applies to all subsystems
# Self-kerr frequencies for each subsystem ("\xi_k", multiplying a_k^d a_k^d a_k a_k, GHz).
# Either a single value (same for all) or one per subsystem. (Default: 0.0)
selfkerr = [0.2198, 0.2252]
# selfkerr = 0.22 # single value applies to all subsystems
# Cross-kerr coupling strength for subsystems k<->l ("\xi_kl", multiplying a_k^d a_k a_l^d a_l, GHz).
# Option 1: All-to-all connectivity with single value
# crosskerr_coupling = 0.1
# Option 2: Per-subsystem-pair coupling using array of tables
crosskerr_coupling = [
{ subsystem = [0,1], value = 0.1 }
]
# Dipole-dipole coupling strength for subsystems k<->l ("J_kl", multiplying a_k^d a_l + a_k a_l^d, GHz).
# Option 1: All-to-all connectivity with single value
dipole_coupling = 0.0
# Option 2: Per-subsystem-pair coupling using array of tables
# dipole_coupling = [
# {subsystem = [0,1], value = 0.0 }
# ]
# Rotational wave approximation frequencies for each subsystem ("\omega_rot", GHz).
# Either a single value (same for all) or one per subsystem. (Default: 0.0)
rotation_frequency = [4.10595, 4.81526]
# rotation_frequency = 0.0 # single value applies to all subsystems
# Decoherence setting: Switch between Schroedinger and Lindblad solver. Default is "none" which solves Schroedinger equation (state vector dynamics), all other types solve Lindblads master equation for the density matrix.
decoherence = { type = "none", # "none", "decay", "dephase", or "both"
# decay_time = [0.0, 0.0], # Decay times T1: single value or one per subsystem (ns)
# dephase_time = [0.0, 0.0] # Dephasing times T2: single value or one per subsystem (ns)
}
# Specify the initial conditions that are to be propagated
# Avalable initial condition types:
# "basis" - all basis states of the full composite system, or of specified subsystems (subsystem = [...])
# "state" - single initial state specified as levels of a product state (levels = [...])
# "file" - read one initial state from file (filename = "...")
# "diagonal" - for Lindblad solver, all diagonal basis density matrices of the full system, or of specified subsystems (subsystem = [...])
# "ensemble" - for Lindblad solver, ensemble state used for pure-state preparation, optionally over specified subsystems (subsystem = [...])
# "3states" - for Lindblad solver, three initial states for gate optimization
# "nplus1" - for Lindblad solver, N+1 initial states for fidelity estimation
initial_condition = {type = "basis"}
# initial_condition = {type = "state", levels = [1, 0]}
# initial_condition = {type = "basis", subsystem = [0, 1]}
# initial_condition = {type = "file", filename = "path/to/initial_state.dat"}
# Optional: Read system Hamiltonian from file (default: none - use built-in Hamiltonian)
# hamiltonian_file_Hsys = "/path/to/system_hamiltonian.dat"
# Optional: Read control Hamiltonian from file (default: none - use built-in Hamiltonian)
# hamiltonian_file_Hc = "/path/to/control_hamiltonian.dat"
[control]
# Control parameterization options:
# Available control types:
# "spline" - 2nd order B-spline basis functions (recommended).
# "spline0" - piecewise constant control parameterization (0th order B-splines)
# "spline_amplitude" - amplitude-only parameterization
# For each type, specify number of basis functions (num), and optionally start and stop times (tstart, tstop)
# Option 1: Parameterization that applies to all subsystems
parameterization = { type = "spline", num = 150}
# parameterization = { type = "spline0", num = 300 , tstart = 0.0, tstop = 10.0 }
# Option 2: Specify different parameterizations per-subsystem as array of tables
# parameterization = [
# { subsystem = 0, type = "spline", num = 150, tstart = 0.0, tstop = 10.0 },
# { subsystem = 1, type = "spline0", num = 300 }
# ]
# Carrier wave frequencies (GHz).
# Option 1: Specify different arrays of frequencies for each subsystem, as array of tables
carrier_frequency = [
{subsystem = 0, value = [0.0, -0.2198, -0.1]},
{subsystem = 1, value = [0.0, -0.2252, -0.1]}
]
# Option 2: Same array of frequencies for all subsystems using a table
# carrier_frequency = { values = [0.0, -0.2252, -0.1] }
# Option 3: Same array of frequencies for all subsystems using shorthand
# carrier_frequency = [0.0, -0.2252, -0.1]
## Control parameter initialization:
# Available types:
# "random" - random initialization within amplitude bounds (amplitude = ...)
# "constant" - constant amplitude initialization (amplitude = ...)
# "file" - read initial parameters from file (filename = "...")
## Option 1: Initialization that applies to all subsystems
initialization = { type = "random", amplitude = 0.005}
# initialization = { type = "file", filename = "./params.dat"}
## Option 2: Specify different initialization per subsystem as array of tables
# initialization = [
# { subsystem = 0, type = "constant", amplitude = 0.003 },
# { subsystem = 1, type = "random", amplitude = 0.05 }
# ]
# Maximum amplitude bound for the control pulses (GHz).
# Option 1: Single value applies to all subsystems
amplitude_bound = 0.008
# Option 2: Specify different bounds for each subsystem as array
# amplitude_bound = [0.008, 0.010]
## Decide whether control pulses should start and end at zero.
zero_boundary_condition = false
[optimization]
# Optimization target options:
# Available target types:
# "none" - No optimization target
# "gate" - Unitary gate transformation. The gate can be read from file (filename = "..."), or chosen from standard gates below (gate_type = "..."). Optionally, a gate rotation frequency can be specified (gate_rot_freq = single value or array)
# "state" - Single target state. The state can be read from file (filename = "..."), or can be specified as levels of a product state (levels = [...])
target = {type = "gate", gate_type = "cnot"} # "cnot", "cqnot", "swap", "swap0q", "qft", "xgate", "ygate", "zgate", "hadamard"
# target = { type = "gate", gate_type = "cnot", gate_rot_freq = 0.0 } # single value for all
# target = { type = "gate", gate_type = "cnot", gate_rot_freq = [0.0, 0.0] } # one per subsystem
# target = {type = "gate", filename = "/path/to/target_gate.dat"}
# target = {type = "state", levels = [0, 0]}
# target = {type = "state", filename = "/path/to/target_state.dat"}
#target = {type = "none"}
# Objective function measure options: "Jtrace", "Jfrobenius", "Jmeasure"
objective = "Jtrace"
# Weights (beta_i) for summing up objective function terms from different initial conditions.
# Must be an array of weights (one per initial condition). Default is uniform weighting.
# weights = [1.0, 0.1, 0.1, 0.1]
# Optimization tolerances (stopping criteria):
tolerance = { grad_abs = 1e-7, # absolute gradient norm tolerance (||G|| < grad_abs)
grad_rel = 1e-8, # relative gradient norm tolerance (||G||/||G0|| < grad_rel)
final_cost = 1e-5, # final-time cost tolerance (J(T) < final_cost)
infidelity = 1e-5 # infidelity tolerance (1 - F_avg < infidelity)
}
# Maximum number of optimization iterations
maxiter = 200
# Tikhonov regularization for the optimization variables (gamma * ||x||^2)
tikhonov = { coeff = 0.00001, # Coefficient (gamma) for Tikhonov regularization
use_x0 = false # use gamma * ||x - x_0||^2 instead (default: false)
}
# Coefficients for Penalty terms added to the optimization cost function
penalty = { leakage = 0.0, # Penalize leakage into guard levels
energy = 0.0, # Penalize integral over control pulse energy
dpdm = 0.0, # Penalize 2nd derivative of state populations
variation = 0.0, # Penalize control pulse variation (for 0-th order Bsplines)
weightedcost = 0.0, # Penalize time-weighted cost function integral
weightedcost_width = 0.0 # Width paramter for weighted cost function integral
}
[output]
# Directory for output files
directory = "./data_out"
# Specify the desired observables during time evolution. Format: list of any of the following options:
# "expectedEnergy" - expected level occupation for each subsystem
# "expectedEnergyComposite" - expected level of the full-dimensional composite system
# "population" - level occupation (probabilities) for each subsystem
# "populationComposite" - level occupation (probabilities) for the full-dimensional composite system
# "fullstate" - full state of the composite system (full density matrix, or state vector). WARNING: This might result in very large output files - use with care.
observables = ["population", "expectedEnergy"]
# Output frequency in the time domain: write output every <num> time-step
timestep_stride = 1
# Output frequency for optimization history: write every <num> optimization iterations
optimization_stride = 1
[solver]
# Runtype options:
# "simulation" - a forward simulation only
# "gradient" - forward simulation and backward simulation
# "optimization" - a full optimization cycle
# "evalControls" - only evaluates the current control pulses (no simulation)
runtype = "optimization"
# Use matrix free solver, instead of sparse matrix implementation. Only available for 2,3,4, or 5 subsystems.
usematfree = true
# Linear solver configuration: type can be "gmres" or "neumann", and maximum number of iteration (maxiter)
linearsolver = { type = "gmres", maxiter = 20 }
# Switch the time-stepping algorithm. Currently available:
# "IMR" - Implicit Midpoint Rule (IMR) of 2nd order,
# "IMR4" - Compositional IMR of order 2 using 3 stages,
# "IMR8" - Compositional IMR of order 8 using 15 stages,
# "EE" - Explicit Euler (EE) of 1st order, (for debugging only)
timestepper = "IMR"
# Fixed seed for the random number generator. Comment out, or set negative if seed should be random (non-reproducable)
rand_seed = 1234