Skip to main content

Haiqu.variational_optimization(problem: VariationalProblem, shots: int = 1000, device: DeviceModel | None = None, device_id: str | None = None, options: dict | None = None, initial_parameters: list[float] | None = None, seed: int | None = None, optimizer_options: OptimizerOptions | None = None, use_mitigation: bool = False, use_packing: bool = False, pack_size: int | None = None, use_session: bool = False) → VariationalJobModel

Optimize a variational quantum circuit to minimize the expectation value of input observable. This method uses the NFT (Nakanishi-Fujii-Todo) optimizer internally, a gradient-free optimizer designed for variational quantum algorithms. For detailed information about the algorithm, see the paper: https://arxiv.org/abs/1903.12166
  • Parameters:
    • problem (VariationalProblem) — problem instance containing the ansatz circuit and observable.
    • shots — Number of shots per circuit evaluation. Defaults to 1000.
    • device — Device to execute on. If specified, device_id is ignored.
    • device_id — ID of the device to execute on. Defaults to None.
    • options — Additional device options.
    • initial_parameters — Initial parameter values. Cannot be used together with seed. If neither is provided, random parameters in [-0.1π, 0.1π] are generated.
    • seed — Random seed for reproducible generation of initial parameters from a uniform distribution in [-0.1π, 0.1π]. Cannot be used together with initial_parameters.
    • optimizer_options — Configuration for the NFT optimizer. If None, uses NFTOptimizerOptions with default values. See NFTOptimizerOptions for available settings.
    • use_mitigation — Whether to use error mitigation techniques. Defaults to False.
    • use_packing — Whether to use circuit packing for efficient device utilization. Defaults to False. Warning: Experimental — packing replicates circuits on unused device qubits to run multiple copies in parallel, which may increase errors for deeper input circuits. For example, a 4-qubit circuit with pack_size=2 and 1000 shots runs two copies in parallel with 500 shots each, yielding 1000 shots of results while only paying for 500 shot executions on the QPU — a 2x cost saving.
    • pack_size — Number of circuit copies to pack onto the device. Must be >= 2. Only valid when use_packing=True. If None (default), the backend will pack into at most 2/3 of the device qubits.
    • use_session — Whether to use IBM Qiskit Runtime Session for execution. Defaults to False.
  • Returns: Job handle to track optimization progress and retrieve results.
  • Return type: VariationalJobModel

Examples

Default optimizer settings:
>>> from qiskit import QuantumCircuit
>>> from qiskit.circuit import Parameter
>>> from qiskit.quantum_info import SparsePauliOp
>>> from haiqu.sdk.qml import VariationalProblem
>>> theta = Parameter('θ')
>>> ansatz = QuantumCircuit(2)
>>> ansatz.ry(theta, 0)
>>> ansatz.cx(0, 1)
>>> obs = SparsePauliOp.from_list([("ZZ", 1.0), ("XI", 0.5)])
>>> problem = VariationalProblem(ansatz, obs)
>>> job = haiqu.variational_optimization(problem, shots=1000, device_id="aer_simulator")
>>> result = job.result()
>>> print(result.min_loss)
Custom optimizer settings:
>>> from haiqu.sdk.qml import NFTOptimizerOptions
>>> optimizer = NFTOptimizerOptions(maxfev=2048, maxiter=100)
>>> job = haiqu.variational_optimization(problem, shots=1000, device_id="aer_simulator", optimizer_options=optimizer)

class haiqu.sdk.qml.problem.VariationalProblem(ansatz: QuantumCircuit, observable: SparsePauliOp)

A variational quantum optimization problem definition. Bundles a parameterized ansatz circuit with an observable to minimize.
  • Parameters:
    • ansatz — Parameterized quantum circuit.
    • observable — The observable as a SparsePauliOp.
  • Raises:
    • TypeError — If inputs are wrong types.
    • ValueError — If ansatz is not parameterized.

Example

>>> from qiskit import QuantumCircuit
>>> from qiskit.circuit import Parameter
>>> from qiskit.quantum_info import SparsePauliOp
>>> from haiqu.sdk.qml import VariationalProblem
>>> theta = Parameter('θ')
>>> ansatz = QuantumCircuit(2)
>>> ansatz.ry(theta, 0)
>>> ansatz.cx(0, 1)
>>> obs = SparsePauliOp.from_list([("ZZ", 1.0), ("XI", 0.5)])
>>> problem = VariationalProblem(ansatz, obs)

SEE ALSO

haiqu.sdk.quantum_haiqu.Haiqu.variational_optimization(): Submit problem to Haiqu cloud.

class haiqu.sdk.qml.optimizer.NFTOptimizerOptions(*, randomized_order: bool = False, reset_interval: int = 32, maxfev: int = 1024, maxiter: int = 500, eps: float = 1e-32)

Configuration options for the NFT (Nakanishi-Fujii-Todo) optimizer. The NFT algorithm is a gradient-free optimizer designed for variational quantum algorithms. For detailed information about the algorithm, see the paper: https://arxiv.org/abs/1903.12166 Preconditions: : NFT requires the following conditions on the parameterized quantum circuit:
  1. Parameters must be independent: each parameter must appear in exactly one gate (no reusing the same parameter across multiple gates).
  2. Parameterized gates must be rotations of the form R_j(θ_j) = exp(-i*θ_j*A_j/2) where A_j² = I (e.g., RX, RY, RZ gates satisfy this).
  3. The cost function must be a sum of expectation values of Hermitian operators: L(θ) = Σ_k w_k ⟨ψ_k|U†(θ) H_k U(θ)|ψ_k⟩.
Scaling: : NFT updates one parameter at a time. Each full sweep through N parameters requires ≥2N function evaluations (depending on reset_interval).
  • Parameters:
    • randomized_order — If True, shuffles the order of parameters to update each lap (full sweep through all parameters). Default: False.
    • reset_interval — How often to reset the recycled loss value. Set to 0 to disable resets. Default: 32.
    • maxfev — Maximum number of function evaluations (circuit executions). Optimization stops when this limit is reached. Default: 1024.
    • maxiter — Maximum number of iterations (parameter updates). Default: 500.
    • eps — Small epsilon value to avoid division by zero in the analytic solution. Default: 1e-32.

Notes

Stopping criterion: Optimization stops when either maxfev or maxiter is reached, whichever comes first. Function evaluations per iteration: Each iteration uses 2-3 function evaluations. The very first iteration and the first iteration of each reset interval use 3 evaluations. Subsequent iterations reuse the previous optimal value, requiring only 2 evaluations.

Example

>>> from haiqu.sdk.qml import NFTOptimizerOptions
>>> optimizer = NFTOptimizerOptions(maxfev=2048, maxiter=100)