qat.pylinalg: Python Linear-algebra simulator
myQLM comes with one simulator which performs a unitary evolution of the initial quantum state using the operations described in a quantum circuit. This simulator is called “Python Linear-Algebra”.
It is entirely written in Python, and is based in particular on the Numpy library.
The quantum state is stored as an ndarray of shape \(\left(2,...,2\right)\), with one 2-valued index per qubit:
where \(|i_{1}\dots i_{N}\rangle\) represents a computational basis state.
Quantum gates are also manipulated as ndarrays, with \(2\times \text{arity}\) 2-valued indices. Half of the indices are input indices and the other half output indices.
Applying a gate consists in contracting the input indices with the indices corresponding to the qubits on which the gate is applied:
The main point of using ndarrays is that this operation can be easily written with the np.tensordot function. See source code documentation for more details.
miscellanous remarks about the simulator:
it accepts any gate, of any arity.
it works with the entire amplitude vector. Any information is available.
it is memory and run-time exponential in the number of qubits. This implies a hard simulation limit at around 20-30 qubits, depending on your RAM.
Within myQLM, this simulator is contained in the qat.pylinalg
module.
Note
The full QLM appliance also includes ‘’noisy’’ simulators, which take into account realistic, parametrable physical noise into the execution of a quantum circuit.
The qat.pylinalg
module contains a linear-algebra-based quantum simulator.
This simulator encodes the quantum amplitudes in a vector with \(2^n\)
complex numbers, where \(n\) is the number of qubits. This vector is modified
by the application of quantum gates.
Quantum Processing Unit
This is the high-level class wrapping the simulator. It follows the convention
of the qat.core.qpu.QPUHandler
structure.
- class qat.pylinalg.PyLinalg
Simple linalg simulator plugin.
Inherits
serve()
andsubmit()
method fromqat.core.qpu.QPUHandler
Only thesubmit_job()
method is simulator-specific and defined here.- serve(port, host_ip='localhost', server_type=None)
Runs the QPU inside a server
- Parameters
port (int) – the port on which to listen
host_ip (str) – the url on which to publish the API. Optional. Defaults to ‘localhost’.
server_type (str, optional) –
type of server. The different types of server are:
”simple”: single-thread server, accepts one connection at a time (default server type)
”threaded”: multi-thread server, each connection starts a new thread
”pool”: multi-thread server, each connection runs in a thread, with a maximum of 10 running threads
”fork”: multi-process server, each connection runs in a new process
- submit(batch: Batch, meta_data: Optional[dict] = None) BatchResult
Executes a batch of jobs and returns the corresponding list of Results.
- Parameters
batch (
Batch
) – a batch of jobs. If a single job is provided, the job is embedded into a Batch, executed, and the first result is returned.- Returns
a batch result
- Return type
Note
The submit_job()
method above basically consists of two
imbricated if statements.
The first one looks at the type
attribute of the job, which can take
two values:
OBSERVABLE
(cf.ProcessingType
): the job consists in evaluating an observable at the end of the circuit. Currently, the attribute nbshots has no effect if the type isOBSERVABLE
SAMPLING
(cf.ProcessingType
): the job consists in sampling the output probability distribution of the quantum circuit. This is where the second if loop comes in, depending on the number of shots which is asked (job.nbshots
):
if nbshots=0 then the simulator/quantum-processor returns the best it can do. In our case, of a linear-algebra-based simulator, this is the entire probability distribution.
else, the simulator samples the output probability distribution nbshots times.
Simulator Internal Functions
The actual numpy-based simulation code can be accessed in the qat.pylinalg.simulator
module, whose source code is documented here.
- qat.pylinalg.simulator.simulate(circuit)
Computes state vector at the output of provided circuit.
State vector is stored as a
numpy.ndarray
It is initialized at \(|0^n\rangle\). Then, loop over gates, updating the state vector using np.tensordot- Parameters
circuit (
Circuit
) – Input circuit. The circuit to simulate.- Returns
a tuple composed of a state vector and intermediate measurements:
state vector:
numpy.ndarray
containing the final state vector. It has one 2-valued index per qubits.intermediate measurements:
list
ofqat.comm.shared.ttypes.IntermediateMeasurement
. List containing descriptors of the intermediate measurements that occurred within the circuit, so that the classical branching is known to the user.
- Return type
tuple
Note
qat.pylinalg.simulator.simulate()
mainly consists in a for loop
over the ops
attribute of the input Circuit
,
i.e the gates of the circuit. They are successively applied onto the quantum
state, which starts in \(|0...0\rangle\). A gate can be of several types:
GATETYPE (default)
MEASURE (measure some qubits, store the result)
RESET (measure a qubit, if result is 1, apply X onto it)
CLASSIC (perform classical logical computation on classical bits)
CLASSICCTRL (perform classically controlled quantum gate)
BREAK (raise break exception if a clasical formula is evaluated to True)
circuit.ops
is a list of qat.comm.datamodel.ttypes.Op
.
- qat.pylinalg.simulator.measure(state_vec, qubits, nb_samples=1)
Samples measurement results on the specified qubits.
No projection is carried out ! See “project” function. Thanks to the absence of projection, several samples can be asked.
- Parameters
state_vec (numpy.ndarray) – the
numpy.ndarray
containing full state vector.qubits (list) – list of integers specifying the subset of qubits to measure.
nb_samples (int, optional) – the number of samples to return. Set to 1 by default.
- Returns
intprob_list, a list (of length nb_samples) containing tuples of the form (integer, probability). The integer is the result of the measurement on the subset of qubits (when converted to binary representation, it needs to have a width of len(qubits)). The probability is the probability the measurement had to occur. It is useful for renormalizing afterwards. In short: it is a list of samples. One sample is a (int, prob) tuple.
- Return type
list
- qat.pylinalg.simulator.project(state_vec, qubits, intprob)
Projects the state by assigning qubits to specified values.
The “measure” function does not project. This is nice when asking for several samples. But the full behavior of a quantum state when undergoing measurement includes a projection onto the result state. This is what this function does. In practice, it is used for intermediary measurements. (i.e within measure and reset gates)
- Parameters
state_vec (numpy.ndarray) – The state vector to project, i.e the one from which the results were sampled.
qubits (list) – The qubits that were measured, presented as a list of integers. Without this info, we don’t know to what axes the result corresponds.
intprob (tuple) – a tuple of the form (integer, probability). The integer codes for the value that was measured on the qubits in the list “qubits”. The probability that the measurement had to occur. It is useful for renormalizing without having to recompute a norm.
- Returns
The projected state vector. The values of the qubits in the “qubits” list have been assigned to the measured values.
- Return type
numpy.ndarray
- qat.pylinalg.simulator.reset(state_vec, qubits)
Resets the value of the specified qubits to 0.
It works by measuring each qubit, and then applying an X gate if the result is 1.
for one qubit, entirely equivalent to, in AQASM:
MEAS q[k] c[k] ?c[k] : X q[k]
- Parameters
state_vec (numpy.ndarray) – nd-array containing the full state vector.
qubits (list) – list of integers, containing the qubits to reset.
- Returns
a tuple composed of:
state_vec(numpy.ndarray) the full state vector. the specified qubits have been reset.
an integer: result of the measurement on the subset of qubits (when converted to binary representation, it needs to have a width of len(qubits)).
a float: probability the measurement had to occur.
- Return type
(state_vec, int, prob)
- qat.pylinalg.simulator.raise_break(op, op_pos, cbits)
Raises break exception, as a result of a boolean classical formula being evaluated to True.
- qat.pylinalg.simulator.mat2nparray(matrix)
Converts serialized matrix format into numpy array.
When extracted from the quantum circuit, gate matrices are not directly numpy arrays. They are instances of
Matrix
, an internally-defined structure.- Parameters
matrix (
qat.comm.datamodel.ttypes.Matrix
) – The matrix, as extracted from circuit operation, to convert tonumpy.ndarray
- Returns
a
numpy.ndarray
of shape (2*arity,2*arity) containing the matrix data.- Return type
numpy.ndarray