Structured state evolution¶
Module for circuit simulation by state evolution, where the state is
represented by a tensor network with a predefined structure.
Approximate tensor network contraction is supported. Both MPS and TTN
methods are provided.
For an example of its use, see the examples/ folder at
https://github.com/CQCL/pytket-cutensornet.
Library handle¶
- class pytket.extensions.cutensornet.CuTensorNetHandle(device_id=None)[source]¶
Initialise the cuTensorNet library with automatic workspace memory management.
Note
Always use as
with CuTensorNetHandle() as libhandle:so that cuTensorNet handles are automatically destroyed at the end of execution.- device_id¶
The ID of the device (GPU) where cuTensorNet is initialised. If not provided, defaults to
cp.cuda.Device().- Type:
Simulation¶
- pytket.extensions.cutensornet.structured_state.simulate(libhandle, circuit, algorithm, config, compilation_params=None)[source]¶
Simulates the circuit and returns the
StructuredStateof the final state.Note
A
libhandleis created via awith CuTensorNetHandle() as libhandle:statement. The device where theStructuredStateis stored will match the one specified by the library handle.The input
circuitmust be composed of one-qubit and two-qubit gates only. Any gateset supported bypytketcan be used.- Parameters:
libhandle (
CuTensorNetHandle) – The cuTensorNet library handle that will be used to carry out tensor operations.circuit (
Circuit) – The pytket circuit to be simulated.algorithm (
SimulationAlgorithm) – Choose between the values of theSimulationAlgorithmenum.config (
Config) – The configuration object for simulation.compilation_params (
dict[str,Any] |None) – Experimental feature. Defaults to no compilation. Parameters currently not documented.
- Return type:
- Returns:
An instance of
StructuredStatefor (an approximation of) the final state of the circuit. The instance be of the class matchingalgorithm.
- enum pytket.extensions.cutensornet.structured_state.SimulationAlgorithm(value)[source]¶
An enum to refer to the StructuredState contraction algorithm.
Each enum value corresponds to the class with the same name; see its docs for information about the algorithm.
Valid values are as follows:
- TTNxGate = <SimulationAlgorithm.TTNxGate: 0>¶
- MPSxGate = <SimulationAlgorithm.MPSxGate: 1>¶
- MPSxMPO = <SimulationAlgorithm.MPSxMPO: 2>¶
- class pytket.extensions.cutensornet.structured_state.Config(chi=None, truncation_fidelity=None, kill_threshold=0.0, seed=None, float_precision=<class 'numpy.float64'>, value_of_zero=1e-16, leaf_size=8, k=4, optim_delta=1e-05, loglevel=30, logfile=None)[source]¶
Configuration class for simulation using
StructuredState.- __init__(chi=None, truncation_fidelity=None, kill_threshold=0.0, seed=None, float_precision=<class 'numpy.float64'>, value_of_zero=1e-16, leaf_size=8, k=4, optim_delta=1e-05, loglevel=30, logfile=None)[source]¶
Instantiate a configuration object for
StructuredStatesimulation.Note
Providing both a custom
chiandtruncation_fidelitywill raise an exception. Choose one or the other (or neither, for exact simulation).- Parameters:
chi (
int|None) – The maximum value allowed for the dimension of the virtual bonds. Higher implies better approximation but more computational resources. If not provided,chiwill be unbounded.truncation_fidelity (
float|None) – Every time a two-qubit gate is applied, the virtual bond will be truncated to the minimum dimension that satisfies|<psi|phi>|^2 >= trucantion_fidelity, where|psi>and|phi>are the states before and after truncation (both normalised). If not provided, it will default to its maximum value 1.kill_threshold (
float) – If the fidelity estimateself.get_fidelity()drops below the specified threshold, the simulation will be stopped, raising aLowFidelityExceptionexception. Defaults to 0, meaning it is never killed.seed (
int|None) – Seed for the random number generator. Setting a seed provides reproducibility across simulations usingStructuredState, in the sense that they will produce the same sequence of measurement outcomes. Crucially, consecutive samples taken from the sameStructuredStatecan still be different from each other.float_precision (
type[Any]) – The floating point precision used in tensor calculations; choose fromnumpytypes:np.float64ornp.float32. Complex numbers are represented using two of suchfloatnumbers. Default isnp.float64.value_of_zero (
float) – Any number below this value will be considered equal to zero. Even when nochiortruncation_fidelityis provided, singular values below this number will be truncated. We suggest to use a value slightly below what your chosenfloat_precisioncan reasonably achieve. For instance,1e-16fornp.float64precision (default) and1e-7fornp.float32.leaf_size (
int) – ForTTNsimulation only. Sets the maximum number of qubits in a leaf node when usingTTN. Default is 8.k (
int) – ForMPSxMPOsimulation only. Sets the maximum number of layers the MPO is allowed to have before being contracted. Increasing this might increase fidelity, but it will also increase resource requirements exponentially. Default value is 4.optim_delta (
float) – ForMPSxMPOsimulation only. Sets the stopping criteria for the optimisation when contracting theklayers of MPO. Stops when the increase of fidelity between iterations is smaller than this value. Default value is1e-5.loglevel (
int) – Internal logger output level. Use 30 for warnings only, 20 for verbose and 10 for debug mode.logfile (
str|None) – If provided, log will be written to the given file.
- Raises:
ValueError – If both
chiandtruncation_fidelityare fixed.ValueError – If the value of
chiis set below 2.ValueError – If the value of
truncation_fidelityis not in [0,1].LowFidelityException – If a
kill_thresholdspecified by the user was violated.
Classes¶
- class pytket.extensions.cutensornet.structured_state.StructuredState[source]¶
Class representing a Tensor Network state.
- abstract is_valid()[source]¶
Verify that the tensor network state is valid.
- Return type:
- Returns:
False if a violation was detected or True otherwise.
- apply_gate(gate)[source]¶
Apply the command to the
StructuredState.Note
All one-qubit gates and two-qubit gates are supported. Multi-qubit
CnXandPauliExpBoxgates are supported forMPSxGate.- Parameters:
gate (
Command) – The command to be applied.- Return type:
- Returns:
self, to allow for method chaining.- Raises:
RuntimeError – If the
CuTensorNetHandleis out of scope.ValueError – If the command introduced is not a unitary gate.
ValueError – If the command acts on more than 2 qubits.
- abstract apply_unitary(unitary, qubits)[source]¶
Applies the unitary to the specified qubits of the StructuredState.
Note
It is assumed that the matrix provided by the user is unitary. If this is not the case, the program will still run, but its behaviour is undefined.
- Parameters:
unitary (cp.ndarray) – The matrix to be applied as a CuPy ndarray. It should either be a 2x2 matrix if acting on one qubit or a 4x4 matrix if acting on two.
qubits (list[Qubit]) – The qubits the unitary acts on. Only one qubit and two qubit unitaries are supported.
- Return type:
StructuredState
- Returns:
self, to allow for method chaining.- Raises:
RuntimeError – If the
CuTensorNetHandleis out of scope.ValueError – If the number of qubits provided is not one or two.
ValueError – If the size of the matrix does not match with the number of qubits provided.
- abstract apply_scalar(scalar)[source]¶
Multiplies the state by a complex number.
- Parameters:
scalar (
complex) – The complex number to be multiplied.- Return type:
- Returns:
self, to allow for method chaining.
- abstract apply_qubit_relabelling(qubit_map)[source]¶
Relabels each qubit
qasqubit_map[q].This does not apply any SWAP gate, nor it changes the internal structure of the state. It simply changes the label of the physical bonds of the tensor network.
- Parameters:
qubit_map (
dict[Qubit,Qubit]) – Dictionary mapping each qubit to its new label.- Return type:
- Returns:
self, to allow for method chaining.- Raises:
ValueError – If any of the keys in
qubit_mapare not qubits in the state.
- abstract vdot(other)[source]¶
Obtain the inner product of the two states:
<self|other>.It can be used to compute the squared norm of a state
stateasstate.vdot(state). The tensors within the state are not modified.Note
The state that is conjugated is
self.- Parameters:
other (
StructuredState) – The otherStructuredState.- Return type:
- Returns:
The resulting complex number.
- Raises:
RuntimeError – If number of tensors, dimensions or positions do not match. This may be the case if you used
prepare_circuit_mps.RuntimeError – If the two states do not have the same qubits.
RuntimeError – If the
CuTensorNetHandleis out of scope.
- abstract sample()[source]¶
Returns a sample from a Z measurement applied on every qubit.
Notes
The contents of
selfare not updated. This is equivalent to applyingstate = self.copy()thenstate.measure(state.get_qubits()).
- abstract measure(qubits, destructive=True)[source]¶
Applies a Z measurement on each of the
qubits.Notes
After applying this function,
selfwill contain the normalised projected state.- Parameters:
- Return type:
- Returns:
A dictionary mapping the given
qubitsto their measurement outcome, i.e. either0or1.- Raises:
ValueError – If an element in
qubitsis not a qubit in the state.
- abstract postselect(qubit_outcomes)[source]¶
Applies a postselection, updates the states and returns its probability.
Notes
After applying this function,
selfwill contain the projected state over the non-postselected qubits.The resulting state has been normalised.
- Parameters:
qubit_outcomes (
dict[Qubit,int]) – A dictionary mapping a subset of qubits to their desired outcome value (either0or1).- Return type:
- Returns:
The probability of this postselection to occur in a measurement.
- Raises:
ValueError – If a key in
qubit_outcomesis not a qubit in the state.ValueError – If a value in
qubit_outcomesis other than0or1.ValueError – If all of the qubits in the state are being postselected. Instead, you may wish to use
get_amplitude().
- abstract expectation_value(pauli_string)[source]¶
Obtains the expectation value of the Pauli string observable.
- Parameters:
pauli_string (
QubitPauliString) – A pytket object representing a tensor product of Paulis.- Return type:
- Returns:
The expectation value.
- Raises:
ValueError – If a key in
pauli_stringis not a qubit in the state.
- abstract get_statevector()[source]¶
Returns the statevector with qubits in Increasing Lexicographic Order (ILO).
- Raises:
ValueError – If there are no qubits left in the state.
- Return type:
ndarray
- abstract get_amplitude(state)[source]¶
Returns the amplitude of the chosen computational state.
Notes
The result is equivalent to
state.get_statevector[b], but this method is faster when querying a single amplitude (or just a few).
- get_bits()[source]¶
Returns the dictionary of bits and their values.
A bit with value
Falsecorresponds to0, andTrueis1.
- abstract get_byte_size()[source]¶
Returns the number of bytes
selfcurrently occupies in GPU memory.- Return type:
- abstract get_device_id()[source]¶
Returns the identifier of the device (GPU) where the tensors are stored.
- Return type:
- abstract update_libhandle(libhandle)[source]¶
Update the
CuTensorNetHandleused byself. Multiple objects may use the same handle.- Parameters:
libhandle (
CuTensorNetHandle) – The new cuTensorNet library handle.- Raises:
RuntimeError – If the device (GPU) where
libhandlewas initialised does not match the one where the tensors ofselfare stored.- Return type:
- class pytket.extensions.cutensornet.structured_state.TTNxGate(libhandle, qubit_partition, config, bits=None)[source]¶
Implements a gate-by-gate contraction algorithm to calculate the output state of a circuit as a
TTN.- __init__(libhandle, qubit_partition, config, bits=None)¶
Initialise a TTN on the computational state
|0>.Note
A
libhandleshould be created via awith CuTensorNet() as libhandle:statement. The device where the TTN is stored will match the one specified by the library handle.The current implementation requires the keys of
qubit_partitionto be integers from0to2^l - 1for somel.- Parameters:
libhandle (
CuTensorNetHandle) – The cuTensorNet library handle that will be used to carry out tensor operations on the TTN.qubit_partition (
dict[int,list[Qubit]]) – A partition of the qubits in the circuit into disjoint groups, describing the hierarchical structure of the TTN. Each key identifies a leaf of the TTN, with its corresponding value indicating the list of qubits represented by the leaf. The leaves are numbered from left to right on a planar representation of the tree. Hence, the smaller half of the keys correspond to leaves in the left subtree and the rest are in the right subtree; providing recursive bipartitions.config (
Config) – The object describing the configuration for simulation.
- Raises:
ValueError – If the keys of
qubit_partitiondo not range from0to2^l - 1for somel.ValueError – If a
Qubitis repeated inqubit_partition.
- class pytket.extensions.cutensornet.structured_state.MPSxGate(libhandle, qubits, config, bits=None)[source]¶
Implements a gate-by-gate contraction algorithm to calculate the output state of a circuit as an
MPS. The algorithm is described in: https://arxiv.org/abs/2002.07730- __init__(libhandle, qubits, config, bits=None)¶
Initialise an MPS on the computational state
|0>Note
A
libhandleshould be created via awith CuTensorNet() as libhandle:statement. The device where the MPS is stored will match the one specified by the library handle.- Parameters:
libhandle (
CuTensorNetHandle) – The cuTensorNet library handle that will be used to carry out tensor operations on the MPS.qubits (
list[Qubit]) – The list of qubits in the circuit to be simulated.config (
Config) – The object describing the configuration for simulation.
- add_qubit(new_qubit, position, state=0)¶
Adds a qubit at the specified position.
- Parameters:
- Return type:
MPS- Returns:
self, to allow for method chaining.- Raises:
ValueError – If
new_qubitalready exists in the state.ValueError – If
positionis negative or larger thanlen(self).ValueError – If
stateis not0or1.
- get_entanglement_entropy(position)[source]¶
Returns the entanglement entropy of the virtual bond to the right of
position.- Parameters:
position (
int) – A position in the MPS.- Return type:
- Returns:
The entanglement entropy.
- Raises:
RuntimeError – If
positionis out of bounds.
- class pytket.extensions.cutensornet.structured_state.MPSxMPO(libhandle, qubits, config, bits=None)[source]¶
Implements a batched–gate contraction algorithm (DMRG-like) to calculate the output state of a circuit as an
MPS. The algorithm is described in: https://arxiv.org/abs/2207.05612.- __init__(libhandle, qubits, config, bits=None)[source]¶
Initialise an MPS on the computational state
|0>.Note
A
libhandleshould be created via awith CuTensorNet() as libhandle:statement. The device where the MPS is stored will match the one specified by the library handle.- Parameters:
libhandle (
CuTensorNetHandle) – The cuTensorNet library handle that will be used to carry out tensor operations on the MPS.qubits (
list[Qubit]) – The list of qubits in the circuit to be simulated.config (
Config) – The object describing the configuration for simulation.
Miscellaneous¶
- pytket.extensions.cutensornet.structured_state.prepare_circuit_mps(circuit)[source]¶
Adds SWAP gates to the circuit so that all gates act on adjacent qubits.
The qubits in the output circuit will be renamed. Implicit SWAPs may be added to the circuit, meaning that the logical qubit held at the
node[i]qubit at the beginning of the circuit may differ from the one it holds at the end. Consider applyingapply_qubit_relabellingon the MPS after simulation.Note
This preprocessing is not required by the MPS algorithms we provide. The current implementation of
vdotis not compatible withprepare_circuit_mpsand may lead to aRuntimeErrorwhen used. Shallow circuits tend to run faster if this preprocessing is not used. In occassions, it has been shown to improve runtime for deep circuits.