Components¶
The Qibo package comes with the following modules:
Models¶
Qibo provides models for both the circuit based and the adiabatic quantum
computation paradigms. Circuit based models include General circuit models which
allow defining arbitrary circuits and Application specific models such as the
Quantum Fourier Transform (qibo.models.QFT
) and the
Variational Quantum Eigensolver (qibo.models.VQE
).
Adiabatic quantum computation is simulated using the Time evolution
of state vectors.
The general purpose model is called Circuit
and holds the list of gates
that are applied to the state vector or density matrix. All Circuit
models
inherit the qibo.abstractions.circuit.AbstractCircuit
which implements basic
properties of the circuit, such as the list of gates and the number of qubits.
In order to perform calculations and apply gates to a state vector a backend
has to be used. The main Circuit
used for simulation is defined in
qibo.core.circuit.Circuit
. This uses an abstract backend object K
to perform calculation which can be one of the backends defined in qibo/backends
.
General circuit models¶
- class qibo.abstractions.circuit.AbstractCircuit(nqubits)¶
Circuit object which holds a list of gates.
This circuit is symbolic and cannot perform calculations. A specific backend has to be used for performing calculations. All backend-based circuits should inherit
AbstractCircuit
.Qibo provides the following circuits: A state vector simulation circuit:
qibo.core.circuit.Circuit
, a density matrix simulation circuit:qibo.core.circuit.DensityMatrixCircuit
and a circuit that distributes state vector simulation on multiple devices:qibo.core.distcircuit.DistributedCircuit
. All circuits use core as the computation backend.- Parameters
nqubits (int) – Total number of qubits in the circuit.
- on_qubits(*q)¶
Generator of gates contained in the circuit acting on specified qubits.
Useful for adding a circuit as a subroutine in a larger circuit.
- Parameters
q (int) – Qubit ids that the gates should act.
Example
from qibo import gates, models # create small circuit on 4 qubits smallc = models.Circuit(4) smallc.add((gates.RX(i, theta=0.1) for i in range(4))) smallc.add((gates.CNOT(0, 1), gates.CNOT(2, 3))) # create large circuit on 8 qubits largec = models.Circuit(8) largec.add((gates.RY(i, theta=0.1) for i in range(8))) # add the small circuit to the even qubits of the large one largec.add(smallc.on_qubits(*range(0, 8, 2)))
- copy(deep: bool = False)¶
Creates a copy of the current
circuit
as a newCircuit
model.- Parameters
deep (bool) – If
True
copies of the gate objects will be created for the new circuit. IfFalse
, the same gate objects ofcircuit
will be used.- Returns
The copied circuit object.
- invert()¶
Creates a new
Circuit
that is the inverse of the original.Inversion is obtained by taking the dagger of all gates in reverse order. If the original circuit contains measurement gates, these are included in the inverted circuit.
- Returns
The circuit inverse.
- decompose(*free: int)¶
Decomposes circuit’s gates to gates supported by OpenQASM.
- Parameters
free – Ids of free (work) qubits to use for gate decomposition.
- Returns
Circuit that contains only gates that are supported by OpenQASM and has the same effect as the original circuit.
- with_noise(noise_map: Union[Tuple[int, int, int], Dict[int, Tuple[int, int, int]]])¶
Creates a copy of the circuit with noise gates after each gate.
If the original circuit uses state vectors then noise simulation will be done using sampling and repeated circuit execution. In order to use density matrices the original circuit should be created using the
density_matrix
flag set toTrue
. For more information we refer to the How to perform noisy simulation? example.- Parameters
noise_map (dict) – Dictionary that maps qubit ids to noise probabilities (px, py, pz). If a tuple of probabilities (px, py, pz) is given instead of a dictionary, then the same probabilities will be used for all qubits.
- Returns
Circuit object that contains all the gates of the original circuit and additional noise channels on all qubits after every gate.
Example
from qibo.models import Circuit from qibo import gates # use density matrices for noise simulation c = Circuit(2, density_matrix=True) c.add([gates.H(0), gates.H(1), gates.CNOT(0, 1)]) noise_map = {0: (0.1, 0.0, 0.2), 1: (0.0, 0.2, 0.1)} noisy_c = c.with_noise(noise_map) # ``noisy_c`` will be equivalent to the following circuit c2 = Circuit(2, density_matrix=True) c2.add(gates.H(0)) c2.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c2.add(gates.H(1)) c2.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1)) c2.add(gates.CNOT(0, 1)) c2.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c2.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1))
- check_measured(gate_qubits: Tuple[int])¶
Helper method for add.
Checks if the qubits that a gate acts are already measured and raises a NotImplementedError if they are because currently we do not allow measured qubits to be reused.
- add(gate)¶
Add a gate to a given queue.
- Parameters
gate (
qibo.abstractions.gates.Gate
) – the gate object to add. See Gates for a list of available gates. gate can also be an iterable or generator of gates. In this case all gates in the iterable will be added in the circuit.- Returns
If the circuit contains measurement gates with
collapse=True
asympy.Symbol
that parametrizes the corresponding outcome.
- set_nqubits(gate: qibo.abstractions.abstract_gates.Gate)¶
Sets the number of qubits and prepares all gates.
Helper method for
circuit.add(gate)
.
- property ngates: int¶
Total number of gates/operations in the circuit.
- property depth: int¶
Circuit depth if each gate is placed at the earliest possible position.
- property gate_types: collections.Counter¶
collections.Counter
with the number of appearances of each gate type.The QASM names are used as gate identifiers.
- gates_of_type(gate: Union[str, type]) → List[Tuple[int, qibo.abstractions.abstract_gates.Gate]]¶
Finds all gate objects of specific type.
- set_parameters(parameters)¶
Updates the parameters of the circuit’s parametrized gates.
For more information on how to use this method we refer to the How to use parametrized gates? example.
- Parameters
parameters – Container holding the new parameter values. It can have one of the following types: List with length equal to the number of parametrized gates and each of its elements compatible with the corresponding gate. Dictionary with keys that are references to the parametrized gates and values that correspond to the new parameters for each gate. Flat list with length equal to the total number of free parameters in the circuit. A backend supported tensor (for example
np.ndarray
ortf.Tensor
) may also be given instead of a flat list.
Example
from qibo.models import Circuit from qibo import gates # create a circuit with all parameters set to 0. c = Circuit(3, accelerators) c.add(gates.RX(0, theta=0)) c.add(gates.RY(1, theta=0)) c.add(gates.CZ(1, 2)) c.add(gates.fSim(0, 2, theta=0, phi=0)) c.add(gates.H(2)) # set new values to the circuit's parameters using list params = [0.123, 0.456, (0.789, 0.321)] c.set_parameters(params) # or using dictionary params = {c.queue[0]: 0.123, c.queue[1]: 0.456 c.queue[3]: (0.789, 0.321)} c.set_parameters(params) # or using flat list (or an equivalent `np.array`/`tf.Tensor`) params = [0.123, 0.456, 0.789, 0.321] c.set_parameters(params)
- get_parameters(format: str = 'list', include_not_trainable: bool = False) → Union[List, Dict]¶
Returns the parameters of all parametrized gates in the circuit.
Inverse method of
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
.- Parameters
format (str) – How to return the variational parameters. Available formats are
'list'
,'dict'
and'flatlist'
. Seeqibo.abstractions.circuit.AbstractCircuit.set_parameters()
for more details on each format. Default is'list'
.include_not_trainable (bool) – If
True
it includes the parameters of non-trainable parametrized gates in the returned list or dictionary. Default isFalse
.
- summary() → str¶
Generates a summary of the circuit.
The summary contains the circuit depths, total number of qubits and the all gates sorted in decreasing number of appearance.
Example
from qibo.models import Circuit from qibo import gates c = Circuit(3) c.add(gates.H(0)) c.add(gates.H(1)) c.add(gates.CNOT(0, 2)) c.add(gates.CNOT(1, 2)) c.add(gates.H(2)) c.add(gates.TOFFOLI(0, 1, 2)) print(c.summary()) # Prints ''' Circuit depth = 5 Total number of gates = 7 Number of qubits = 3 Most common gates: h: 3 cx: 2 ccx: 1 '''
- abstract fuse()¶
Creates an equivalent
Circuit
with gates fused up to two-qubits.- Returns
The equivalent
Circuit
object where the gates are fused.
Example
from qibo import models, gates c = models.Circuit(2) c.add([gates.H(0), gates.H(1)]) c.add(gates.CNOT(0, 1)) c.add([gates.Y(0), gates.Y(1)]) # create circuit with fused gates fused_c = c.fuse() # now ``fused_c`` contains only one ``gates.Unitary`` gate # that is equivalent to applying the five gates of the original # circuit.
- abstract property final_state¶
Returns the final state after full simulation of the circuit.
If the circuit is executed more than once, only the last final state is returned.
- abstract execute(initial_state=None, nshots=None)¶
Executes the circuit. Exact implementation depends on the backend.
See
qibo.core.circuit.Circuit.execute()
for more details.
- to_qasm()¶
Convert circuit to QASM.
- Parameters
filename (str) – The filename where the code is saved.
- classmethod from_qasm(qasm_code: str, **kwargs)¶
Constructs a circuit from QASM code.
- Parameters
qasm_code (str) – String with the QASM script.
- Returns
A
qibo.abstractions.circuit.AbstractCircuit
that contains the gates specified by the given QASM script.
Example
from qibo import models, gates qasm_code = '''OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; h q[1]; cx q[0],q[1];''' c = models.Circuit.from_qasm(qasm_code) # is equivalent to creating the following circuit c2 = models.Circuit(2) c2.add(gates.H(0)) c2.add(gates.H(1)) c2.add(gates.CNOT(0, 1))
- class qibo.core.circuit.Circuit(nqubits)¶
Backend implementation of
qibo.abstractions.circuit.AbstractCircuit
.Performs simulation using state vectors.
Example
from qibo import models, gates c = models.Circuit(3) # initialized circuit with 3 qubits c.add(gates.H(0)) # added Hadamard gate on qubit 0
- Parameters
nqubits (int) – Total number of qubits in the circuit.
- set_nqubits(gate)¶
Sets the number of qubits and prepares all gates.
Helper method for
circuit.add(gate)
.
- fuse()¶
Creates an equivalent
Circuit
with gates fused up to two-qubits.- Returns
The equivalent
Circuit
object where the gates are fused.
Example
from qibo import models, gates c = models.Circuit(2) c.add([gates.H(0), gates.H(1)]) c.add(gates.CNOT(0, 1)) c.add([gates.Y(0), gates.Y(1)]) # create circuit with fused gates fused_c = c.fuse() # now ``fused_c`` contains only one ``gates.Unitary`` gate # that is equivalent to applying the five gates of the original # circuit.
- compile()¶
Compiles the circuit as a Tensorflow graph.
- execute(initial_state=None, nshots=None)¶
Propagates the state through the circuit applying the corresponding gates.
If channels are found within the circuits gates then Qibo will perform the simulation by repeating the circuit execution
nshots
times. If the circuit contains measurements the corresponding noisy measurement result will be returned, otherwise the final state vectors will be collected to a(nshots, 2 ** nqubits)
tensor and returned. The latter usage is memory intensive and not recommended. If the circuit is created with thedensity_matrix = True
flag and contains channels, then density matrices will be used instead of repeated execution. Note that some channels (qibo.abstractions.gates.KrausChannel
) can only be simulated using density matrices and not repeated execution. For more details on noise simulation with and without density matrices we refer to How to perform noisy simulation?- Parameters
initial_state (array) – Initial state vector as a numpy array of shape
(2 ** nqubits,)
. A Tensorflow tensor with shapenqubits * (2,)
is also allowed allowed as an initial state but must have the dtype of the circuit. Ifinitial_state
isNone
the |000…0> state will be used.nshots (int) – Number of shots to sample if the circuit contains measurement gates. If
nshots
isNone
the measurement gates will be ignored.
- Returns
A
qibo.abstractions.states.AbstractState
object which holds the final state vector as a tensor of shape(2 ** nqubits,)
or the final density matrix as a tensor of shpae(2 ** nqubits, 2 ** nqubits)
. Ifnshots
is given and the circuit contains measurements the returned circuit object also contains the measured bitstrings.
- property final_state¶
Final state as a tensor of shape
(2 ** nqubits,)
.The circuit has to be executed at least once before accessing this property, otherwise a
ValueError
is raised. If the circuit is executed more than once, only the last final state is returned.
- class qibo.core.circuit.DensityMatrixCircuit(nqubits)¶
Backend implementation of
qibo.abstractions.circuit.AbstractCircuit
.Performs simulation using density matrices. Can be initialized using the
density_matrix=True
flag and supports the use of channels. For more information on the use of density matrices we refer to the Using density matrices? example.Example
from qibo import models, gates c = models.Circuit(2, density_matrix=True) c.add(gates.H(0)) c.add(gates.PauliNoiseChannel(1, px=0.2))
- Parameters
nqubits (int) – Total number of qubits in the circuit.
- class qibo.tensorflow.distcircuit.DistributedCircuit(nqubits: int, accelerators: Dict[str, int], memory_device: str = '/CPU:0')¶
Distributed implementation of
qibo.abstractions.circuit.AbstractCircuit
in Tensorflow.Uses multiple accelerator devices (GPUs) for applying gates to the state vector. The full state vector is saved in the given memory device (usually the CPU) during the simulation. A gate is applied by splitting the state to pieces and copying each piece to an accelerator device that is used to perform the matrix multiplication. An accelerator device can be used more than once resulting to logical devices that are more than the physical accelerators in the system.
Distributed circuits currently do not support native tensorflow gates, compilation and callbacks.
Example
from qibo.models import Circuit # The system has two GPUs and we would like to use each GPU twice # resulting to four total logical accelerators accelerators = {'/GPU:0': 2, '/GPU:1': 2} # Define a circuit on 32 qubits to be run in the above GPUs keeping # the full state vector in the CPU memory. c = Circuit(32, accelerators, memory_device="/CPU:0")
- Parameters
nqubits (int) – Total number of qubits in the circuit.
accelerators (dict) – Dictionary that maps device names to the number of times each device will be used. The total number of logical devices must be a power of 2.
memory_device (str) – Name of the device where the full state will be saved (usually the CPU).
- set_nqubits(gate)¶
Sets the number of qubits and prepares all gates.
Helper method for
circuit.add(gate)
.
- on_qubits(*q)¶
Generator of gates contained in the circuit acting on specified qubits.
Useful for adding a circuit as a subroutine in a larger circuit.
- Parameters
q (int) – Qubit ids that the gates should act.
Example
from qibo import gates, models # create small circuit on 4 qubits smallc = models.Circuit(4) smallc.add((gates.RX(i, theta=0.1) for i in range(4))) smallc.add((gates.CNOT(0, 1), gates.CNOT(2, 3))) # create large circuit on 8 qubits largec = models.Circuit(8) largec.add((gates.RY(i, theta=0.1) for i in range(8))) # add the small circuit to the even qubits of the large one largec.add(smallc.on_qubits(*range(0, 8, 2)))
- copy(deep: bool = True)¶
Creates a copy of the current
circuit
as a newCircuit
model.- Parameters
deep (bool) – If
True
copies of the gate objects will be created for the new circuit. IfFalse
, the same gate objects ofcircuit
will be used.- Returns
The copied circuit object.
- fuse()¶
Creates an equivalent
Circuit
with gates fused up to two-qubits.- Returns
The equivalent
Circuit
object where the gates are fused.
Example
from qibo import models, gates c = models.Circuit(2) c.add([gates.H(0), gates.H(1)]) c.add(gates.CNOT(0, 1)) c.add([gates.Y(0), gates.Y(1)]) # create circuit with fused gates fused_c = c.fuse() # now ``fused_c`` contains only one ``gates.Unitary`` gate # that is equivalent to applying the five gates of the original # circuit.
- with_noise(noise_map, measurement_noise=None)¶
Creates a copy of the circuit with noise gates after each gate.
If the original circuit uses state vectors then noise simulation will be done using sampling and repeated circuit execution. In order to use density matrices the original circuit should be created using the
density_matrix
flag set toTrue
. For more information we refer to the How to perform noisy simulation? example.- Parameters
noise_map (dict) – Dictionary that maps qubit ids to noise probabilities (px, py, pz). If a tuple of probabilities (px, py, pz) is given instead of a dictionary, then the same probabilities will be used for all qubits.
- Returns
Circuit object that contains all the gates of the original circuit and additional noise channels on all qubits after every gate.
Example
from qibo.models import Circuit from qibo import gates # use density matrices for noise simulation c = Circuit(2, density_matrix=True) c.add([gates.H(0), gates.H(1), gates.CNOT(0, 1)]) noise_map = {0: (0.1, 0.0, 0.2), 1: (0.0, 0.2, 0.1)} noisy_c = c.with_noise(noise_map) # ``noisy_c`` will be equivalent to the following circuit c2 = Circuit(2, density_matrix=True) c2.add(gates.H(0)) c2.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c2.add(gates.H(1)) c2.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1)) c2.add(gates.CNOT(0, 1)) c2.add(gates.PauliNoiseChannel(0, 0.1, 0.0, 0.2)) c2.add(gates.PauliNoiseChannel(1, 0.0, 0.2, 0.1))
- execute(initial_state=None, nshots=None)¶
Equivalent to
qibo.core.circuit.Circuit.execute()
.- Returns
A
qibo.core.states.DistributedState
object corresponding to the final state of execution. Note that this state contains the full state vector scattered to pieces and does not create a single tensor unless the user explicitly calls thetensor
property. This avoids creating multiple copies of large states in CPU memory.
Application specific models¶
Circuit addition¶
Circuit
objects also support addition. For example
from qibo import models
from qibo import gates
c1 = models.QFT(4)
c2 = models.Circuit(4)
c2.add(gates.RZ(0, 0.1234))
c2.add(gates.RZ(1, 0.1234))
c2.add(gates.RZ(2, 0.1234))
c2.add(gates.RZ(3, 0.1234))
c = c1 + c2
will create a circuit that performs the Quantum Fourier Transform on four qubits followed by Rotation-Z gates.
Circuit fusion¶
The gates contained in a circuit can be fused up to two-qubits using the
qibo.abstractions.circuit.AbstractCircuit.fuse()
method. This returns a new circuit
that contains qibo.abstractions.gates.Unitary
gates that are less in number
than the gates in the original circuit but have equivalent action.
For some circuits (such as variational), if the number of qubits is large it is
more efficient to execute the fused instead of the original circuit.
The fusion algorithm starts by creating a qibo.abstractions.fusion.FusionGroup
.
The first available gates in the circuit’s gate queue are added in the group
until the two qubits of the group are identified. Any subsequent one-qubit gate
applied in one of these qubits or two-qubit gates applied to these two qubits
are added in the group. Gates that affect more than two qubits or target
different qubits are left for the next round of fusion. Once all compatible gates
are added in the group the fusion round finishes and a new FusionGroup
is
created for the next round. The algorithm terminates once all gates are assigned
to a group.
A FusionGroup
can either start with any one- or two-qubit gate
except CNOT
, CZ
, SWAP
and CU1
because it is more efficient
to apply such gates on their own rather than fusing them with others. These gates
are fused only when “sandwiched” between one-qubit gates. For example
c.add([gates.H(0), gates.H(1)])
c.add(gates.CZ(0, 1))
c.add([gates.X(0), gates.Y(1)])
will be fused to a single Unitary(0, 1)
gate, while
c.add([gates.H(0), gates.H(1)])
c.add(gates.CZ(0, 1))
will remain as it is.
Once groups are identified, all gates belonging to a FusionGroup
are fused
by multiplying their respective unitary matrices. This way each group results
to a new qibo.abstractions.gates.Unitary
gate that is equivalent to applying
all the gates in the group.
- class qibo.core.fusion.FusionGroup¶
Group of one-qubit and two-qubit gates that act in two specific gates.
These gates can be fused into a single two-qubit gate represented by a general 4x4 matrix.
- Parameters
qubit0 (int) – Id of the first qubit that the
FusionGroup
act.qubit1 (int) – Id of the first qubit that the
FusionGroup
act.gates0 (list) – List of lists of one-qubit gates to be applied to
qubit0
. One qubit gates are split in groups according to when the two qubit gates are applied (see example). Haslen(gates0) = len(two_qubit_gates) + 1
.gates1 (list) – Same as
gates0
but forqubit1
.two_qubit_gates (list) – List of two qubit gates acting on
qubit0
andqubit1
.
Example
queue = [gates.H(0), gates.H(1), gates.CNOT(0, 1), gates.X(0), gates.X(1)] group = fusion.FusionGroup.from_queue(queue) # results to the following values for the attributes: group.qubit0 = 0 group.qubit1 = 1 group.gates0 = [[gates.H(0)], [gates.X(0)]] group.gates1 = [[gates.H(1)], [gates.X(1)]] group.two_qubit_gates = [gates.CNOT(0, 1)]
- property qubits: Set[int]¶
Set of ids of the two qubits that the
FusionGroup
acts on.
- property gates: Tuple[Gate]¶
Tuple with fused gates.
These gates have equivalent action with all the original gates that were added in the
FusionGroup
.
- update() → Tuple[Gate]¶
Recalculates fused gates.
This is used automatically by circuit objects in order to repeat the calculation of fused gates after the parameters of original gates have been changed using
circuit.set_parameters
. It assumes that the parameters of the gate objects contained in the currentFusionGroup
have already been updated.
- is_efficient(gate: Gate) → bool¶
Checks if given two-qubit
gate
is efficient.Efficient gates are not fused if they are in the start or in the end.
- classmethod from_queue(queue: List[Gate]) → List[FusionGroup]¶
Fuses a queue of gates by combining up to two-qubit gates.
- Parameters
queue (list) – List of gates.
- Returns
List of
FusionGroup
objects that correspond to the fused gates.
- add(gate: Gate)¶
Adds a gate in the group.
- Raises
ValueError – If the gate cannot be added in the group (eg. because it acts on different qubits).
RuntimeError – If the group is completed.
- calculate()¶
Calculates fused gate.
Time evolution¶
Gates¶
All supported gates can be accessed from the qibo.gates
module and inherit
the base gate object qibo.abstractions.gates.Gate
. Read below for a complete
list of supported gates.
All gates support the controlled_by
method that allows to control
the gate on an arbitrary number of qubits. For example
gates.X(0).controlled_by(1, 2)
is equivalent togates.TOFFOLI(1, 2, 0)
,gates.RY(0, np.pi).controlled_by(1, 2, 3)
applies the Y-rotation to qubit 0 when qubits 1, 2 and 3 are in the |111> state.gates.SWAP(0, 1).controlled_by(3, 4)
swaps qubits 0 and 1 when qubits 3 and 4 are in the |11> state.
- class qibo.abstractions.gates.X(q)¶
The Pauli X gate.
- Parameters
q (int) – the qubit id number.
- decompose(*free: int, use_toffolis: bool = True) → List[qibo.abstractions.abstract_gates.Gate]¶
Decomposes multi-control
X
gate to one-qubit,CNOT
andTOFFOLI
gates.- Parameters
free – Ids of free qubits to use for the gate decomposition.
use_toffolis – If
True
the decomposition contains onlyTOFFOLI
gates. IfFalse
a congruent representation is used forTOFFOLI
gates. Seeqibo.abstractions.gates.TOFFOLI
for more details on this representation.
- Returns
List with one-qubit,
CNOT
andTOFFOLI
gates that have the same effect as applying the original multi-control gate.
- class qibo.abstractions.gates.M(*q, register_name: Optional[str] = None, collapse: bool = False, p0: Optional[ProbsType] = None, p1: Optional[ProbsType] = None)¶
The Measure Z gate.
- Parameters
*q (int) – id numbers of the qubits to measure. It is possible to measure multiple qubits using
gates.M(0, 1, 2, ...)
. If the qubits to measure are held in an iterable (eg. list) the*
operator can be used, for examplegates.M(*[0, 1, 4])
orgates.M(*range(5))
.register_name (str) – Optional name of the register to distinguish it from other registers when used in circuits.
collapse (bool) – Collapse the state vector after the measurement is performed. Can be used only for single shot measurements. If
True
the collapsed state vector is returned. IfFalse
the measurement result is returned.p0 (dict) – Optional bitflip probability map. Can be: A dictionary that maps each measured qubit to the probability that it is flipped, a list or tuple that has the same length as the tuple of measured qubits or a single float number. If a single float is given the same probability will be used for all qubits.
p1 (dict) – Optional bitflip probability map for asymmetric bitflips. Same as
p0
but controls the 1->0 bitflip probability. Ifp1
isNone
thenp0
will be used both for 0->1 and 1->0 bitflips.
- static einsum_string(qubits, nqubits, measuring=False)¶
Generates einsum string for partial trace of density matrices.
- Parameters
- Returns
String to use in einsum for performing partial density of a density matrix.
- symbol()¶
Returns symbol containing measurement outcomes for
collapse=True
gates.
- add(gate: qibo.abstractions.gates.M)¶
Adds target qubits to a measurement gate.
This method is only used for creating the global measurement gate used by the models.Circuit. The user is not supposed to use this method and a ValueError is raised if he does so.
- Parameters
gate – Measurement gate to add its qubits in the current gate.
- class qibo.abstractions.gates.RX(q, theta, trainable=True)¶
Rotation around the X-axis of the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} \cos \frac{\theta }{2} & -i\sin \frac{\theta }{2} \\ -i\sin \frac{\theta }{2} & \cos \frac{\theta }{2} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.RY(q, theta, trainable=True)¶
Rotation around the Y-axis of the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} \cos \frac{\theta }{2} & -\sin \frac{\theta }{2} \\ \sin \frac{\theta }{2} & \cos \frac{\theta }{2} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.RZ(q, theta, trainable=True)¶
Rotation around the Z-axis of the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} e^{-i \theta / 2} & 0 \\ 0 & e^{i \theta / 2} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.U1(q, theta, trainable=True)¶
First general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 \\ 0 & e^{i \theta} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.U2(q, phi, lam, trainable=True)¶
Second general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\frac{1}{\sqrt{2}} \begin{pmatrix} e^{-i(\phi + \lambda )/2} & -e^{-i(\phi - \lambda )/2} \\ e^{i(\phi - \lambda )/2} & e^{i (\phi + \lambda )/2} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
phi (float) – first rotation angle.
lamb (float) – second rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.U3(q, theta, phi, lam, trainable=True)¶
Third general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} e^{-i(\phi + \lambda )/2}\cos\left (\frac{\theta }{2}\right ) & -e^{-i(\phi - \lambda )/2}\sin\left (\frac{\theta }{2}\right ) \\ e^{i(\phi - \lambda )/2}\sin\left (\frac{\theta }{2}\right ) & e^{i (\phi + \lambda )/2}\cos\left (\frac{\theta }{2}\right ) \\ \end{pmatrix}\end{split}\]
- class qibo.abstractions.gates.ZPow(q, theta, trainable=True)¶
Equivalent to
qibo.abstractions.gates.U1
.Implemented to maintain compatibility with previous versions. Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 \\ 0 & e^{i \theta} \\ \end{pmatrix}\end{split}\]- Parameters
q (int) – the qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CNOT(q0, q1)¶
The Controlled-NOT gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ \end{pmatrix}\end{split}\]- decompose(*free, use_toffolis: bool = True) → List[qibo.abstractions.abstract_gates.Gate]¶
Decomposes multi-control gates to gates supported by OpenQASM.
Decompositions are based on arXiv:9503016.
- Parameters
free – Ids of free qubits to use for the gate decomposition.
- Returns
List with gates that have the same effect as applying the original gate.
- class qibo.abstractions.gates.CZ(q0, q1)¶
The Controlled-Phase gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & -1 \\ \end{pmatrix}\end{split}\]
- class qibo.abstractions.gates.CRX(q0, q1, theta, trainable=True)¶
Controlled rotation around the X-axis for the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \cos \frac{\theta }{2} & -i\sin \frac{\theta }{2} \\ 0 & 0 & -i\sin \frac{\theta }{2} & \cos \frac{\theta }{2} \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CRY(q0, q1, theta, trainable=True)¶
Controlled rotation around the X-axis for the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \cos \frac{\theta }{2} & -\sin \frac{\theta }{2} \\ 0 & 0 & \sin \frac{\theta }{2} & \cos \frac{\theta }{2} \\ \end{pmatrix}\end{split}\]Note that this differs from the
qibo.abstractions.gates.RZ
gate.- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CRZ(q0, q1, theta, trainable=True)¶
Controlled rotation around the X-axis for the Bloch sphere.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & e^{-i \theta / 2} & 0 \\ 0 & 0 & 0 & e^{i \theta / 2} \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CU1(q0, q1, theta, trainable=True)¶
Controlled first general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i \theta } \\ \end{pmatrix}\end{split}\]Note that this differs from the
qibo.abstractions.gates.CRZ
gate.- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CU2(q0, q1, phi, lam, trainable=True)¶
Controlled second general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\frac{1}{\sqrt{2}} \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & e^{-i(\phi + \lambda )/2} & -e^{-i(\phi - \lambda )/2} \\ 0 & 0 & e^{i(\phi - \lambda )/2} & e^{i (\phi + \lambda )/2} \\ \end{pmatrix}\end{split}\]- Parameters
- class qibo.abstractions.gates.CU3(q0, q1, theta, phi, lam, trainable=True)¶
Controlled third general unitary gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & e^{-i(\phi + \lambda )/2}\cos\left (\frac{\theta }{2}\right ) & -e^{-i(\phi - \lambda )/2}\sin\left (\frac{\theta }{2}\right ) \\ 0 & 0 & e^{i(\phi - \lambda )/2}\sin\left (\frac{\theta }{2}\right ) & e^{i (\phi + \lambda )/2}\cos\left (\frac{\theta }{2}\right ) \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – first rotation angle.
phi (float) – second rotation angle.
lamb (float) – third rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.CZPow(q0, q1, theta, trainable=True)¶
Equivalent to
qibo.abstractions.gates.CU1
.Implemented to maintain compatibility with previous versions. Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i \theta } \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the control qubit id number.
q1 (int) – the target qubit id number.
theta (float) – the rotation angle.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.SWAP(q0, q1)¶
The swap gate.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ \end{pmatrix}\end{split}\]
- class qibo.abstractions.gates.fSim(q0, q1, theta, phi, trainable=True)¶
The fSim gate defined in arXiv:2001.08343.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \theta & -i\sin \theta & 0 \\ 0 & -i\sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & e^{-i \phi } \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the first qubit to be swapped id number.
q1 (int) – the second qubit to be swapped id number.
theta (float) – Angle for the one-qubit rotation.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- class qibo.abstractions.gates.GeneralizedfSim(q0, q1, unitary, phi, trainable=True)¶
The fSim gate with a general rotation.
Corresponds to the following unitary matrix
\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & R_{00} & R_{01} & 0 \\ 0 & R_{10} & R_{11} & 0 \\ 0 & 0 & 0 & e^{-i \phi } \\ \end{pmatrix}\end{split}\]- Parameters
q0 (int) – the first qubit to be swapped id number.
q1 (int) – the second qubit to be swapped id number.
unitary (np.ndarray) – Unitary that corresponds to the one-qubit rotation.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).
- property parameters¶
Returns a tuple containing the current value of gate’s parameters.
- class qibo.abstractions.gates.TOFFOLI(q0, q1, q2)¶
The Toffoli gate.
- Parameters
- decompose(*free, use_toffolis: bool = True) → List[qibo.abstractions.abstract_gates.Gate]¶
Decomposes multi-control gates to gates supported by OpenQASM.
Decompositions are based on arXiv:9503016.
- Parameters
free – Ids of free qubits to use for the gate decomposition.
- Returns
List with gates that have the same effect as applying the original gate.
- congruent(use_toffolis: bool = True) → List[qibo.abstractions.abstract_gates.Gate]¶
Congruent representation of
TOFFOLI
gate.This is a helper method for the decomposition of multi-control
X
gates. The congruent representation is based on Sec. 6.2 of arXiv:9503016. The sequence of the gates produced here has the same effect asTOFFOLI
with the phase of the |101> state reversed.- Parameters
use_toffolis – If
True
a singleTOFFOLI
gate is returned. IfFalse
the congruent representation is returned.- Returns
List with
RY
andCNOT
gates that have the same effect as applying the originalTOFFOLI
gate.
- class qibo.abstractions.gates.Unitary(unitary, *q, trainable=True, name=None)¶
Arbitrary unitary gate.
- Parameters
unitary – Unitary matrix as a tensor supported by the backend. Note that there is no check that the matrix passed is actually unitary. This allows the user to create non-unitary gates.
*q (int) – Qubit id numbers that the gate acts on.
trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).name (str) – Optional name for the gate.
- class qibo.abstractions.gates.VariationalLayer(qubits: List[int], pairs: List[Tuple[int, int]], one_qubit_gate, two_qubit_gate, params: List[float], params2: Optional[List[float]] = None, trainable: bool = True, name: Optional[str] = None)¶
Layer of one-qubit parametrized gates followed by two-qubit entangling gates.
Performance is optimized by fusing the variational one-qubit gates with the two-qubit entangling gates that follow them and applying a single layer of two-qubit gates as 4x4 matrices.
- Parameters
qubits (list) – List of one-qubit gate target qubit IDs.
pairs (list) – List of pairs of qubit IDs on which the two qubit gate act.
one_qubit_gate – Type of one qubit gate to use as the variational gate.
two_qubit_gate – Type of two qubit gate to use as entangling gate.
params (list) – Variational parameters of one-qubit gates as a list that has the same length as
qubits
. These gates act before the layer of entangling gates.params2 (list) – Variational parameters of one-qubit gates as a list that has the same length as
qubits
. These gates act after the layer of entangling gates.trainable (bool) – whether gate parameters can be updated using
qibo.abstractions.circuit.AbstractCircuit.set_parameters()
(default isTrue
).name (str) – Optional name for the gate. If
None
the name"VariationalLayer"
will be used.
Example
import numpy as np from qibo.models import Circuit from qibo import gates # generate an array of variational parameters for 8 qubits theta = 2 * np.pi * np.random.random(8) # define qubit pairs that two qubit gates will act pairs = [(i, i + 1) for i in range(0, 7, 2)] # map variational parameters to qubit IDs theta_map = {i: th for i, th in enumerate(theta} # define a circuit of 8 qubits and add the variational layer c = Circuit(8) c.add(gates.VariationalLayer(pairs, gates.RY, gates.CZ, theta_map)) # this will create an optimized version of the following circuit c2 = Circuit(8) c.add((gates.RY(i, th) for i, th in enumerate(theta))) c.add((gates.CZ(i, i + 1) for i in range(7)))
- property parameters¶
Returns a tuple containing the current value of gate’s parameters.
- class qibo.abstractions.gates.Flatten(coefficients)¶
Passes an arbitrary state vector in the circuit.
- Parameters
coefficients (list) – list of the target state vector components. This can also be a tensor supported by the backend.
- class qibo.abstractions.gates.CallbackGate(callback: Callback)¶
Calculates a
qibo.core.callbacks.Callback
at a specific point in the circuit.This gate performs the callback calulation without affecting the state vector.
- Parameters
callback (
qibo.core.callbacks.Callback
) – Callback object to calculate.
- property nqubits: int¶
Number of qubits that this gate acts on.
Channels¶
Channels are implemented in Qibo as additional gates and can be accessed from
the qibo.gates
module. Channels can be used on density matrices to perform
noisy simulations. Channels that inherit qibo.abstractions.gates.UnitaryChannel
can also be applied to state vectors using sampling and repeated execution.
For more information on the use of channels to simulate noise we refer to
How to perform noisy simulation?
The following channels are currently implemented:
- class qibo.abstractions.gates.PartialTrace(*q)¶
Collapses a density matrix by tracing out selected qubits.
Works only with density matrices (not state vectors) and implements the following transformation:
\[\mathcal{E}(\rho ) = (|0\rangle \langle 0|) _A \otimes \mathrm{Tr} _A (\rho )\]where A denotes the subsystem of qubits that are traced out.
- Parameters
q (int) – Qubit ids that will be traced-out and collapsed to the zero state. More than one qubits can be given.
- class qibo.abstractions.gates.KrausChannel(ops)¶
General channel defined by arbitrary Krauss operators.
Implements the following transformation:
\[\mathcal{E}(\rho ) = \sum _k A_k \rho A_k^\dagger\]where A are arbitrary Kraus operators given by the user. Note that Kraus operators set should be trace preserving, however this is not checked. Simulation of this gate requires the use of density matrices. For more information on channels and Kraus operators please check J. Preskill’s notes.
- Parameters
ops (list) – List of Kraus operators as pairs
(qubits, Ak)
wherequbits
refers the qubit ids thatAk
acts on andAk
is the corresponding matrix as anp.ndarray
ortf.Tensor
.
Example
from qibo.models import Circuit from qibo import gates # initialize circuit with 3 qubits c = Circuit(3) # define a sqrt(0.4) * X gate a1 = np.sqrt(0.4) * np.array([[0, 1], [1, 0]]) # define a sqrt(0.6) * CNOT gate a2 = np.sqrt(0.6) * np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) # define the channel rho -> 0.4 X{1} rho X{1} + 0.6 CNOT{0, 2} rho CNOT{0, 2} channel = gates.GeneralChannel([((1,), a1), ((0, 2), a2)]) # add the channel to the circuit c.add(channel)
- class qibo.abstractions.gates.UnitaryChannel(p, ops, seed=None)¶
Channel that is a probabilistic sum of unitary operations.
Implements the following transformation:
\[\mathcal{E}(\rho ) = \left (1 - \sum _k p_k \right )\rho + \sum _k p_k U_k \rho U_k^\dagger\]where U are arbitrary unitary operators and p are floats between 0 and 1. Note that unlike
qibo.abstractions.gates.KrausChannel
which requires density matrices, it is possible to simulate the unitary channel using state vectors and probabilistic sampling. For more information on this approach we refer to Using repeated execution.- Parameters
p (list) – List of floats that correspond to the probability that each unitary Uk is applied.
ops (list) – List of operators as pairs
(qubits, Uk)
wherequbits
refers the qubit ids thatUk
acts on andUk
is the corresponding matrix as anp.ndarray
/tf.Tensor
. Must have the same length as the given probabilitiesp
.seed (int) – Optional seed for the random number generator when sampling instead of density matrices is used to simulate this gate.
- class qibo.abstractions.gates.PauliNoiseChannel(q, px=0, py=0, pz=0, seed=None)¶
Noise channel that applies Pauli operators with given probabilities.
Implements the following transformation:
\[\mathcal{E}(\rho ) = (1 - p_x - p_y - p_z) \rho + p_x X\rho X + p_y Y\rho Y + p_z Z\rho Z\]which can be used to simulate phase flip and bit flip errors. This channel can be simulated using either density matrices or state vectors and sampling with repeated execution. See How to perform noisy simulation? for more information.
- Parameters
q (int) – Qubit id that the noise acts on.
px (float) – Bit flip (X) error probability.
py (float) – Y-error probability.
pz (float) – Phase flip (Z) error probability.
seed (int) – Optional seed for the random number generator when sampling instead of density matrices is used to simulate this gate.
- class qibo.abstractions.gates.ResetChannel(q, p0=0.0, p1=0.0, seed=None)¶
Single-qubit reset channel.
Implements the following transformation:
\[\mathcal{E}(\rho ) = (1 - p_0 - p_1) \rho + p_0 (|0\rangle \langle 0| \otimes \tilde{\rho }) + p_1 (|1\rangle \langle 1| \otimes \tilde{\rho })\]with
\[\tilde{\rho } = \frac{\langle 0|\rho |0\rangle }{\mathrm{Tr}\langle 0|\rho |0\rangle}\]
- class qibo.abstractions.gates.ThermalRelaxationChannel(q, t1, t2, time, excited_population=0, seed=None)¶
Single-qubit thermal relaxation error channel.
Implements the following transformation:
If \(T_1 \geq T_2\):
\[\mathcal{E} (\rho ) = (1 - p_z - p_0 - p_1)\rho + p_zZ\rho Z + p_0 (|0\rangle \langle 0| \otimes \tilde{\rho }) + p_1 (|1\rangle \langle 1| \otimes \tilde{\rho })\]with
\[\tilde{\rho } = \frac{\langle 0|\rho |0\rangle }{\mathrm{Tr}\langle 0|\rho |0\rangle}\]while if \(T_1 < T_2\):
\[\mathcal{E}(\rho ) = \mathrm{Tr} _\mathcal{X}\left [\Lambda _{\mathcal{X}\mathcal{Y}}(\rho _\mathcal{X} ^T \otimes \mathbb{I}_\mathcal{Y})\right ]\]with
\[\begin{split}\Lambda = \begin{pmatrix} 1 - p_1 & 0 & 0 & e^{-t / T_2} \\ 0 & p_1 & 0 & 0 \\ 0 & 0 & p_0 & 0 \\ e^{-t / T_2} & 0 & 0 & 1 - p_0 \end{pmatrix}\end{split}\]where \(p_0 = (1 - e^{-t / T_1})(1 - \eta )\) \(p_1 = (1 - e^{-t / T_1})\eta\) and \(p_z = 1 - e^{-t / T_1} + e^{-t / T_2} - e^{t / T_1 - t / T_2}\). Here \(\eta\) is the
excited_population
and \(t\) is thetime
, both controlled by the user. This gate is based on Qiskit’s thermal relaxation error channel.- Parameters
q (int) – Qubit id that the noise channel acts on.
t1 (float) – T1 relaxation time. Should satisfy
t1 > 0
.t2 (float) – T2 dephasing time. Should satisfy
t1 > 0
andt2 < 2 * t1
.time (float) – the gate time for relaxation error.
excited_population (float) – the population of the excited state at equilibrium. Default is 0.
seed (int) – Optional seed for the random number generator when sampling instead of density matrices is used to simulate this gate.
Hamiltonians¶
The main abstract Hamiltonian object of Qibo is:
- class qibo.abstractions.hamiltonians.Hamiltonian(nqubits, matrix, numpy=False)¶
Abstract Hamiltonian operator using full matrix representation.
- Parameters
nqubits (int) – number of quantum bits.
matrix (np.ndarray) – Matrix representation of the Hamiltonian in the computational basis as an array of shape
(2 ** nqubits, 2 ** nqubits)
.numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise the selected backend is used. Default option isnumpy = False
.
- classmethod from_symbolic(symbolic_hamiltonian, symbol_map, numpy=False)¶
Creates a
Hamiltonian
from a symbolic Hamiltonian.We refer to the How to define custom Hamiltonians using symbols? example for more details.
- Parameters
symbolic_hamiltonian (sympy.Expr) – The full Hamiltonian written with symbols.
symbol_map (dict) – Dictionary that maps each symbol that appears in the Hamiltonian to a pair of (target, matrix).
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise the selected backend is used. Default option isnumpy = False
.
- Returns
A
qibo.abstractions.hamiltonians.Hamiltonian
object that implements the given symbolic Hamiltonian.
- abstract eigenvalues()¶
Computes the eigenvalues for the Hamiltonian.
- abstract eigenvectors()¶
Computes a tensor with the eigenvectors for the Hamiltonian.
- ground_state()¶
Computes the ground state of the Hamiltonian.
Uses the
eigenvectors
method and returns the lowest energy eigenvector.
- abstract exp(a)¶
Computes a tensor corresponding to exp(-1j * a * H).
- Parameters
a (complex) – Complex number to multiply Hamiltonian before exponentiation.
- abstract expectation(state, normalize=False)¶
Computes the real expectation value for a given state.
- Parameters
state (array) – the expectation state.
normalize (bool) – If
True
the expectation value is divided with the state’s norm squared.
- Returns
Real number corresponding to the expectation value.
Qibo provides an additional object that represents Hamiltonians without using their full matrix representation and can be used for time evolution using the Trotter decomposition. The Hamiltonians represented by this object are sums of commuting terms, following the description of Sec. 4.1 of arXiv:1901.05824.
- class qibo.abstractions.hamiltonians.TrotterHamiltonian(*parts, ground_state=None)¶
Hamiltonian operator used for Trotterized time evolution.
The Hamiltonian represented by this class has the form of Eq. (57) in arXiv:1901.05824.
- Parameters
*parts (dict) – Dictionary whose values are
qibo.abstractions.hamiltonians.Hamiltonian
objects representing the h operators of Eq. (58) in the reference. The keys of the dictionary are tuples of qubit ids (int) that represent the targets of each h term.ground_state (Callable) – Optional callable with no arguments that returns the ground state of this
TrotterHamiltonian
. Specifying this method is useful if theTrotterHamiltonian
is used as the easy Hamiltonian of the adiabatic evolution and its ground state is used as the initial condition.
Example
from qibo import matrices, hamiltonians # Create h term for critical TFIM Hamiltonian matrix = -np.kron(matrices.Z, matrices.Z) - np.kron(matrices.X, matrices.I) term = hamiltonians.Hamiltonian(2, matrix) # TFIM with periodic boundary conditions is translationally # invariant and therefore the same term can be used for all qubits # Create even and odd Hamiltonian parts (Eq. (43) in arXiv:1901.05824) even_part = {(0, 1): term, (2, 3): term} odd_part = {(1, 2): term, (3, 0): term} # Create a ``TrotterHamiltonian`` object using these parts h = hamiltonians.TrotterHamiltonian(even_part, odd_part) # Alternatively the precoded TFIM model may be used with the # ``trotter`` flag set to ``True`` h = hamiltonians.TFIM(nqubits, h=1.0, trotter=True)
- classmethod from_symbolic(symbolic_hamiltonian, symbol_map, ground_state=None)¶
Creates a
TrotterHamiltonian
from a symbolic Hamiltonian.We refer to the How to define custom Hamiltonians using symbols? example for more details.
- Parameters
symbolic_hamiltonian (sympy.Expr) – The full Hamiltonian written with symbols.
symbol_map (dict) – Dictionary that maps each symbol that appears in the Hamiltonian to a pair of (target, matrix).
ground_state (Callable) – Optional callable with no arguments that returns the ground state of this
TrotterHamiltonian
. Seeqibo.abstractions.hamiltonians.TrotterHamiltonian
for more details.
- Returns
A
qibo.abstractions.hamiltonians.TrotterHamiltonian
object that implements the given symbolic Hamiltonian.
- abstract static construct_terms(terms)¶
Helper method for from_symbolic.
Constructs the term dictionary by using the same
qibo.abstractions.hamiltonians.Hamiltonian
object for terms that have equal matrix representation. This is done for efficiency during the exponentiation of terms.
- is_compatible(o)¶
Checks if a
TrotterHamiltonian
has the same part structure.By part structure we mean that the target keys of the dictionaries contained in the
self.parts
list are the same for both Hamiltonians. Twoqibo.abstractions.hamiltonians.TrotterHamiltonian
objects can be added only when they are compatible (have the same part structure). When using Trotter decomposition to simulate adiabatic evolution thenh0
andh1
should be compatible.- Parameters
o – The Hamiltonian to check compatibility with.
- Returns
True
ifo
has the same structure asself
otherwiseFalse
.
- abstract make_compatible(o)¶
Makes given
TrotterHamiltonian
compatible to the current one.See
qibo.abstractions.hamiltonians.TrotterHamiltonian.is_compatible()
for more details on how compatibility is defined in this context. The current method will be used automatically byqibo.evolution.AdiabaticEvolution
to make theh0
andh1
Hamiltonians compatible if they are not. We note that in some applications making the Hamiltonians compatible manually instead of relying in this method may take better advantage of caching and lead to better execution performance.- Parameters
o – The
TrotterHamiltonian
to make compatible to the current. Should be non-interacting (contain only one-qubit terms).- Returns
A new
qibo.abstractions.hamiltonians.TrotterHamiltonian
object that is equivalent too
but has the same part structure asself
.
- property dense¶
Creates an equivalent Hamiltonian model that holds the full matrix.
- Returns
A
qibo.abstractions.hamiltonians.Hamiltonian
object that is equivalent to this local Hamiltonian.
- eigenvalues()¶
Computes the eigenvalues for the Hamiltonian.
- eigenvectors()¶
Computes a tensor with the eigenvectors for the Hamiltonian.
- ground_state()¶
Computes the ground state of the Hamiltonian.
If this method is needed it should be implemented efficiently for the particular Hamiltonian by passing the
ground_state
argument during initialization. If this argument is not passed then this method will diagonalize the full (dense) Hamiltonian matrix which is computationally and memory intensive.
- exp(a)¶
Computes a tensor corresponding to exp(-1j * a * H).
- Parameters
a (complex) – Complex number to multiply Hamiltonian before exponentiation.
- expectation(state, normalize=False)¶
Computes the real expectation value for a given state.
- Parameters
state (array) – the expectation state.
normalize (bool) – If
True
the expectation value is divided with the state’s norm squared.
- Returns
Real number corresponding to the expectation value.
- circuit(dt, accelerators=None, memory_device='/CPU:0')¶
Circuit implementing second order Trotter time step.
- Parameters
dt (float) – Time step to use for Trotterization.
- Returns
qibo.abstractions.circuit.AbstractCircuit
that implements a single time step of the second order Trotterized evolution.
In addition to these abstract models, Qibo provides the following pre-coded Hamiltonians:
- qibo.hamiltonians.XXZ(nqubits, delta=0.5, numpy=False, trotter=False)¶
Heisenberg XXZ model with periodic boundary conditions.
\[H = \sum _{i=0}^N \left ( X_iX_{i + 1} + Y_iY_{i + 1} + \delta Z_iZ_{i + 1} \right ).\]- Parameters
nqubits (int) – number of quantum bits.
delta (float) – coefficient for the Z component (default 0.5).
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
Example
from qibo.hamiltonians import XXZ h = XXZ(3) # initialized XXZ model with 3 qubits
- qibo.hamiltonians.X(nqubits, numpy=False, trotter=False)¶
Non-interacting Pauli-X Hamiltonian.
\[H = - \sum _{i=0}^N X_i.\]- Parameters
nqubits (int) – number of quantum bits.
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
- qibo.hamiltonians.Y(nqubits, numpy=False, trotter=False)¶
Non-interacting Pauli-Y Hamiltonian.
\[H = - \sum _{i=0}^N Y_i.\]- Parameters
nqubits (int) – number of quantum bits.
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
- qibo.hamiltonians.Z(nqubits, numpy=False, trotter=False)¶
Non-interacting Pauli-Z Hamiltonian.
\[H = - \sum _{i=0}^N Z_i.\]- Parameters
nqubits (int) – number of quantum bits.
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
- qibo.hamiltonians.TFIM(nqubits, h=0.0, numpy=False, trotter=False)¶
Transverse field Ising model with periodic boundary conditions.
\[H = - \sum _{i=0}^N \left ( Z_i Z_{i + 1} + h X_i \right ).\]- Parameters
nqubits (int) – number of quantum bits.
h (float) – value of the transverse field.
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
- qibo.hamiltonians.MaxCut(nqubits, random_graph=False, numpy=False, trotter=False)¶
Max Cut Hamiltonian.
\[H = - \sum _{i,j=0}^N \frac{1 - Z_i Z_j}{2}.\]- Parameters
nqubits (int) – number of quantum bits.
random_graph (bool) – enable random connections between qubits.
numpy (bool) – If
True
the Hamiltonian is created using numpy as the calculation backend, otherwise TensorFlow is used. Default option isnumpy = False
.trotter (bool) – If
True
it creates the Hamiltonian as aqibo.abstractions.hamiltonians.TrotterHamiltonian
object, otherwise it creates aqibo.abstractions.hamiltonians.Hamiltonian
object.
Note that all pre-coded Hamiltonians can be created as either
qibo.abstractions.hamiltonians.Hamiltonian
or
qibo.abstractions.hamiltonians.TrotterHamiltonian
using the trotter
flag.
States¶
Qibo circuits return qibo.abstractions.states.AbstractState
objects
when executed. By default, Qibo works as a wave function simulator in the sense
that propagates the state vector through the circuit applying the
corresponding gates. In this default usage the result of a circuit execution
is the full final state vector which can be accessed via the tensor
property of states.
However for specific applications it is useful to have measurement samples
from the final wave function, instead of its full vector form.
To that end, qibo.abstractions.states.AbstractState
provides the
qibo.abstractions.states.AbstractState.samples()
and
qibo.abstractions.states.AbstractState.frequencies()
methods.
In order to perform measurements the user has to add the measurement gate
qibo.core.gates.M
to the circuit and then execute providing a number
of shots. If this is done, the qibo.abstractions.states.AbstractState
returned by the circuit will contain the measurement samples.
For more information on measurements we refer to the How to perform measurements? example.
- class qibo.abstractions.states.AbstractState(nqubits=None)¶
Abstract class for quantum states returned by model execution.
- Parameters
nqubits (int) – Optional number of qubits in the state. If
None
then the number is calculated automatically from the tensor representation of the state.
- property nqubits¶
Number of qubits in the state.
- abstract property shape¶
Shape of the state’s tensor representation.
- abstract property dtype¶
Type of state’s tensor representation.
- property tensor¶
Tensor representation of the state in the computational basis.
- abstract numpy()¶
State’s tensor representation as a numpy array.
- state(numpy=False)¶
State’s tensor representation as an backend tensor.
- Parameters
numpy (bool) – If
True
the returned tensor will be a numpy array, otherwise it will follow the backend tensor type. Default isFalse
.
- classmethod from_tensor(x, nqubits=None)¶
Constructs state from a tensor.
- Parameters
x – Tensor representation of the state in the computational basis.
nqubits (int) – Optional number of qubits in the state. If
None
it is calculated automatically from the tensor representation shape.
- abstract classmethod zero_state(nqubits)¶
Constructs the |00…0> state.
- Parameters
nqubits (int) – Number of qubits in the state.
- abstract classmethod plus_state(nqubits)¶
Constructs the |++…+> state.
- Parameters
nqubits (int) – Number of qubits in the state.
- copy()¶
Creates a copy of the state.
Note that this does not create a deep copy. The new state references to the same tensor representation for memory efficiency.
- abstract to_density_matrix()¶
Transforms a pure quantum state to its density matrix form.
- Returns
A
qibo.abstractions.states.AbstractState
object that contains the state in density matrix form.
- abstract probabilities(qubits=None, measurement_gate=None)¶
Calculates measurement probabilities by tracing out qubits.
Exactly one of the following arguments should be given.
- Parameters
measurement_gate (
qibo.abstractions.gates.M
) – Measurement gate that contains the measured qubit details.
- abstract measure(gate, nshots, registers=None)¶
Measures the state using a measurement gate.
- Parameters
gate (
qibo.abstractions.gates.M
) – Measurement gate to use for measuring the state.nshots (int) – Number of measurement shots.
registers (dict) – Dictionary that maps register names to the corresponding tuples of qubit ids.
- abstract set_measurements(qubits, samples, registers=None)¶
Sets the state’s measurements using decimal samples.
- abstract samples(binary=True, registers=False)¶
Returns raw measurement samples.
- Parameters
binary (bool) – Return samples in binary or decimal form.
registers (bool) – Group samples according to registers. Can be used only if
registers
were given when callingqibo.abstractions.states.AbstractState.measure()
.
- Returns
- If binary is True
samples are returned in binary form as a tensor of shape (nshots, n_measured_qubits).
- If binary is False
samples are returned in decimal form as a tensor of shape (nshots,).
- If registers is True
samples are returned in a dict where the keys are the register names and the values are the samples tensors for each register.
- If registers is False
a single tensor is returned which contains samples from all the measured qubits, independently of their registers.
- abstract frequencies(binary=True, registers=False)¶
Returns the frequencies of measured samples.
- Parameters
binary (bool) – Return frequency keys in binary or decimal form.
registers (bool) – Group frequencies according to registers. Can be used only if
registers
were given when callingqibo.abstractions.states.AbstractState.measure()
.
- Returns
A collections.Counter where the keys are the observed values and the values the corresponding frequencies, that is the number of times each measured value/bitstring appears.
- If binary is True
the keys of the Counter are in binary form, as strings of 0s and 1s.
- If binary is False
the keys of the Counter are integers.
- If registers is True
a dict of Counter s is returned where keys are the name of each register.
- If registers is False
a single Counter is returned which contains samples from all the measured qubits, independently of their registers.
- abstract apply_bitflips(p0, p1=None)¶
Applies bitflip noise to the measured samples.
- Parameters
p0 – Bitflip probability map. Can be: A dictionary that maps each measured qubit to the probability that it is flipped, a list or tuple that has the same length as the tuple of measured qubits or a single float number. If a single float is given the same probability will be used for all qubits.
p1 – Probability of asymmetric bitflip. If
p1
is given,p0
will be used as the probability for 0->1 andp1
as the probability for 1->0. Ifp1
isNone
the same probabilityp0
will be used for both bitflips.
- abstract expectation(hamiltonian, normalize=False)¶
Calculates Hamiltonian expectation value with respect to the state.
- Parameters
hamiltonian (qibo.abstractions.hamiltonians.Hamiltonian) – Hamiltonian object to calculate the expectation value of.
normalize (bool) – Normalize the result by dividing with the norm of the state. Default is
False
.
- class qibo.core.states.DistributedState(circuit)¶
Data structure that holds the pieces of a state vector.
This is created automatically by
qibo.tensorflow.distcircuit.DistributedCircuit
which uses state pieces instead of the full state vector tensor to allow distribution to multiple devices. Using theDistributedState
instead of the full state vector as a tensor avoids creating two copies of the state in the CPU memory and allows simulation of one more qubit.The full state vector can be accessed using the
state.vector
orstate.numpy()
methods of theDistributedState
. TheDistributedState
supports indexing as a standard array.- property dtype¶
Type of state’s tensor representation.
- property tensor¶
Returns the full state vector as a tensor of shape
(2 ** nqubits,)
.This is done by merging the state pieces to a single tensor. Using this method will double memory usage.
- assign_pieces(full_state)¶
Splits a full state vector and assigns it to the
tf.Variable
pieces.- Parameters
full_state (array) – Full state vector as a tensor of shape
(2 ** nqubits)
.
- classmethod from_tensor(full_state, circuit)¶
Constructs state from a tensor.
- Parameters
x – Tensor representation of the state in the computational basis.
nqubits (int) – Optional number of qubits in the state. If
None
it is calculated automatically from the tensor representation shape.
- classmethod zero_state(circuit)¶
Constructs the |00…0> state.
- Parameters
nqubits (int) – Number of qubits in the state.
- classmethod plus_state(circuit)¶
Constructs the |++…+> state.
- Parameters
nqubits (int) – Number of qubits in the state.
- copy()¶
Creates a copy of the state.
Note that this does not create a deep copy. The new state references to the same tensor representation for memory efficiency.
Callbacks¶
Callbacks provide a way to calculate quantities on the state vector as it
propagates through the circuit. Example of such quantity is the entanglement
entropy, which is currently the only callback implemented in
qibo.abstractions.callbacks.EntanglementEntropy
.
The user can create custom callbacks by inheriting the
qibo.abstractions.callbacks.Callback
class. The point each callback is
calculated inside the circuit is defined by adding a qibo.abstractions.gates.CallbackGate
.
This can be added similarly to a standard gate and does not affect the state vector.
- class qibo.abstractions.callbacks.Callback¶
Base callback class.
Callbacks should inherit this class and implement its state_vector_call and density_matrix_call methods.
Results of a callback can be accessed by indexing the corresponding object.
- property nqubits¶
Total number of qubits in the circuit that the callback was added in.
- class qibo.abstractions.callbacks.EntanglementEntropy(partition: Optional[List[int]] = None, compute_spectrum: bool = False)¶
Von Neumann entanglement entropy callback.
\[S = \mathrm{Tr} \left ( \rho \log _2 \rho \right )\]- Parameters
Example
from qibo import models, gates, callbacks # create entropy callback where qubit 0 is the first subsystem entropy = callbacks.EntanglementEntropy([0], compute_spectrum=True) # initialize circuit with 2 qubits and add gates c = models.Circuit(2) # add callback gates between normal gates c.add(gates.CallbackGate(entropy)) c.add(gates.H(0)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) # execute the circuit final_state = c() print(entropy[:]) # Should print [0, 0, 1] which is the entanglement entropy # after every gate in the calculation. print(entropy.spectrum) # Print the entanglement spectrum.
- class qibo.abstractions.callbacks.Norm¶
State norm callback.
\[\mathrm{Norm} = \left \langle \Psi | \Psi \right \rangle = \mathrm{Tr} (\rho )\]
- class qibo.abstractions.callbacks.Overlap¶
State overlap callback.
Calculates the overlap between the circuit state and a given target state:
\[\mathrm{Overlap} = |\left \langle \Phi | \Psi \right \rangle |\]- Parameters
state (np.ndarray) – Target state to calculate overlap with.
normalize (bool) – If
True
the states are normalized for the overlap calculation.
- class qibo.abstractions.callbacks.Energy(hamiltonian: hamiltonians.Hamiltonian)¶
Energy expectation value callback.
Calculates the expectation value of a given Hamiltonian as:
\[\left \langle H \right \rangle = \left \langle \Psi | H | \Psi \right \rangle = \mathrm{Tr} (\rho H)\]assuming that the state is normalized.
- Parameters
hamiltonian (
qibo.hamiltonians.Hamiltonian
) – Hamiltonian object to calculate its expectation value.
- class qibo.abstractions.callbacks.Gap(mode: Union[str, int] = 'gap', check_degenerate: bool = True)¶
Callback for calculating the gap of adiabatic evolution Hamiltonians.
Can also be used to calculate the Hamiltonian eigenvalues at each time step during the evolution. Note that this callback can only be added in
qibo.evolution.AdiabaticEvolution
models.- Parameters
mode (str/int) – Defines which quantity this callback calculates. If
mode == 'gap'
then the difference between ground state and first excited state energy (gap) is calculated. Ifmode
is an integer, then the energy of the corresponding eigenstate is calculated.check_degenerate (bool) – If
True
the excited state number is increased until a non-zero gap is found. This is used to find the proper gap in the case of degenerate Hamiltonians. This flag is relevant only ifmode
is'gap'
. Default isTrue
.
Example
from qibo import models, callbacks # define easy and hard Hamiltonians for adiabatic evolution h0 = hamiltonians.X(3) h1 = hamiltonians.TFIM(3, h=1.0) # define callbacks for logging the ground state, first excited # and gap energy ground = callbacks.Gap(0) excited = callbacks.Gap(1) gap = callbacks.Gap() # define and execute the ``AdiabaticEvolution`` model evolution = AdiabaticEvolution(h0, h1, lambda t: t, dt=1e-1, callbacks=[gap, ground, excited]) final_state = evolution(final_time=1.0) # print results print(ground[:]) print(excited[:]) print(gap[:])
Solvers¶
Solvers are used to numerically calculate the time evolution of state vectors. They perform steps in time by integrating the time-dependent Schrodinger equation.
- class qibo.solvers.BaseSolver(dt, hamiltonian)¶
Basic solver that should be inherited by all solvers.
- Parameters
dt (float) – Time step size.
hamiltonian (
qibo.abstractions.hamiltonians.Hamiltonian
) – Hamiltonian object that the state evolves under.
- property t¶
Solver’s current time.
- class qibo.solvers.TrotterizedExponential(dt, hamiltonian)¶
Solver that uses Trotterized exponentials.
Created automatically from the
qibo.solvers.Exponential
if the given Hamiltonian object is aqibo.abstractions.hamiltonians.TrotterHamiltonian
.
- class qibo.solvers.Exponential(dt, hamiltonian)¶
Solver that uses the matrix exponential of the Hamiltonian:
\[U(t) = e^{-i H(t) \delta t}\]Calculates the evolution operator in every step and thus is compatible with time-dependent Hamiltonians.
- class qibo.solvers.RungeKutta4(dt, hamiltonian)¶
Solver based on the 4th order Runge-Kutta method.
- class qibo.solvers.RungeKutta45(dt, hamiltonian)¶
Solver based on the 5th order Runge-Kutta method.
Optimizers¶
Optimizers are used automatically by the minimize
methods of
qibo.models.VQE
and qibo.evolution.AdiabaticEvolution
models.
The user does not have to use any of the optimizer methods included in the
current section, however the required options of each optimization method
can be passed when calling the minimize
method of the respective Qibo
variational model.
- qibo.optimizers.optimize(loss, initial_parameters, args=(), method='Powell', jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None, compile=False, processes=None)¶
- Main optimization method. Selects one of the following optimizers:
- Parameters
loss (callable) – Loss as a function of
parameters
and optional extra arguments. Make sure the loss function returns a tensor formethod=sgd
and numpy object for all the other methods.initial_parameters (np.ndarray) – Initial guess for the variational parameters that are optimized.
args (tuple) – optional arguments for the loss function.
method (str) – Name of optimizer to use. Can be
'cma'
,'sgd'
or one of the Newtonian methods supported byqibo.optimizers.newtonian()
and'parallel_L-BFGS-B'
.jac (dict) – Method for computing the gradient vector for scipy optimizers.
hess (dict) – Method for computing the hessian matrix for scipy optimizers.
hessp (callable) – Hessian of objective function times an arbitrary vector for scipy optimizers.
bounds (sequence or Bounds) – Bounds on variables for scipy optimizers.
constraints (dict) – Constraints definition for scipy optimizers.
tol (float) – Tolerance of termination for scipy optimizers.
callback (callable) – Called after each iteration for scipy optimizers.
options (dict) – Dictionary with options. See the specific optimizer bellow for a list of the supported options.
compile (bool) – If
True
the Tensorflow optimization graph is compiled. This is relevant only for the'sgd'
optimizer.processes (int) – number of processes when using the parallel BFGS method.
- Returns
final best loss value. xbest (float): best parameters obtained by the optimizer. extra: optimizer specific return object containing. For scipy methods it
returns the
OptimizeResult
, for'cma'
theCMAEvolutionStrategy.result
, and for'sgd'
the options used during the optimization.- Return type
loss (float)
Example
import numpy as np from qibo import gates, models from qibo.optimizers import optimize # create custom loss function # make sure the return type matches the optimizer requirements. def myloss(parameters, circuit): circuit.set_parameters(parameters) return np.square(np.sum(circuit())) # returns numpy array # create circuit ansatz for two qubits circuit = models.Circuit(2) circuit.add(gates.RY(0, theta=0)) # optimize using random initial variational parameters initial_parameters = np.random.uniform(0, 2, 1) best, params, extra = optimize(myloss, initial_parameters, args=(circuit)) # set parameters to circuit circuit.set_parameters(params)
- qibo.optimizers.cmaes(loss, initial_parameters, args=(), options=None)¶
Genetic optimizer based on pycma.
- Parameters
loss (callable) – Loss as a function of variational parameters to be optimized.
initial_parameters (np.ndarray) – Initial guess for the variational parameters.
args (tuple) – optional arguments for the loss function.
options (dict) – Dictionary with options accepted by the
cma
optimizer. The user can useimport cma; cma.CMAOptions()
to view the available options.
- qibo.optimizers.newtonian(loss, initial_parameters, args=(), method='Powell', jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None, processes=None)¶
Newtonian optimization approaches based on
scipy.optimize.minimize
.For more details check the scipy documentation.
Note
When using the method
parallel_L-BFGS-B
theprocesses
option controls the number of processes used by the parallel L-BFGS-B algorithm through themultiprocessing
library. By defaultprocesses=None
, in this case the total number of logical cores are used. Make sure to select the appropriate number of processes for your computer specification, taking in consideration memory and physical cores. In order to obtain optimal results you can control the number of threads used by each process with theqibo.set_threads
method. For example, for small-medium size circuits you may benefit from single thread per process, thus setqibo.set_threads(1)
before running the optimization.- Parameters
loss (callable) – Loss as a function of variational parameters to be optimized.
initial_parameters (np.ndarray) – Initial guess for the variational parameters.
args (tuple) – optional arguments for the loss function.
method (str) – Name of method supported by
scipy.optimize.minimize
and'parallel_L-BFGS-B'
for a parallel version of L-BFGS-B algorithm.jac (dict) – Method for computing the gradient vector for scipy optimizers.
hess (dict) – Method for computing the hessian matrix for scipy optimizers.
hessp (callable) – Hessian of objective function times an arbitrary vector for scipy optimizers.
bounds (sequence or Bounds) – Bounds on variables for scipy optimizers.
constraints (dict) – Constraints definition for scipy optimizers.
tol (float) – Tolerance of termination for scipy optimizers.
callback (callable) – Called after each iteration for scipy optimizers.
options (dict) – Dictionary with options accepted by
scipy.optimize.minimize
.processes (int) – number of processes when using the parallel BFGS method.
- qibo.optimizers.sgd(loss, initial_parameters, args=(), options=None, compile=False)¶
Stochastic Gradient Descent (SGD) optimizer using Tensorflow backpropagation.
See tf.keras.Optimizers for a list of the available optimizers.
- Parameters
loss (callable) – Loss as a function of variational parameters to be optimized.
initial_parameters (np.ndarray) – Initial guess for the variational parameters.
args (tuple) – optional arguments for the loss function.
options (dict) –
Dictionary with options for the SGD optimizer. Supports the following keys:
'optimizer'
(str, default:'Adagrad'
): Name of optimizer.'learning_rate'
(float, default:'1e-3'
): Learning rate.'nepochs'
(int, default:1e6
): Number of epochs for optimization.'nmessage'
(int, default:1e3
): Every how many epochs to print a message of the loss function.
Parallelism¶
We provide CPU multi-processing methods for circuit evaluation for multiple input states and multiple parameters for fixed input state.
When using the methods below the processes
option controls the number of
processes used by the parallel algorithms through the multiprocessing
library. By default processes=None
, in this case the total number of logical
cores are used. Make sure to select the appropriate number of processes for your
computer specification, taking in consideration memory and physical cores. In
order to obtain optimal results you can control the number of threads used by
each process with the qibo.set_threads
method. For example, for small-medium
size circuits you may benefit from single thread per process, thus set
qibo.set_threads(1)
before running the optimization.
Resources for parallel circuit evaluation.
- qibo.parallel.parallel_execution(circuit, states, processes=None)¶
Execute circuit for multiple states.
Example
from qibo import models, set_threads from qibo.parallel import parallel_execution import numpy as np # create circuit nqubits = 22 circuit = models.QFT(nqubits) # create random states states = [ np.random.random(2**nqubits) for i in range(5)] # set threads to 1 per process (optional, requires tuning) set_threads(1) # execute in parallel results = parallel_execution(circuit, states, processes=2)
- qibo.parallel.parallel_parametrized_execution(circuit, parameters, initial_state=None, processes=None)¶
Execute circuit for multiple parameters and fixed initial_state.
Example
from qibo import models, gates, set_threads from qibo.parallel import parallel_parametrized_execution import numpy as np # create circuit nqubits = 6 nlayers = 2 circuit = models.Circuit(nqubits) for l in range(nlayers): circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) circuit.add((gates.CZ(q, q+1) for q in range(0, nqubits-1, 2))) circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) circuit.add((gates.CZ(q, q+1) for q in range(1, nqubits-2, 2))) circuit.add(gates.CZ(0, nqubits-1)) circuit.add((gates.RY(q, theta=0) for q in range(nqubits))) # create random parameters size = len(circuit.get_parameters()) parameters = [ np.random.uniform(0, 2*np.pi, size) for _ in range(10) ] # set threads to 1 per process (optional, requires tuning) set_threads(1) # execute in parallel results = parallel_parametrized_execution(circuit, parameters, processes=2)
- Parameters
- Returns
Circuit evaluation for input parameters.
Backends¶
The main calculation engine is defined in the abstract backend object
qibo.backends.abstract.AbstractBackend
. This object defines the methods
required by all Qibo models to perform simulation.
Qibo currently provides two different calculation backends, one based on
numpy and one based on Tensorflow. It is possible to define new backends by
ineriting qibo.backends.abstract.AbstractBackend
and implementing its abstract
methods. Tensorflow is the default backend, however Qibo will automatically
fall back to numpy if Tensorflow is not found installed in the system.
The Tensorflow backend is supplemented by custom operators defined under
tensorflow/custom_operators
, which can be used to efficiently apply gates
to state vectors or density matrices.
These operators are much faster than implementations based on Tensorflow
primitives (such as tf.einsum
) but do not support the following
automatic differentiation for backpropagation of variational circuits.
It is possible to use these features in Qibo by using a backend based on
Tensorflow primitives. There are two such backends available:
the "defaulteinsum"
backend based on tf.einsum
and the "matmuleinsum"
backend based on tf.matmul
.
The user can switch backends using
import qibo
qibo.set_backend("matmuleinsum")
before creating any circuits or gates. The default backend is "custom"
and
uses the custom Tensorflow operators. One can switch to a numpy backend using
the same approach:
import qibo
qibo.set_backend("numpy_defaulteinsum")
Note that custom operators are only supported by the Tensorflow backend.
- class qibo.backends.abstract.AbstractBackend¶
- get_cpu()¶
Returns default CPU device to use for OOM fallback.
- cpu_fallback(func, *args)¶
Executes a function on CPU if the default devices raises OOM.
- abstract cast(x, dtype='DTYPECPX')¶
Casts tensor to the given dtype.
- abstract reshape(x, shape)¶
Reshapes tensor in the given shape.
- abstract stack(x, axis=None)¶
Stacks a list of tensors to a single tensor.
- abstract concatenate(x, axis=None)¶
Concatenates a list of tensor along a given axis.
- abstract expand_dims(x, axis)¶
Creates a new axis of dimension one.
- abstract copy(x)¶
Creates a copy of the tensor in memory.
- abstract range(start, finish, step, dtype=None)¶
Creates a tensor of integers from start to finish.
- abstract eye(dim, dtype='DTYPECPX')¶
Creates the identity matrix as a tensor.
- abstract zeros(shape, dtype='DTYPECPX')¶
Creates tensor of zeros with the given shape and dtype.
- abstract ones(shape, dtype='DTYPECPX')¶
Creates tensor of ones with the given shape and dtype.
- abstract zeros_like(x)¶
Creates tensor of zeros with shape and dtype of the given tensor.
- abstract ones_like(x)¶
Creates tensor of ones with shape and dtype of the given tensor.
- abstract real(x)¶
Real part of a given complex tensor.
- abstract imag(x)¶
Imaginary part of a given complex tensor.
- abstract conj(x)¶
Elementwise complex conjugate of a tensor.
- abstract mod(x)¶
Elementwise mod operation.
- abstract right_shift(x, y)¶
Elementwise bitwise right shift.
- abstract exp(x)¶
Elementwise exponential.
- abstract sin(x)¶
Elementwise sin.
- abstract cos(x)¶
Elementwise cos.
- abstract pow(base, exponent)¶
Elementwise power.
- abstract square(x)¶
Elementwise square.
- abstract sqrt(x)¶
Elementwise square root.
- abstract log(x)¶
Elementwise natural logarithm.
- abstract abs(x)¶
Elementwise absolute value.
- abstract expm(x)¶
Matrix exponential.
- abstract trace(x)¶
Matrix trace.
- abstract sum(x, axis=None)¶
Sum of tensor elements.
- abstract matmul(x, y)¶
Matrix multiplication of two tensors.
- abstract outer(x, y)¶
Outer (Kronecker) product of two tensors.
- abstract kron(x, y)¶
Outer (Kronecker) product of two tensors.
- abstract einsum(*args)¶
Generic tensor operation based on Einstein’s summation convention.
- abstract tensordot(x, y, axes=None)¶
Generalized tensor product of two tensors.
- abstract transpose(x, axes=None)¶
Tensor transpose.
- abstract inv(x)¶
Matrix inversion.
- abstract eigh(x)¶
Hermitian matrix eigenvalues and eigenvectors.
- abstract eigvalsh(x)¶
Hermitian matrix eigenvalues.
- abstract unique(x, return_counts=False)¶
Identifies unique elements in a tensor.
- abstract less(x, y)¶
Compares the values of two tensors element-wise. Returns a bool tensor.
- abstract array_equal(x, y)¶
Checks if two arrays are equal element-wise. Returns a single bool.
Used in
qibo.tensorflow.hamiltonians.TrotterHamiltonian.construct_terms()
.
- abstract squeeze(x, axis=None)¶
Removes axis of unit length.
- abstract gather(x, indices=None, condition=None, axis=0)¶
Indexing of one-dimensional tensor.
- abstract gather_nd(x, indices)¶
Indexing of multi-dimensional tensor.
- abstract initial_state(nqubits, is_matrix=False)¶
Creates the default initial state |00…0> as a tensor.
- abstract transpose_state(pieces, state, nqubits, order)¶
Transposes state pieces to the full state.
Used by
qibo.core.states.DistributedState
.
- abstract random_uniform(shape, dtype='DTYPE')¶
Samples array of given shape from a uniform distribution in [0, 1].
- abstract sample_shots(probs, nshots)¶
Samples measurement shots from a given probability distribution.
- Parameters
probs (Tensor) – Tensor with the probability distribution on the measured bitsrings.
nshots (int) – Number of measurement shots to sample.
- Returns
Measurements in decimal as a tensor of shape
(nshots,)
.
- abstract sample_frequencies(probs, nshots)¶
Samples measurement frequencies from a given probability distribution.
- Parameters
probs (Tensor) – Tensor with the probability distribution on the measured bitsrings.
nshots (int) – Number of measurement shots to sample.
- Returns
Frequencies of measurements as a
collections.Counter
.
- abstract compile(func)¶
Compiles the graph of a given function.
Relevant for Tensorflow, not numpy.
- abstract device(device_name)¶
Used to execute code in specific device if supported by backend.
- executing_eagerly()¶
Checks if we are in eager or compiled mode.
Relevant for the Tensorflow backends only.
- abstract set_seed(seed)¶
Sets the seed for random number generation.
- Parameters
seed (int) – Integer to use as seed.
- abstract create_gate_cache(gate)¶
Calculates data required for applying gates to states.
These can be einsum index strings or tensors of qubit ids and it depends on the underlying backend.
- Parameters
gate (
qibo.abstractions.abstract_gates.BackendGate
) – Gate object to calculate its cache.- Returns
Custom cache object that holds all the required data as attributes.
- abstract state_vector_call(gate, state)¶
Applies gate to state vector.
- Parameters
gate (
qibo.abstractions.abstract_gates.BackendGate
) – Gate object to apply to state.state (Tensor) – State vector as a
Tensor
supported by this backend.
- Returns
State vector after applying the gate as a
Tensor
.
- abstract state_vector_matrix_call(gate, state)¶
Applies gate to state vector using the gate’s unitary matrix representation.
This method is useful for the
custom
backend for which some gates do not require the unitary matrix.- Parameters
gate (
qibo.abstractions.abstract_gates.BackendGate
) – Gate object to apply to state.state (Tensor) – State vector as a
Tensor
supported by this backend.
- Returns
State vector after applying the gate as a
Tensor
.
- abstract density_matrix_call(gate, state)¶
Applies gate to density matrix.
- Parameters
gate (
qibo.abstractions.abstract_gates.BackendGate
) – Gate object to apply to state.state (Tensor) – Density matrix as a
Tensor
supported by this backend.
- Returns
Density matrix after applying the gate as a
Tensor
.
- abstract density_matrix_matrix_call(gate, state)¶
Applies gate to density matrix using the gate’s unitary matrix representation.
This method is useful for the
custom
backend for which some gates do not require the unitary matrix.- Parameters
gate (
qibo.abstractions.abstract_gates.BackendGate
) – Gate object to apply to state.state (Tensor) – Density matrix as a
Tensor
supported by this backend.
- Returns
Density matrix after applying the gate as a
Tensor
.
- abstract state_vector_collapse(gate, state, result)¶
Collapses state vector to a given result.
- abstract density_matrix_collapse(gate, state, result)¶
Collapses density matrix to a given result.