qutip_qip.vqa

Variational Quantum Algorithms generation and optimization

Classes

OptimizationResult(res, final_state)

Class for results of VQA optimization loop.

ParameterizedHamiltonian([...])

Hamiltonian with 0 or more parameterized terms.

VQA(num_qubits[, num_layers, cost_method])

Optimizes free parameters to generate QubitCircuit instances based on Variational Quantum Algorithms.

VQABlock(operator[, is_unitary, name, ...])

Component of a VQA.

class qutip_qip.vqa.OptimizationResult(res, final_state)[source]

Bases: object

Class for results of VQA optimization loop.

Parameters:
res: scipy results instance
final_state: :obj:`qutip.Qobj`

Final state of the circuit after optimization.

get_top_bitstring()[source]

Return the bitstring associated with the highest probability measurement outcome

Returns:
bitstring: str

bitstring in the form \(|x_0x_1...x_n>\) where each \(x_i\) is 0 or 1 and n is the number of qubits of the system.

plot(S=None, label_sets=False, top_ten=False, display=True)[source]

Plot probability amplitudes of each measurement outcome of a state.

Parameters:
S: list of float, optional

Problem instance

min_cost: str, optional

The minimum cost found by optimization

label_sets: bool, optional

Replace bitstring labels with sets referring to the inferred output of the combinatorial optimization problem. For example a bitstring \(|010>\) would produce a set with the first and last elements of S, and one with the second element of S.

top_ten: bool, optional

Only plot the ten highest-probability states.

display: bool, optional

Display the plot with the pyplot plot.show() method

class qutip_qip.vqa.ParameterizedHamiltonian(parameterized_terms=[], constant_term=None)[source]

Bases: object

Hamiltonian with 0 or more parameterized terms. In general, computes a unitary as \(U = e^{H_0 + p_1 H_1 + P_2 H_2 + \dots}\)

Parameters:
parameterized_terms: list of :obj:`qutip.Qobj`

Hamiltonian terms which each require a unique parameter

constant_term: :obj:`qutip.Qobj`

Hamiltonian term which does not require parameters.

class qutip_qip.vqa.VQA(num_qubits, num_layers=1, cost_method='OBSERVABLE')[source]

Bases: object

Optimizes free parameters to generate QubitCircuit instances based on Variational Quantum Algorithms. Accepts VQABlock elements instead of Gate elements, which allows for easy parameterization of user-defined circuit elements. Includes methods for parameter optimization and generators of QubitCircuit instances.

Parameters:
num_qubits: int

number of qubits used by the algorithm

num_layers: int, optional

number of layers used by the algorihtm

cost_method: str

method used to compute the cost of an instance of the circuit constructed by fixing its free parameters. Can be one of OBSERVABLE, BITSTRING or STATE.

  1. If OBSERVABLE is set, then the attribute VQA.cost_observable needs to be specified as a Qobj. The cost of the circuit is the expectation value of this observable in the final state.

  2. If STATE is set, then VQA.cost_func needs to be specified as a callable that takes in a quantum state, as a Qobj, and returns a float.

  3. If BITSTRING is set, then VQA.cost_func needs to be specified as a callable that takes in a bitstring and returns a float.

add_block(block)[source]

Append a VQABlock instance to the circuit, and update the user_gates dictionary if necessary.

Parameters:
block: VQABlock
compute_jac(angles, indices_to_compute=None)[source]

Compute the jacobian for the circuit’s cost function, assuming the cost function is in observable mode.

Parameters:
angles: list of float

Circuit free parameters

indicies_to_compute: list of int, optional

Block indices for which to use in computing the jacobian. By default, this is every index (every block).

Returns:
jac: (n,) numpy array of floats
construct_circuit(angles)[source]

Construct a circuit by specifying values for each free parameter.

Parameters:
angles: list of float

A list of dimension (n,) for n free parameters in the circuit

Returns:
circ: QubitCircuit
cost_derivative(U, dU)[source]

Returns partial derivative of cost function (in observable mode) with respect to the parameter in the block’s unitary. Assuming a block unitary of the form e^{-iH * theta}, this will return d/(d theta) of the cost function in terms of an observable.

Parameters:
U: :obj:`qutip.Qobj`

Block unitary

dU: :obj:`qutip.Qobj`

Partial derivative of U with respect to its parameter

Returns:
dCost: float

Partial derivative of cost with respect to block’s parameter

evaluate_parameters(angles)[source]

Evaluate a cost for the circuit, based on the VQA cost method defined.

Parameters:
angles: list of float

A list of dimension (n,) for n free parameters in the circuit

Returns:
cost: float
export_image(filename='circuit.png')[source]

Export an image of the circuit.

Parameters:
filename: str, optional

The name of the exported file

get_block_series()[source]

Ordered list of circuit blocks, including layer repetitions, from first applied to last applied.

get_final_state(angles)[source]

Evaluate the circuit by specifying each circuit parameter

Parameters:
angles: list of float

A list of dimension (n,) for n free parameters in the circuit

Returns:
final_state: qutip.Qobj.

Final state of the circuit after evaluation

get_free_parameters_num()[source]

Compute the number of free parameters required to evaluate the circuit.

Returns:
num_params: int

Number of free circuit parameters

get_initial_state()[source]
Returns:
initial_state: qutip.Qobj

Initial circuit state

get_unitary_products(propagators)[source]

Return two ordered lists of propagators in the circuit. Useful for modifying individual propagators and computing the product with these modifications. For example, to modify U_k in a product of N unitaries, one could take U_prods_back[N - 1 - k] * modified_U_k * U_prods[k]

Returns:
U_prods: list of qutip.Qobj

Ordered list of [identity, U_0, U_1, … U_N]

U_prods_back: list of qutip.Qobj

Ordered list of [identity, U_N, U_{N-1}, … U_0]

optimize_parameters(initial='random', method='COBYLA', use_jac=False, layer_by_layer=False, bounds=None, constraints=())[source]

Run VQA optimization loop

Parameters:
initial: str or list of floats, optional

Initialization method for the free parameters. If a list of floats of dimensions (n,) for n free parameters in the circuit is given, then these are taken to be the initial conditions for the optimizer. Otherwise if a string is given:

  • (Default) “random” will randomize initial free parameters between 0 and 1.

  • “ones” will set each initial free parameter to a value of 1.

method: str or callable, optional

Method to give to scipy.optimize.minimize

use_jac: bool, optional

Whether to compute the jacobian or not. If computed, it will be passed to the optimizer chosen by method, regardless of if the method is gradient-based or not. Note that derivatives of unitaries generated by ParameterizedHamiltonian are calculated with the Frechet derivative of the exponential function, using scipy.linalg.expm_frechet.

layer_by_layer: bool, optional

Grow the circuit from a single layer to VQA.num_layers. At each step, hold the parameters found for previous layers fixed.

bounds: sequence or `scipy.optimize.Bounds`, optional

Bounds to be passed to the optimizer. Either

  1. Instance of scipy.optimize.Bounds

  2. Sequence of (min, max) tuples corresponding to each free parameter.

constraints: list of `Constraint`

See scipy.optimize.minimize documentation.

Returns:
result: OptimizationResult

The optimized angles and final state.

class qutip_qip.vqa.VQABlock(operator, is_unitary=False, name=None, targets=None, initial=False)[source]

Bases: object

Component of a VQA. Can return a unitary, and take derivatives of its own unitary. Forms a Gate in the QubitCircuit generated by the VQA.

Parameters:
operator: :obj:`qutip.Qobj` or Callable or str

If given as a qutip.Qobj, assumed to be a Hamiltonian with a single global parameter. If given as a Callable, assumed to take in a parameter, and return a unitary operator. If given as a str, assumed to reference a native QuTiP gate from qutip_qip.operations

is_unitary: bool, optional

Specifies that the operator was already in Unitary form, and does not need to be exponentiated, or take a parameter.

name: str, optional

Name of the block. This will be used in the custom user_gates dict of the circuit. If not provided, a name will be generated as “U”+str(len(VQA.blocks)).

targets: list of int, optional

The qubits targetted by the gate. By default, applied to all qubits.

initial: bool, optional

Whether or not to repeat this block in layers. For example, this should be True if this block is only used for circuit initialization.

get_unitary(angles=None)[source]

Return the block unitary.

Parameters:
angles: list of float, optional

Block free parameters. Required if the block has free parameters.

get_unitary_derivative(angles, term_index=0)[source]

Compute the derivative of the block’s unitary with respect to its free parameter, assuming it is of the form \(e^{-i \theta H}\) for a free parameter theta. If the block’s operator is a ParameterizedHamiltonian, use the Frechet derivative of the exponential function.

Parameters:
angle: list of float

free parameters to take derivatives with respect to

term_index: int, optional

Index of Parameterized Hamiltonian term that specifies the matrix direction in which to take the derivative.

Returns:
derivative: float