qlass.utils package

The utils module provides utility functions for executing quantum algorithms, processing measurement results, and computing loss functions for VQE optimization.

Key Features

Loss Functions

  • loss_function: Standard loss function for sampling-based VQE

  • loss_function_matrix: Loss function for qubit unitary-based VQE

  • loss_function_photonic_unitary: Loss function for photonic unitaries with post-selection

  • loss_function_bose_hubbard: Sampling-based loss function for Bose-Hubbard Hamiltonians

  • e_vqe_loss_function: Ensemble-VQE loss function supporting multiple states

Utilities

  • linear_circuit_to_unitary: Converts Perceval linear circuits to unitary matrices

  • rotate_modes: Appends a 50/50 beam splitter for hopping-term measurements

  • draw_circuit: Draws or saves Perceval circuits and processors using Perceval rendering

  • DataCollector: Collects and stores energy data during ensemble-VQE optimization

    • loss_data: List of cost function values

    • energy_data: List of energy values for each state

Submodules

qlass.utils.compute_energy(pauli_bin: tuple[int, ...], res: dict[tuple[int, ...], float]) float[source]

Compute the expectation value for a given Pauli string and measurement results.

Parameters:
  • pauli_bin (Tuple[int, ...]) – A tuple of 0’s and 1’s (0’s are identities, 1’s are non-identities (X or Z))

  • res (Dict[Tuple[int, ...], float]) – Frequencies of measured qubit bitstrings

Returns:

The corresponding expectation value

Return type:

float

qlass.utils.compute_expectation_value_from_unitary(unitary: ndarray, pauli_matrix: ndarray, initial_state: ndarray | None = None) float[source]

Compute expectation value <ψ|H|ψ> where |ψ> = U|0>.

Parameters:
  • unitary (np.ndarray) – Unitary matrix representing the circuit

  • pauli_matrix (np.ndarray) – Matrix representation of Pauli operator

  • initial_state (np.ndarray) – Initial state vector (default: |0…0>)

Returns:

Expectation value

Return type:

float

qlass.utils.draw_circuit(circuit_or_processor: Processor | Circuit, output_format: str = 'mpl', skin: str = 'phys', compact: bool = False, save_path: str | None = None, backend: str = 'perceval', **kwargs: Any) None[source]

Draw a linear optical circuit or processor.

Parameters:
  • circuit_or_processor (Union[pcvl.Processor, pcvl.Circuit]) – Perceval processor or linear optical circuit to draw.

  • output_format (str) – Output format. One of "mpl", "html", "latex", or "text".

  • skin (str) – Perceval skin to use. One of "phys", "symb", or "debug".

  • compact (bool) – Whether to use compact circuit display.

  • save_path (Optional[str]) – If provided, save the rendering to this path instead of displaying it interactively.

  • backend (str) – Drawing backend. Currently only "perceval" is supported.

  • **kwargs (Any) – Additional keyword arguments forwarded to Perceval’s display function.

Raises:
  • NotImplementedError – If backend is not "perceval".

  • TypeError – If circuit_or_processor is not a Perceval Processor or Circuit.

  • ValueError – If output_format or skin is invalid.

qlass.utils.e_vqe_loss_function(lp: ndarray, H: dict[str, float], executor: Any, energy_collector: DataCollector, weight_option: str = 'weighted', mitigator: Any | None = None) float[source]

Compute the loss function for the ensemble Variational Quantum Eigensolver (VQE).

Each Pauli term is measured with its own executor call, which returns one sampling result per ensemble state.

The function works with executors that return, per ensemble state, either: 1. Fock states (from linear optical circuits) - exqalibur.FockState objects 2. Bitstring tuples (from regular qubit-based circuits) 3. Bitstring strings (from Qiskit Sampler)

The executor should return a list with one entry per ensemble state, each in one of these formats: - Dict with ‘results’ key: {‘results’: [samples]} - Direct list of samples: [samples] - Qiskit-style format with bitstrings or counts

Parameters:
  • lp (np.ndarray) – Array of variational circuit parameters. Typically optimized to minimize the expectation value of the Hamiltonian.

  • H (dict of {str: float}) – Hamiltonian represented as a dictionary mapping Pauli strings (e.g., 'XZ', 'IZ') to their coefficients.

  • executor (callable) – Function or callable object that executes the quantum circuit and returns measurement samples. Must accept arguments (lp, pauli_string) and return a list of sampling results, one per ensemble state.

  • energy_collector (DataCollector) – Object responsible for tracking or logging the energy convergence history. Must implement a method energies_convergence(energies, n_ensembles, total_loss).

  • weight_option ({'weighted', 'equi', 'ground_state_only'}) – Scheme for assigning ensemble weights: - 'weighted' (default): Linearly decreasing weights with index, i.e., w_i < w_j for i > j. - 'equi' : Equal weights for all occupied orbitals, w_i = w_j. - 'ground_state_only' : Only the ground state contributes, w_0 = 1, others 0.

  • mitigator (object, optional) – Mitigator object (e.g., M3Mitigator) applied to each ensemble state’s measured counts, as in loss_function.

Returns:

loss – The computed ensemble VQE loss value, equal to the weighted sum of ensemble energies.

Return type:

float

qlass.utils.get_probabilities(samples: list[FockState | tuple[int, ...] | str]) dict[FockState | tuple[int, ...], float][source]

Get the probabilities of sampled states.

This function now handles: - Fock states: List[exqalibur.FockState] -> Dict[exqalibur.FockState, float] - Bitstring tuples: List[Tuple[int, …]] -> Dict[Tuple[int, …], float] - Bitstring strings (from Qiskit): List[str] -> Dict[Tuple[int, …], float]

Parameters:

samples (List[Union[exqalibur.FockState, Tuple[int, ...], str]]) – Sampled states (Fock states, bitstring tuples, or bitstring strings)

Returns:

Probabilities of sampled states

Return type:

Dict[Union[exqalibur.FockState, Tuple[int, …]], float]

qlass.utils.is_qubit_state(state: FockState) tuple[int, ...] | None[source]

Check if a given Fock state is a valid dual-rail qubit state.

Parameters:

state (exqalibur.FockState) – The Fock state to check

Returns:

The corresponding qubit state if valid, None otherwise

Return type:

Optional[Tuple[int, …]]

qlass.utils.linear_circuit_to_unitary(circuit: Circuit) ndarray[source]

Convert a linear optical circuit to a unitary matrix.

Parameters:

circuit (pcvl.Circuit) – Linear optical circuit

Returns:

Unitary matrix representation of the circuit

Return type:

np.ndarray

qlass.utils.logical_state_to_modes(logical_state: int, m: int, mode_map: list[int] | None = None) list[int][source]

Convert a logical qubit state to the set of occupied photon modes.

Parameters:

logical_stateint

Integer representing the logical state (0 to 2^m - 1)

mint

Number of qubits

mode_mapOptional[List[int]]

Physical mode index for each of the 2m dual-rail rails. If None, qubit k uses physical modes 2k and 2k+1 directly.

Returns:

List[int]

List of occupied mode indices (0-indexed)

qlass.utils.loss_function(lp: ndarray, H: dict[str, float], executor: Any, mitigator: Any | None = None) float[source]

Compute the loss function for the VQE algorithm.

Each Pauli term is measured with its own executor call. (Grouping commuting terms is available via qlass.quantum_chemistry.group_commuting_pauli_terms but is not applied here, since terms are measured individually either way.)

The function works with executors that return either: 1. Fock states (from linear optical circuits) - exqalibur.FockState objects 2. Bitstring tuples (from regular qubit-based circuits) 3. Bitstring strings (from Qiskit Sampler)

The executor should return samples in one of these formats: - Dict with ‘results’ key: {‘results’: [samples]} - Direct list of samples: [samples] - Qiskit-style format with bitstrings or counts

Parameters:
  • lp (np.ndarray) – Array of parameter values

  • H (Dict[str, float]) – Hamiltonian dictionary

  • executor – A callable function that executes the quantum circuit.

  • mitigator – Optional mitigator object (e.g., M3Mitigator) to correct measurement errors.

Returns:

The computed loss value

Return type:

float

qlass.utils.loss_function_bose_hubbard(lp: ndarray, H: BosonOperator, executor: Callable, mitigator: Any | None = None) float[source]

Compute the expectation value of a Bose-Hubbard Hamiltonian from samples.

Parameters:
  • lp (np.ndarray) – Variational parameters passed to the executor.

  • H (BosonOperator) – Bose-Hubbard Hamiltonian represented as an OpenFermion BosonOperator.

  • executor (Callable) – Sampling executor. It is called as executor(lp, "identity") for diagonal terms and executor(lp, "hop", p, q) for hopping terms.

  • mitigator (Any, optional) – Optional mitigator object used to correct sampled counts.

Returns:

Estimated Bose-Hubbard energy.

Return type:

float

Raises:
  • TypeError – If H is not a BosonOperator.

  • ValueError – If H contains unsupported non-Bose-Hubbard terms.

qlass.utils.loss_function_matrix(params: ndarray, H: dict[str, float], unitary_executor: Callable) float[source]

Compute loss function using unitary matrices directly.

Parameters:
  • params (np.ndarray) – Variational parameters

  • H (Dict[str, float]) – Hamiltonian dictionary

  • unitary_executor – Function that returns unitary matrix given params

Returns:

Energy expectation value

Return type:

float

qlass.utils.loss_function_photonic_unitary(params: ndarray, H: dict[str, float], photonic_unitary_executor: Callable, initial_state: ndarray | None = None, ancillary_modes: list[int] | None = None) float[source]

Computes the loss function for a photonic VQE using the efficient, matrix-free state vector approach for post-selection.

This version accepts a full state vector for the initial state, allowing for superposition states, and allows for post-selection on ancillary modes.

Parameters:
  • params – Variational parameters for the ansatz.

  • H – Hamiltonian dictionary.

  • photonic_unitary_executor – A function that takes params and returns the M x M photonic unitary U, where M is the total number of modes (logical + ancillary).

  • initial_state – The initial qubit state as a 2^m dimensional numpy vector. If None, defaults to the |00…0> state.

  • ancillary_modes – A list of mode indices to be treated as ancillary. Post-selection is performed by assuming these modes are 0 (vacuum) for both input and output.

Returns:

The computed energy expectation value.

qlass.utils.normalize_samples(samples: Any) list[FockState | tuple[int, ...]][source]

Normalize samples from different executor formats to a consistent format.

Handles: - Qiskit bitstring format: [‘00’, ‘01’, ‘11’] -> [(0,0), (0,1), (1,1)] - Already normalized tuples: [(0,0), (0,1)] -> [(0,0), (0,1)] - ExQalibur FockStates: [FockState, …] -> [FockState, …]

Parameters:

samples – Raw samples in various formats

Returns:

Normalized samples

Return type:

List[Union[exqalibur.FockState, Tuple[int, …]]]

qlass.utils.permanent(matrix: ndarray) complex[source]

Calculate the permanent of a matrix.

The permanent is like a determinant but without alternating signs: Perm(A) = Σ_{σ∈Sₘ} Π_{i=1 to m} A_{i,σ(i)}

Parameters:

matrixnp.ndarray

Square matrix to calculate permanent of

Returns:

complex

The permanent of the matrix

qlass.utils.photon_to_qubit_unitary(U_photon: ndarray) ndarray[source]

Convert a photon unitary to the effective qubit unitary via post-selection.

Parameters:

U_photonnp.ndarray

The 2m × 2m unitary matrix acting on photon modes

Returns:

np.ndarray

The 2^m × 2^m effective qubit unitary matrix

qlass.utils.qubit_state_marginal(prob_dist: dict[FockState | tuple[int, ...], float]) dict[tuple[int, ...], float][source]

Calculate the frequencies of measured qubit states from a probability distribution.

This function now handles both Fock states and bitstring inputs: - If input contains Fock states, converts them to qubit states using is_qubit_state - If input already contains bitstrings (tuples), passes them through directly

Parameters:

prob_dist (Dict[Union[exqalibur.FockState, Tuple[int, ...]], float]) – Probability distribution of either Fock states or bitstrings

Returns:

Frequencies of measured qubit states

Return type:

Dict[Tuple[int, …], float]

qlass.utils.rotate_modes(circuit_or_processor: Circuit | Processor, mode_1: int, mode_2: int) Circuit | Processor[source]

Append a 50/50 beam splitter across two photonic modes before measurement.

Parameters:
  • circuit_or_processor (Union[pcvl.Circuit, pcvl.Processor]) – Perceval circuit or processor to rotate.

  • mode_1 (int) – First mode index.

  • mode_2 (int) – Second mode index.

Returns:

The input circuit or processor with the beam splitter appended.

Return type:

Union[pcvl.Circuit, pcvl.Processor]

Raises:

ValueError – If both mode indices are identical or either index is negative.

qlass.utils.rotate_qubits(pauli_string: str, vqe_circuit: Circuit | QuantumCircuit) Circuit | QuantumCircuit[source]

Apply the correct rotations on corresponding qubits for expectation value computation.

Note: the circuit is modified in place and also returned; pass a copy if the original must stay unchanged.

Parameters:
  • pauli_string (str) – A string representation of Pauli operators

  • vqe_circuit (Union[pcvl.Circuit, qiskit.QuantumCircuit]) – The VQE circuit to modify

Returns:

The modified VQE circuit with applied rotations (same type as the input)

Return type:

Union[pcvl.Circuit, qiskit.QuantumCircuit]