Usage

Obtaining the backend for execution

Obtain your account name and token from the Quantum Rings team. You can then use them to create the backend for execution. You can follow the reference code below for further information:

import QuantumRingsLib
from QuantumRingsLib import QuantumRegister, AncillaRegister, ClassicalRegister, QuantumCircuit
from QuantumRingsLib import QuantumRingsProvider
from QuantumRingsLib import job_monitor
from QuantumRingsLib import JobStatus
from matplotlib import pyplot as plt
import numpy as np

provider = QuantumRingsProvider(token =<YOUR_TOKEN_HERE>, name=<YOUR_ACCOUNT_NAME_HERE>)
backend = provider.get_backend("scarlet_quantum_rings")
shots = 100

provider.active_account()

Executing the Code

You can execute the code in the backend as illustrated below and setup a job monitor to watch for completion. The code is executed in a background thread so you can use your system normally.

Using job_monitor function

job = backend.run(qc, shots)
job_monitor(job)
result = job.result()
counts = result.get_counts()
print (counts)

Using wait_for_final_state function

def jobCallback(job_id, state, job):
    #print("Job Status: ", state)
    pass

# Execute the circuit
job = backend.run(qc, shots)
job.wait_for_final_state(0, 5, jobCallback)
counts = job.result().get_counts()

Importing QASM2 code

For importing QASM2 code, refer to the following code example.

Importing QASM2 code

from QuantumRingsLib import QuantumCircuit
qc = QuantumCircuit.from_qasm_file("C:\\Users\\vkasi\\Desktop\\Sycamore\\1\\circuit_n12_m14_s0_e0_pEFGH.qasm")

Using c_if control statements

c_if control is supported on all gates. The following code fragment illustrates this concept.

c_if control

shots = 1
numberofqubits = 4
q = QuantumRegister(numberofqubits , 'q')
c = ClassicalRegister(numberofqubits , 'c')
qc = QuantumCircuit(q, c)

qc.x([q[0],q[1]])
qc.measure(0, 0)
qc.measure(1, 1)
qc.reset(0)
qc.reset(1)
qc.x(q[1]).c_if(c[0],1)
qc.x(q[2]).c_if(c[1],1)
qc.measure_all()

# Execute the quantum code
job = backend.run(qc, shots)
job_monitor(job)


result = job.result()
counts = result.get_counts()
print(counts)

The equivalent QASM2 code can be generated using the instruction outlined in the following section.

Generating equivalent QASM2 code

qc.qasm(True)

The output of the above instruction is:

OPENQASM 2.0;
include "qelib1.inc";

// Register definitions
qreg q[4];
creg c[4];

// Instructions
x q[0];
x q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
reset q[0];
reset q[1];
if (c[0]  == 1) x q[1];
if (c[1]  == 1) x q[2];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
measure q[3] -> c[3];

The generated QASM2 code can be imported in other systems and executed.

Creating Parameterized Quantum Circuits

Parameterized quantum circuits (PQCs) are handy in creating reusable circuit components. PQCs are typically used in variational circuits and in creating machine learning algorithms. Using this method, arguments to circuit instructions can be defined using symbols. They can later be assigned actual values before executing. The following code snippet illustrates this concept.

** create the parameters **

# import the required modules
import QuantumRingsLib
from QuantumRingsLib import QuantumRegister, AncillaRegister, ClassicalRegister, QuantumCircuit
from QuantumRingsLib import QuantumRingsProvider
from QuantumRingsLib import Parameter, ParameterVector
import math

# create the quantum circuit
total_qubits = 5
q = QuantumRegister (total_qubits, "q")
c = ClassicalRegister (total_qubits, "c")
qc = QuantumCircuit (q, c)

# create the parameters
myparamvec = ParameterVector("test", 6)
theta = Parameter("theta")
phi = Parameter("phi")
lam = Parameter("lambda")
gamma = Parameter("gamma")

#build the quantum circuit
qc.h(q[0]);
qc.x(q[1]);
qc.x(q[2]);
qc.h(q[3]);
qc.x(q[4]);
qc.h(q[4]);
qc.mcp(theta, [q[0],q[1],q[3]], q[2]);
qc.rx(phi, 3 )
qc.ry(math.pi/2, 4 )
qc.rz(myparamvec[5], 0 )
qc.u(myparamvec[0], myparamvec[1], myparamvec[2], 1)

Draw the parameterized circuit

qc.draw()

Executing the above code produces the following figure:

       ┌───┐                  ┌──────────────┐
q[0]: ■┤ H ├───────────■──────┤ RZ(test[5])  ├─────────────────
       ├───┤           │      ├──────────────┴───────────────┐
q[1]: ■┤ X ├───────────■──────┤ U(test[0], test[1], test[2]) ├
       ├───┤     ┌─────┴─────┐└──────────────────────────────┘
q[2]: ■┤ X ├─────┤ P(theta)  ├────────────────────────────────
       ├───┤     └─────┬─────┘┌──────────┐
q[3]: ■┤ H ├───────────■──────┤ RX(phi)  ├─────────────────────
       ├───┤┌───┐             ├──────────┤
q[4]: ■┤ X ├┤ H ├─────────────┤ RY(pi/2) ├─────────────────────
       └───┘└───┘             └──────────┘
c: 5/ ■═══════════════════════════════════════════════════════

Assigning parameters to the circuit

The following code illustrates how to assign parameters to the quantum circuit.

# create the parameters
myparam = {"test[0]": math.pi,
           "test[1]": math.pi/2,
           "test[2]": math.pi/3,
           "test[3]": math.pi/4,
           "test[4]": math.pi/6,
           "test[5]": math.pi/7,
           "theta"  : math.pi/8,
           "phi"    : math.pi/9,
           "lambda" : math.pi/11,
           "gamma"  : math.pi/13,
          }

# assign the parameters to the circuit
qc.assign_parameters(myparam, inplace=True)
qc.draw()

Executing the above code produces the following figure:

       ┌───┐                ┌──────────┐
q[0]: ■┤ H ├──────────■─────┤ RZ(pi/7) ├───────────
       ├───┤          │     ├──────────┴─────────┐
q[1]: ■┤ X ├──────────■─────┤ U(pi, pi/2, pi/3)  ├
       ├───┤     ┌────┴────┐└────────────────────┘
q[2]: ■┤ X ├─────┤ P(pi/8) ├──────────────────────
       ├───┤     └────┬────┘┌──────────┐
q[3]: ■┤ H ├──────────■─────┤ RX(pi/9) ├───────────
       ├───┤┌───┐           ├──────────┤
q[4]: ■┤ X ├┤ H ├───────────┤ RY(pi/2) ├───────────
       └───┘└───┘           └──────────┘
c: 5/ ■═══════════════════════════════════════════

We see that the parameters are assigned. This circuit can be executed using the methods outlined in previous sections.