This project is an implementation of a basic quantum computer simulator.
The only requirement for the running of the simulation is the installation of the Python3 package Numpy. The simulator implements the following:
- Initialisation of the ground state
- Reads a quantum circuit with a range of gates (listed below)
- Allows the appending of gates to a quantum circuit
- Runs the quantum circuit and for each gate:
- Find the operator matrix using the universal operator function
- Applies it to the state
- Performs a measurement perform multi-shot measurement of all qubits using weighted random technique
Furthermore the program uses the UNIVERSAL OPERATOR FUNCTION Examples of the implementation are given in the file main.py
The simulation class is imported into a python file as below:
from quantum_simulator import quantum_circuit
First the circuit object must be defined, inputting the number of qubits in your circuit and the quantum circuit itself:
qc = quantum_circuit(num_qubits, my_circuit)
Note the quantum circuit is not a requirement to be input here if you are planning on using the built in functions to append gates
The simulation allows the following quantum gates with any number of targets, or controls if applicable:
Gate | Function | Description | Requirements |
---|---|---|---|
X | x | Pauli X | Targets |
Y | y | Pauli Y | Targets |
Z | z | Pauli Z | Targets |
H | h | Pauli X | Targets |
CX | mx | (Multi) Controlled X | Controls, Targets |
CY | my | (Multi) Controlled Y | Controls, Targets |
CZ | mz | (Multi) Controlled Z | Controls, Targets |
U3 | u3 | U3 Gate | Targets, Parameters |
CU3 | mu3 | (Multi) Controlled U3 | Controls, Targets, Parameters |
Note that this simulator uses big endian encoding
The circuit can be created in one of two ways:
- Defining the circuit initially as an array of dictionaries
- Using the built in functions to append a gate to the circuit
For the first option a sample circuit is provided below:
my_circuit = [
{ 'gate': 'x', 'controls': [], 'targets': [1,3] },
{ 'gate': 'cx', 'controls': [1,3], 'targets': [0,2] },
{ 'gate': 'u3', 'controls': [2], 'targets': [3], 'params': { "theta": "global_1", "phi": "global_2", "lambda": np.pi/2 } }
]
As you can see from this example, there are three main types of gate inputs:
- single qubit gates ( 'x' , 'y' , 'z' , 'h' ) do not require any controls, however an empty controls list must be input
- multi control quibit gates ( 'cx' , 'cy' , 'cz' ) require arrays of both controls and targets
- parameter qubit gates ( 'u3' ) require arrays of controls, targets and parameters, with the parameters defined as above. If using global variables (as theta and phi are in the example), these must be defined later when running the circuit
The second option is to use the built in functions to append gates, as in the example below:
qc.x([1,3])
qc.mx([1,3],[0,2])
qc.mu3([2],[3],{ "theta": "global_1", "phi": "global_2", "lambda": np.pi/2 })
This creates the same circuit as above. Note:
- single qubit gates no longer require an empty controls list, only targets
- multi controlled gates are called with an m as a prefix in the function
- parameter qubit gates still require the parameters to be input in the same form
Once the circuit has been created, it can be run using the following:
qc.run(params={ "global_1": np.pi/2, "global_2": 3*np.pi/2 })
counts = qc.get_counts(num_shots)
Note that the parameters are only needed in qc.run() if global variables were called in the creation of the circuit.
The counts produces an ouput as below:
{'1111': 503, '1110': 497}
Versions is a folder containing a workbook used to test functions, and previous version of the simulator
QOSF Task - https://github.com/quantastica/qosf-mentorship/blob/master/qosf-simulator-task.ipynb
Universal Operator Function - https://github.com/quantastica/qosf-mentorship/blob/master/qosf-simulator-task-additional-info.pdf