Ansatz

The Ansatz class is the core building block for quantum variational algorithms in QuOp_MPI. It manages the quantum state, unitary operators, observables, and classical optimization.

Class Reference

class quop_mpi.Ansatz(system_size: int, MPI_communicator: mpi4py.MPI.Intracomm = mpi4py.MPI.COMM_WORLD)

Bases: Sampling, Logging, Communicator, Jacobian, Benchmark, Bindable

Define and simulate a QVA.

Associated QuOp Functions:

Parameters:
system_sizeint

number of quantum basis states in the simulated system

MPI_communicatorIntracomm, optional

MPI Intracomm, by default MPI.COMM_WORLD

Examples

Minimal definition of an arbitrary QVA, of size system size. Where [UQ, UW] defines the ansatz unitary and observable_function is an Observables Function.

alg = Ansatz(system_size)
alg.set_unitaries([UQ, UW])
alg.set_observables(observable_function)
Attributes:
system_sizeint

The size of the simulated quantum system.

local_iint

parallel partition size of system state and observables

local_i_offsetint

global index offset of the local parallel partition

partition_tablendarray[int]

1-D integer array describing the global partitioning scheme such that for a given MPI rank partition_table[rank + 1] - partition_table[rank] = local_i

observablesndarray[float64]

1-D real array of local_i observables

variational_parametersndarray[float64]

1-D real array of variational parameters, updated during optimisation

ansatz_depthint

number of ansatz iterations, by default 1

total_paramsint

number of variational parameters associated with each ansatz iteration

expectationfloat

last computed objective function value, updated during optimisation

ansatz_initial_statendarray[complex128]

1-D complex array of local_i values, the initial system state

final_statendarray[complex128]

1-D array of local_i elements, the system state after computation of the state evolution under the action of an ansatz unitary.

last_evaluatedndarray[float]

1-D real array, the last variational parameters passed to evolve_state()

objective_cntint

number of objective function evaluations during QVA simulation

resultdict

last result returned by the execute() method

seedint

seeds random number generation, incremented before each repeat in the benchmark() method

sample_indexeslist[ndarray[int32]]

if simulating sampling, contains the global indexes for each block of sampled observables, resets to [] when the objective function value is accepted

sampleslist[ndarray[float64]]

if simulating sampling, contains the observable value for each block of sampled observables, resets to [] when the objective function value is accepted

sample_minimum_indexeslist[int]

if simulating sampling, contains the index of the minimum observable sampled for each computation of the objective function

Key Methods

Configuration

Execution

  • execute() - Run the variational algorithm

  • benchmark() - Study performance across ansatz depths

Results

  • save() - Save results to HDF5

  • print_result() - Display optimization results

evaluate(variational_parameters: list[float] | np.ndarray[float]) float

Lazily computes the objective function value.

The Ansatz instance stores the last variational parameters passed to evaluate and the corresponding objective function value. If the input variational parameters match, re-computation of the final state is skipped and the previously computed objective function value is returned.

Parameters:
variational_parameterslist[float] or ndarray[float]

1-D (ansatz_depth * total_params,) real array of variational parameters

Returns:
float

objective function value

evolve_state(variational_parameters: list[float] | np.ndarray[float])

Compute the system state under the action of the ansatz unitary.

Parameters:
variational_parameterslist[float] or ndarray[float]

1-D (ansatz_depth * total_params,) real array of variational parameters.

See also

set_unitaries()
execute(variational_parameters: list[float] | np.ndarray[float] = None)

Simulate a QVA.

If variational_parameters is None, initial parameter values are generated using the Parameter Function of the corresponding unitary instances.

Parameters:
variational_parameterslist[float] or ndarray[float]

1-D (ansatz_depth * total_params,) real array of variational parameters

gen_initial_params(ansatz_depth: int = None) np.ndarray[np.float64]

Generate initial variational parameters.

Values are generated using the Parameter Function associated with each unitary passed to the set_unitaries() method.

Note

If ansatz_depth is None the ansatz depth defaults to 1 or the depth specified by the set_depth() method.

Parameters:
ansatz_depthint, optional

number of ansatz iterations

Returns:
ndarray[float64]

1-D (ansatz_depth * total_params,) real array of variational parameters

get_expectation_value() float

Compute the objective function at the current value of variational_parameters.

Returns:
float

objective function value

get_final_state() np.ndarray[np.complex128] | None

Gather the final state to rank 0 of the Ansatz MPI subcommunicator.

Requires a previous call to execute(), evolve_state() or benchmark(). If called after benchmark() the gathered state will correspond to the last performed simulation.

Returns:
ndarray[complex128] or None

the final state at rank 0 of the Ansatz subcommunicator, None otherwise

get_probabilities() np.ndarray[np.float64] | None

Gather probabilities computed from the final state at rank 0 of the Ansatz MPI subcommunicator.

Requires a previous call to execute(), evolve_state() or benchmark(). If called after benchmark() the gathered state will correspond to the last performed simulation.

Returns:
ndarray[float64] or None

1-D real array of state probabilities at rank 0 of the Ansatz subcommunicator, None otherwise

property n_free_params

Number of free parameters presented to the optimizer.

Without a parameter map, this equals n_variational_parameters. With a parameter map, this is the size of the reduced parameter vector.

objective(variational_parameters: list[float] | np.ndarray[float]) float

Compute the objective function at variational parameters variational_parameters.

Parameters:
variational_parameterslist or ndarray[float]
Returns:
float

objective function value

prepare()

Fully initialize the Ansatz for inspection without running optimization.

This method runs both setup() and internal preparation steps, bringing the Ansatz to its runtime state. After calling this method:

This is useful for:

  • Debugging QuOp Functions before optimization

  • Inspecting the parallel partitioning scheme

  • Querying bindable attributes with their runtime values

  • Testing observables and initial state functions

See also

setup

Lower-level setup (parallel resources only)

execute

Run optimization

Examples

>>> alg = qwoa(1024)
>>> alg.set_qualities(my_observables)
>>> alg.prepare()  # Fully initialize
>>> alg.print_all_bindable_attributes()  # Now shows actual values
>>> print(f"Observables range: {alg.observables.min():.2f} to {alg.observables.max():.2f}")
print_all_bindable_attributes()

Print bindable attributes for this Ansatz AND all its Unitaries.

This shows the complete picture of what parameters can be bound in QuOp Functions:

  • Ansatz-level functions (Observables, Initial State, Parameter Map, Sampling, Objective) bind to Ansatz attributes

  • Unitary-level functions (Operator, Parameter) bind to Unitary attributes

Call this after set_unitaries() to see Unitary attributes.

See also

print_bindable_attributes

Ansatz attributes only

print_optimiser_result()

Print the result returned from the optimiser for the last QVA simulation.

print_result()

Print a summary of the results of the last QVA simulation.

set_depth(depth: int)

Set the simulated ansatz depth.

Parameters:
depthint

number of ansatz iterations

set_initial_state(function: Callable, initial_state_dict: dict | None = None)

Define the initial state.

Parameters:
functioncallable

Initial State Function

initial_state_dictFunctionDict, optional

FunctionDict for the Initial State Function

set_objective(function: Callable, objective_dict: dict | None = None)

Set a custom objective function (i.e. an objective function other than the expectation value of the prepared state).

The function is called after state evolution - returning a scalar value that is passed to the minimizer.

Parameters:
function: callable

an Objective Function

objective_dict: FunctionDict, optional

FunctionDict for the Objective Function

set_observables(function: Callable | int, observable_dict: dict | None = None)

Specify the observables.

Parameters:
functioncallable or int

an Observables Function or an integer specifying the index of a phase-shift unitary in the list passed to set_unitaries() whose exponent contains the observable vector.

observable_dictFunctionDict, optional

FunctionDict for the Observables Function

set_optimiser(optimiser: str, optimiser_args: dict | None = None, optimiser_log: list[str] | None = None)

Define the classical optimiser for QVA simulation.

Optionally allows for specification of arguments passed to the optimiser and fields in the optimiser dictionary to write to the log file (see set_log()). QuOp_MPI supports optimisers provided by SciPy through its minimize method minimize and optimisers provided by the NLopt package with respect to minimisation with scalar constraints through a SciPy-like interface.

Parameters:
optimiser: {‘scipy’, ‘nlopt’}

‘scipy’ to use the SciPy, ‘nlopt’ to use NLopt, or a callable QuOp_MPI-compatible optimisation function.

optimiser_args: dict

arguments to pass to the optimiser

optimiser_log: list[str]

results of the optimisation process are stored in a dictionary. These values may be logged by passing a list of the corresponding keys

Examples

The default optimiser is the BFGS algorithm, which is set internally as follows:

Ansatz.set_optimiser( 'scipy',
        {'method':'BFGS','options':{'gtol':1e-3}},
                    ['fun','nfev','success'])
set_parameter_map(n_free_params: int, mapping_fn: Callable[[np.ndarray], np.ndarray], mapping_dict: dict | None = None)

Register a mapping from a subset of optimisable parameters to the full set of variational parameters.

Parameters:
n_free_paramsint

The number of free parameters in the reduced parameter vector. This is the dimensionality of the optimization problem.

mapping_fncallable

mapping_fn(free_vec, *args, **kwargs) -> full_vec. free_vec is the vector presented to the optimiser; full_vec must have length ansatz_depth * total_params.

mapping_dictFunctionDict, optional

FunctionDict supplying extra positional and keyword arguments to the mapping function.

set_seed(seed: int)

Integer for seeding of random number generation.

Parameters:
seedint

seeds the generation of random parameters

set_unitaries(unitaries: list[Unitary])

Define the ansatz unitary.

Unitaries are passed as a python list in order of application from left to right.

Parameters:
unitaries: list[unitary]

list of unitaries specifying the action of one ansatz iteration