Multivariable

Algorithms for continuous multivariable optimization problems.

Classes

Predefined QVAs for the optimisation of continuous multivariable functions.

Note

The following compatible Operator Functions may be imported from the multivariable :

  • setup_cartesian()

  • cartesian()

  • cartesian_scaled()

class quop_mpi.algorithm.multivariable.qmoa(Ns: list[int], MPI_COMM: mpi4py.MPI.Intracomm = mpi4py.MPI.COMM_WORLD)

Bases: multivariable

Simulate the QMOA.

A QVA for the optimisation of continuous multivariable functions.

Parameters:
Nslist[int]

the number of grid points in each each coordinate dimension

MPI_communicatorIntracomm, optional

MPI Intracomm, by default MPI.COMM_WORLD

benchmark(ansatz_depths: Iterable[int], repeats: int, initial_parameters: list[float] | np.ndarray[float] = None, param_persist: bool = False, verbose: bool = True, filename: str = None, label: str = 'test', save_action: str = 'a', time_limit: int = None, suspend_path: str = None)

A method by which to study how a QVA performs as the number of ansatz iterations<ansatz depth> increases.

Parameters:
ansatz_depthsiterable[int]

integers specifying a sequence of ansatz depths<ansatz depth>

repeatsint

number of repeats at each ansatz depth

initial_parameters: list[float] or ndarray[float], optional

** Must be defined if a parameter mapping function is set. ** initial variational parameter values, if not present these are generated using the default parameter generation methods of the ansatz unitaries.

param_persistbool, optional

if True the optimised variational parameter values which achieved the lowest objective function value for all repeats at ansatz_depth will be used as starting parameters for the first ansatz_depth * total_params at ansatz_depth += 1. if a parameter map is set, the initial parameters will update whenever the objective function reaches a new minimum.

verbosebool, optional

if True, print current the ansatz depth, repeat number and optimisation results (default True)

filenamestr or None, optional

name of *.h5 file in which to save the optimised system state and observables

labelstr, optional

if filename is not None, *.h5 data will be saved as “filename/label_depth_repeat” (default “test”)

save_action{‘a’, ‘w’}, optional

action taken during first file write: ‘a’ to append, ‘w’ to overwrite (default ‘a’)

time_limitint or None, optional

total allocated in-program time in seconds; if exceeded, the benchmark is suspended

suspend_pathstr or None, optional

path to the suspend file if time_limit is not None

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_bindable_attributes() dict[str, tuple]

Return a dictionary of attributes available for binding to QuOp Functions.

QuOp Functions can have their positional parameters automatically bound to class attributes by matching parameter names. This method shows which attributes are available for binding and their current values.

This method collects bindable attributes from the entire class hierarchy, so subclasses can extend the available attributes.

Returns:
dict

Dictionary mapping attribute names to (value, description) tuples. Value is None if the attribute hasn’t been set yet.

See also

print_bindable_attributes

Print formatted table

Examples

>>> obj.get_bindable_attributes()
{'system_size': (1024, 'Total number of quantum basis states'),
 'local_i': (None, 'Number of elements in this rank\'s partition'),
 ...}
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

grid_point_from_index(index: int) np.ndarray[np.float64]

Retrieve the corresponding coordinate point from a global index of the system state.

Parameters:
indexint

global index of the system state

Returns:
ndarray[float64]

a 1-D real array containing a grid point in Cartesian coordinates

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_bindable_attributes()

Print a formatted table of attributes available for binding to QuOp Functions.

This is a convenience method for interactive use to discover which parameter names can be used in custom QuOp Functions.

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.

save(file_name: str, config_name: str, action: str = 'a')

Write the final state, observables and results summary to a HDf5 file.

Parameters:
file_namestr

file path to saved data

config_namestr

simulation identifier

action{‘a’, ‘w’}, optional

‘a’ to append or ‘w’ to overwrite, by default ‘a’

Notes

Data is saved into a *.h5 file with the following structure.

config_name/
    final_state
    observables

The minimization result is saved in the ‘minimize_result’ attribute of ‘config_name’ as a formatted string.

Multiple configurations with a unique config_name can be stored in the same .h5 file. HDF5 files are supported in python by the h5py package. With it, a saved configuration can be accessed as follows:

import h5py

config_name = "my_simulation"

f = h5py.File(file_name + ".h5", "r") final_state =
np.array(f[config_name]['final_state']).view(np.complex128)
eigenvalues =
np.array(f[config_name]['eigenvalues']).view(np.complex128)
observables =
np.array(f[config_name]['observables']).view(np.float64)

print(f["my_simulation"].attrs["minimize_result"])

Warning

The "final_state" and "observables" datasets are saved using Fortran subroutines which make use of parallel HDF5.

The complex values of the final_state array are saved as a compound datatype consisting of contiguous double precision reals. This is equivalent to the np.complex128 NumPy datatype. To access this data without a loss of precision in python, the user must set the view of the NumPy array to np.complex128, rather than casting it to np.complex128 using the dtype keyword.

Similarly, the observables array, which is saved as an array of double-precision reals, should have its view set to np.float64.

set_depth(depth: int)

Set the simulated ansatz depth.

Parameters:
depthint

number of ansatz iterations

set_independent_t(independent: bool)

Specify simulation with or without independent unitary parameters (walk times) over each coordinate dimension.

Parameters:
independentbool

simulate a unique walk time in each coordinate dimension if True, all walk times share the same value if False

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_log(filename: str, label: str, action: str = 'a')

Creates a CSV in which to save simulation results after a call to execute().

Parameters:
filenamestr

path to the log file

labelstr

simulation identifier

action{‘a’, ‘w’}, optional

‘a’ to append or ‘w’ overwrite, by default ‘a’

set_mixer(Cs: list[int])

Set the circulant mixing unitary operator in each coordinate dimension.

Parameters:
Cslist[int]

specifies the “i-th” symmetric circulant matrix with edges weights 1, Cs[j] == 1 cycle graph, Cs[j] > system_size // 2 complete graph

See also

quop_mpi.propagator.composite.ith()
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_parallel_jacobian(nodes_per_subcomm: int, processes_per_node: int, maxcomm: int, method: str | Callable = 'forward', h: float | None = None)

Specify optimisation of the variational parameters using parallel computation of the jacobian.

This creates MPI subcommunicators containing duplicates of the Ansatz instance which return partial derivative information to the root MPI process during optimisation.

Parameters:
nodes_per_subcommint

MPI nodes per subcommunicator

processes_per_nodeint

MPI processors associated with each node

maxcommint

maximum number of created MPI subcommunicators (and Ansatz instance duplicates) if nodes_per_subcomm > 1, or the maximum number of MPI subcommunicators per node if nodes_per_subcomm = 1

method :{‘forward’, ‘central’} or callable, optional

‘forward’ or ‘central’ to use the forward difference or central difference method for numerical approximation of the partial derivatives, or a QuOp Jacobian Function, by default ‘forward’

hfloat, optional

step-size used by the forward or central difference methods, by default np.sqrt(np.finfo(float).eps)

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_params(param_function: Callable, param_dict: dict | None = None)

Define the Parameter Function for the phase-shift and mixing unitaries.

Parameters:
param_functionCallable

a Parameter Function

param_dictFunctionDict

FunctionDict for param_function

set_qualities(function: Callable, operator_dict: dict | None = None)

Define the observables and phase-shift unitary operator

Parameters:
functionCallable

an Operator Function

operator_dictFunctionDict, optional

FunctionDict for function

set_sampling(sample_block_size: int, function: Callable | None = None, max_sample_iterations: int = 100, sampling_dict: dict | None = None)

Compute the objective function using simulated sampling.

Samples are taken in blocks of sample_block_size. These are passed as a list of lists to function (a Sampling Function), which returns a value for expectation value/objective function and a boolean that indicates whether the sampled result should be passed to the classical optimiser.

If function is None, the objective function is computed as the mean of sample_block_size shots.

Parameters:
sample_block_sizeint

number of shots taken between successive computation of the expectation value/objective function

functioncallable, optional

Sampling Function

max_sample_iterationsint, optional

maximum number of sample blocks per computation of the expectation value/objective function, overrides the boolean returned by function, by default 100

sampling_dictFunctionDict, optional

FunctionDict for the Sampling 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

unset_sampling()

Revert to simulation using exact computation of the objective function.

class quop_mpi.algorithm.multivariable.qowe(Ns: list[int], deltas: list[float], mins: list[float], MPI_COMM: mpi4py.MPI.Intracomm = mpi4py.MPI.COMM_WORLD)

Bases: multivariable

benchmark(ansatz_depths: Iterable[int], repeats: int, initial_parameters: list[float] | np.ndarray[float] = None, param_persist: bool = False, verbose: bool = True, filename: str = None, label: str = 'test', save_action: str = 'a', time_limit: int = None, suspend_path: str = None)

A method by which to study how a QVA performs as the number of ansatz iterations<ansatz depth> increases.

Parameters:
ansatz_depthsiterable[int]

integers specifying a sequence of ansatz depths<ansatz depth>

repeatsint

number of repeats at each ansatz depth

initial_parameters: list[float] or ndarray[float], optional

** Must be defined if a parameter mapping function is set. ** initial variational parameter values, if not present these are generated using the default parameter generation methods of the ansatz unitaries.

param_persistbool, optional

if True the optimised variational parameter values which achieved the lowest objective function value for all repeats at ansatz_depth will be used as starting parameters for the first ansatz_depth * total_params at ansatz_depth += 1. if a parameter map is set, the initial parameters will update whenever the objective function reaches a new minimum.

verbosebool, optional

if True, print current the ansatz depth, repeat number and optimisation results (default True)

filenamestr or None, optional

name of *.h5 file in which to save the optimised system state and observables

labelstr, optional

if filename is not None, *.h5 data will be saved as “filename/label_depth_repeat” (default “test”)

save_action{‘a’, ‘w’}, optional

action taken during first file write: ‘a’ to append, ‘w’ to overwrite (default ‘a’)

time_limitint or None, optional

total allocated in-program time in seconds; if exceeded, the benchmark is suspended

suspend_pathstr or None, optional

path to the suspend file if time_limit is not None

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_bindable_attributes() dict[str, tuple]

Return a dictionary of attributes available for binding to QuOp Functions.

QuOp Functions can have their positional parameters automatically bound to class attributes by matching parameter names. This method shows which attributes are available for binding and their current values.

This method collects bindable attributes from the entire class hierarchy, so subclasses can extend the available attributes.

Returns:
dict

Dictionary mapping attribute names to (value, description) tuples. Value is None if the attribute hasn’t been set yet.

See also

print_bindable_attributes

Print formatted table

Examples

>>> obj.get_bindable_attributes()
{'system_size': (1024, 'Total number of quantum basis states'),
 'local_i': (None, 'Number of elements in this rank\'s partition'),
 ...}
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

grid_point_from_index(index: int) np.ndarray[np.float64]

Retrieve the corresponding coordinate point from a global index of the system state.

Parameters:
indexint

global index of the system state

Returns:
ndarray[float64]

a 1-D real array containing a grid point in Cartesian coordinates

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_bindable_attributes()

Print a formatted table of attributes available for binding to QuOp Functions.

This is a convenience method for interactive use to discover which parameter names can be used in custom QuOp Functions.

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.

save(file_name: str, config_name: str, action: str = 'a')

Write the final state, observables and results summary to a HDf5 file.

Parameters:
file_namestr

file path to saved data

config_namestr

simulation identifier

action{‘a’, ‘w’}, optional

‘a’ to append or ‘w’ to overwrite, by default ‘a’

Notes

Data is saved into a *.h5 file with the following structure.

config_name/
    final_state
    observables

The minimization result is saved in the ‘minimize_result’ attribute of ‘config_name’ as a formatted string.

Multiple configurations with a unique config_name can be stored in the same .h5 file. HDF5 files are supported in python by the h5py package. With it, a saved configuration can be accessed as follows:

import h5py

config_name = "my_simulation"

f = h5py.File(file_name + ".h5", "r") final_state =
np.array(f[config_name]['final_state']).view(np.complex128)
eigenvalues =
np.array(f[config_name]['eigenvalues']).view(np.complex128)
observables =
np.array(f[config_name]['observables']).view(np.float64)

print(f["my_simulation"].attrs["minimize_result"])

Warning

The "final_state" and "observables" datasets are saved using Fortran subroutines which make use of parallel HDF5.

The complex values of the final_state array are saved as a compound datatype consisting of contiguous double precision reals. This is equivalent to the np.complex128 NumPy datatype. To access this data without a loss of precision in python, the user must set the view of the NumPy array to np.complex128, rather than casting it to np.complex128 using the dtype keyword.

Similarly, the observables array, which is saved as an array of double-precision reals, should have its view set to np.float64.

set_depth(depth: int)

Set the simulated ansatz depth.

Parameters:
depthint

number of ansatz iterations

set_independent_t(independent: bool)

Specify simulation with or without independent unitary parameters (walk times) over each coordinate dimension.

Parameters:
independentbool

simulate a unique walk time in each coordinate dimension if True, all walk times share the same value if False

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_log(filename: str, label: str, action: str = 'a')

Creates a CSV in which to save simulation results after a call to execute().

Parameters:
filenamestr

path to the log file

labelstr

simulation identifier

action{‘a’, ‘w’}, optional

‘a’ to append or ‘w’ overwrite, by default ‘a’

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_parallel_jacobian(nodes_per_subcomm: int, processes_per_node: int, maxcomm: int, method: str | Callable = 'forward', h: float | None = None)

Specify optimisation of the variational parameters using parallel computation of the jacobian.

This creates MPI subcommunicators containing duplicates of the Ansatz instance which return partial derivative information to the root MPI process during optimisation.

Parameters:
nodes_per_subcommint

MPI nodes per subcommunicator

processes_per_nodeint

MPI processors associated with each node

maxcommint

maximum number of created MPI subcommunicators (and Ansatz instance duplicates) if nodes_per_subcomm > 1, or the maximum number of MPI subcommunicators per node if nodes_per_subcomm = 1

method :{‘forward’, ‘central’} or callable, optional

‘forward’ or ‘central’ to use the forward difference or central difference method for numerical approximation of the partial derivatives, or a QuOp Jacobian Function, by default ‘forward’

hfloat, optional

step-size used by the forward or central difference methods, by default np.sqrt(np.finfo(float).eps)

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_params(param_function: Callable, param_dict: dict | None = None)

Define the Parameter Function for the phase-shift and mixing unitaries.

Parameters:
param_functionCallable

a Parameter Function

param_dictFunctionDict

FunctionDict for param_function

set_qualities(function: Callable, operator_dict: dict | None = None)

Define the observables and phase-shift unitary operator

Parameters:
functionCallable

an Operator Function

operator_dictFunctionDict, optional

FunctionDict for function

set_sampling(sample_block_size: int, function: Callable | None = None, max_sample_iterations: int = 100, sampling_dict: dict | None = None)

Compute the objective function using simulated sampling.

Samples are taken in blocks of sample_block_size. These are passed as a list of lists to function (a Sampling Function), which returns a value for expectation value/objective function and a boolean that indicates whether the sampled result should be passed to the classical optimiser.

If function is None, the objective function is computed as the mean of sample_block_size shots.

Parameters:
sample_block_sizeint

number of shots taken between successive computation of the expectation value/objective function

functioncallable, optional

Sampling Function

max_sample_iterationsint, optional

maximum number of sample blocks per computation of the expectation value/objective function, overrides the boolean returned by function, by default 100

sampling_dictFunctionDict, optional

FunctionDict for the Sampling 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

unset_sampling()

Revert to simulation using exact computation of the objective function.