Getting Started
Installation
Clone repository
It is important to say that, for ensuring a correct cloning of the repository, the SSH is the one preferred. In order to get this to work one has to do:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/SSH_KEY
Now, everything is set to get the source code.
git clone git@github.com:CESGA-Quantum-Spain/cunqa.git
Define STORE environment variable
Before doing any kind of compilation, the user has to define the STORE environment variable in bash. This repository will be the root for the .cunqa folder, where CUNQA is going to store several runtime files (configuration files and logging files, mainly).
export STORE=/path/to/your/store
Dependencies
CUNQA has a set of dependencies. They are divided in three main groups.
Must be installed before configuration.
Can be installed, but if they are not they will be by the configuration process.
They will be installed by the configuration process.
From the first group, the ones that must be installed, the dependencies are the following. The versions here displayed are the ones that have been employed in the development and, therefore, that are recommended.
gcc 12.3.0
qiskit 1.24.0
CMake 3.21.0
python 3.9 (recommended 3.11)
pybind11 2.7 (recommended 2.12)
MPI 3.1
OpenMP 4.5
Boost 1.85.0
Blas -
Lapack -
From the second group, the ones that will be installed if they are not yet, they are the next ones.
nlohmann JSON 3.11.3
spdlog 1.16.0
MQT-DDSIM 1.24.0
libzmq 4.3.5
cppzmq 4.11.0
CunqaSimulator 0.1.1
And, finally, the ones that will be installed.
argparse -
qiskit-aer 0.17.2 (modified version)
Configure, build and install
Now, as with any other CMake project, is can be installed using the usual directives. The CMAKE_INSTALL_PREFIX variable should be defined and, if not, its will be the HOME environment variable value.
cmake -B build/ -DCMAKE_PREFIX_INSTALL=/your/installation/path
cmake --build build/ --parallel $(nproc)
cmake --install build/
It is important to mention that the user can also employ Ninja to perform this task.
cmake -G Ninja -B build/ -DCMAKE_PREFIX_INSTALL=/your/installation/path
ninja -C build -j $(nproc)
cmake --install build/
Alternatively, you can use the configure.sh file, but only after all the dependencies have been solved.
source configure.sh /your/installation/path
Install as Lmod module
Cunqa is available as Lmod module in CESGA. To use it all you have to do is:
In QMIO:
module load qmio/hpc gcc/12.3.0 cunqa/0.3.1-python-3.9.9-mpiIn FT3:
module load cesga/2022 gcc/system cunqa/0.3.1
If your HPC center is interested in using it this way, EasyBuild files employed to install it in CESGA are available inside easybuild/ folder.
Uninstall
There has also been developed a Make directive to uninstall CUNQA if needed:
If you installed using the standard way:
make uninstall.If you installed using Ninja:
ninja uninstall.
Be sure to execute this command inside the build/ directory in both cases. An alternative is using:
cmake --build build/ --target uninstall
to abstract from the installation method.
Run your first distributed program
Once CUNQA is installed, the basic workflow to use it is:
Raise the desired QPUs with the command
qraise.Run circuits on the QPUs:
Connect to the QPUs through the python API.
Define the circuits to execute.
Execute the circuits on the QPUs.
Obtain the results.
Drop the raised QPUs with the command
qdrop.
1. qraise command
The qraise command raises as many QPUs as desired. Each QPU can be configured by the user to have a personalized backend. There is a help FLAG with a quick guide of how this command works:
qraise --help
The only two mandatory FLAGS of
qraiseare the number of QPUs, set up with-nor--num_qpusand the maximum time the QPUs will be raised, set up with-tor--time. So, for instance, the command
qraise -n 4 -t 01:20:30
📘 Note: By default, all the QPUs will be raised with AerSimulator as the background simulator and IdealAer as the background backend. That is, a backend of 32 qubits, all connected and without noise.
will raise four QPUs during at most 1 hour, 20 minutes and 30 seconds. The time format is hh:mm:ss.
2. The simulator and the backend configuration can be set by the user through qraise FLAGs:
Set simulator:
qraise -n 4 -t 01:20:30 --sim=Munich
The command above changes the default simulator by the mqt-ddsim simulator. Currently, CUNQA only allows two simulators: --sim=Aer and --sim=Munich.
Set FakeQmio:
qraise -n 4 -t 01:20:30 --fakeqmio=<path/to/calibrations/file>
The --fakeqmio FLAG raises the QPUs as simulated QMIO <https://www.cesga.es/infraestructuras/cuantica/>`_s. If no ``<path/to/calibrations/file>` is provided, last calibrations of de QMIO are used. With this FLAG, the background simulator is AerSimulator.
Set personalized backend:
qraise -n 4 -t 01:20:30 --backend=<path/to/backend/json>
The personalized backend has to be a json file with the following structure:
{"backend":{"name": "BackendExample", "version": "0.0", "n_qubits": 32,"url": "", "is_simulator": true, "conditional": true, "memory": true, "max_shots": 1000000, "description": "", "basis_gates": [], "custom_instructions": "", "gates": [], "coupling_map": []}, "noise": {}}
📘 Note: The “noise” key must be filled with a json with noise instructions supported by the chosen simulator.
❗ Important: Several
qraisecommands can be executed one after another to raise as many QPUs as desired, each one having its own configuration, independently of the previous ones. Theget_QPUs()method presented in the section below will collect all the raised QPUs.
2. Python Program Example
Once the QPUs are raised, they are ready to execute any quantum circuit. The following script shows a basic workflow to run a circuit on a single QPU.
⚠️ Warning: To execute the following python example it is needed to load the Qiskit module:
In QMIO:
module load qmio/hpc gcc/12.3.0 qiskit/1.2.4-python-3.9.9
In FT3:
module load cesga/2022 gcc/system qiskit/1.2.4
# Python Script Example
import os
import sys
# Adding pyhton folder path to detect modules
sys.path.append(os.getenv("HOME"))
# Let's get the raised QPUs
from cunqa.qutils import get_QPUs
qpus = get_QPUs(local=False) # List of all raised QPUs
for q in qpus:
print(f"QPU {q.id}, name: {q.backend.name}, backend: {q.backend.simulator}, version: {q.backend.version}.")
# Let's create a circuit to run in our QPUs
from qiskit import QuantumCircuit
N_QUBITS = 2 # Number of qubits
qc = QuantumCircuit(N_QUBITS)
qc.h(0)
qc.cx(0,1)
qc.measure_all()
# Time to run
qpu0 = qpus[0] # Select one of the raise QPUs
job = qpu0.run(qc, transpile = True, shots = 1000) # Run the transpiled circuit
result = job.result # Get the result of the execution
counts = result.counts # Get the counts
print(f"Counts: {counts}" ) # {'00':546, '11':454}
📘 Note: It is not mandatory to run a QuantumCircuit from Qiskit. The
.runmethod also supports OpenQASM 2.0 with the following structure:
{"instructions":"OPENQASM 2.0;\ninclude \"qelib1.inc\";\nqreg q[2];\ncreg c[2];\nh q[0];\ncx q[0], q[1];\nmeasure q[0] -> c[0];\nmeasure q[1] -> c[1];" , "num_qubits": 2, "num_clbits": 4, "quantum_registers": {"q": [0, 1]}, "classical_registers": {"c": [0, 1], "other_measure_name": [2], "meas": [3]}}
and json format with the following structure:
{"instructions": [{"name": "h", "qubits": [0], "params": []},{"name": "cx", "qubits": [0, 1], "params": []}, {"name": "rx", "qubits": [0], "params": [0.39528385768119634]}, {"name": "measure", "qubits": [0], "memory": [0]}], "num_qubits": 2, "num_clbits": 4, "quantum_registers": {"q": [0, 1]}, "classical_registers": {"c": [0, 1], "other_measure_name": [2], "meas": [3]}}
3. qdrop command
Once the work is finished, the raised QPUs should be dropped in order to not monopolize computational resources.
The qdrop command can be used to drop all the QPUs raised with a single qraise by passing the corresponding qraise SLURM_JOB_ID:
qdrop SLURM_JOB_ID
Note that the SLURM_JOB_ID can be obtained, for instance, executing the squeue command.
To drop all the raised QPUs, just execute:
qdrop --all