-
Notifications
You must be signed in to change notification settings - Fork 4
Quick Guide
v. Jan.2022
Authors: Chin-Yang Jen, Chin-Huan Wang, Cheng-Yun Hsieh, Yu-Min Li and James Chien-Mo Li
qATG is an open-source project based on "cite" and "cite". It automatic generates a test configuration (which is a list of quantum gates) based on the quantum circuit size, quantum circuit basis gate set, and quantum circuit faults that are given by the user.
The github link is here.
This guide leads you to generate your first test configuration.
First we need to declare our target faults. Every fault should be express as a class, which inherits the class qatgFault
. Here is a minimum example:
import qiskit.circuit.library as qGate
from qatgFault import qatgFault
class myUFault(qatgFault):
def __init__(self, qubit):
super(myUFault, self).__init__(gateType = qGate.UGate, qubit = qubit)
def getOriginalGateParameters(self):
return [0, 0, 0]
def createFaulty(self, parameters):
return qGate.UGate(*[param + 0.1 for param in parameters])
Here we explain the code.
-
import qiskit.circuit.library as qGate
is an important part in our project, since we need qiskit to work on our configuration. The parametergateType
ofqatgFault
must be one of theqiskit.circuit.library
gates. Details is written in III. Detailed Arguments - About Faults' Gate Types. -
class myUFault(qatgFault):
inherits our classqatgFault
. - In
qatgFault
there are two necessary arguments:gateType
andqubit
. The type of the fault would begateType
, and the fault will happen on qubit #qubit
. - User must override function
getOriginalGateParameters
. This function should return the first fault-free gate's parameters in the required configuration. In this case, we simply have$U(\theta, \phi, \lambda) = U(0, 0, 0)$ as our first fault-free gate. - User must override function
createFaulty
. qATG will explore the faulty behavior via this function. This function gets a parameter list as input, and outputs a faulty gate when the fault-free gate's parameters are the input parameter list. In this example, if we haveUGate(theta, phi, lambda)
as our fault-free gate,self.createFaulty([theta, phi, lambda])
will returnUGate(theta+0.1, phi+0.1, lambda+0.1)
as our faulty gate (which is a bias fault). The return type of this function should be one of theqiskit.circuit.library
gates, or other compatible types. Details is written in III. Detailed Arguments - About Faults' Gate Types.
After declaring the faults, we move on to generate the test configuration. Here is an example:
from qatg import qatg
singleFaultList = [myUFault(qubit = 0)]
twoFaultList = []
generator = qatg(circuitSize = 5, basisGateSet = [qGate.UGate])
generator.configurationSimulationSetup()
configurationList = generator.createTestConfiguration(singleFaultList, twoFaultList)
Here we explain the code:
-
qatg(circuitSize, basisGateSet)
returns a object with classqatg
, which is our test generator.circuitSize
gives the circuit size of the quantum circuit (and the qubits will be numbered into0 ~ (circuitSize-1)
), andbasisGateSet
is a list that contains the basis gates that the quantum circuit supports, only single-qubit gates. Note that every gate inbasisGateSet
should also be inqiskit.circuit.library
, and the whole gate set should be universal. Check IV. Method of qATG - Transpile for detailed descriptions. - Since the generator needs to simulate the circuit to checkout the repetition, overkill and test escape, thus we have to initialize the simulation setup first. Use
generator.configurationSimulationSetup()
to initialize the simulation setup, with the default values. -
generator.createTestConfiguration(singleFaultList, twoFaultList)
returns a list of configurations. The configuration is in typeqatgConfiguration
.singleFaultList
is the list of single-qubit faults, which is only[myUFault(qubit = 0)]
in this case;twoFaultList
is the list of two-qubit faults, which is a empty list in this case. - To get the configuration, use
configuration.getConfigurationQuantumCircuit()
forconfiguration
inconfigurationList
. It will return a qiskit circuit.
Since we will call lots of qiskit's methods, we hope that the gateType
should be qiskit.circuit.library
gates. And for the return gates of createFaulty
, we hope that the type of it should still be qiskit.circuit.library
gates, or other compatible types
- For
qiskit.circuit.library
gates, we haveqiskit.circuit.library.UGate
,qiskit.circuit.library.RXGate
,qiskit.circuit.library.RZGate
,qiskit.circuit.library.CXGate
, and so on. You can check Qiskit Circuit Library[target=_blank] for more details. Note that please seperate those single-qubit gates, two-qubit gates, and multi-qubit gates with more than two qubits as input. Our generator currently does not support multi-qubit gates faults with more than two qubits as input. - For "other compatible types", since the user-defined fault might be complex, user can construct a circuit based on given parameters, and consider the circuit as the faulty gate. Here is a brief example:
- Our fault-free gate is a CXGate, and I would like to implement my faulty gate as the gate shown below:
...where
$U_{F_1}$ and$U_{F_2}$ are some fixed-parameters UGate. - Thus I construct a circuit to describe my fault:
from qiskit import QuantumRegister, QuantumCircuit sub_q = QuantumRegister(2) sub_circ = QuantumCircuit(sub_q, name='myCNOTFault') sub_circ.u(0.05, 0.05, 0.05, 0) sub_circ.cx(0, 1) sub_circ.u(0.05, 0.05, 0.05, 1)
- Since
createFaulty
requires a gate, I changed the circuit into a gate by using qiskit's tools:from qiskit.converters import circuit_to_gate self.faultyGate = circuit_to_gate(sub_circ)
- Note that our generator will call
gate.to_matrix()
, which is a qiskit method, andto_matrix()
will returngate.__array__(dtype = numpy.complex)
. But for the gates that are converted from circuits, qiskit cannot figure out it's__array__
by it's own. Thus, we have to do this job for qiskit. Note thatgate.__array__
is a function, this allows qiskit to change it's dtype.import numpy as np from qatgUtil import U3 resultArray = np.kron(U3([0.05, 0.05, 0.05]), np.eye(2)) resultArray = np.matmul(qGate.CXGate().to_matrix(), resultArray) resultArray = np.matmul(np.kron(np.eye(2), U3([0.05, 0.05, 0.05])), resultArray) self.faultyGate.__array__ = lambda dtype = None: np.array(resultArray, dtype = dtype)
- Thus in
createFaulty
, we have:def createFaulty(self, parameters): return self.faultyGate
- Our fault-free gate is a CXGate, and I would like to implement my faulty gate as the gate shown below:
...where
qatgFault
has an optional argument called description
, where user can describe their fault verbally. It can help you debug if needed.
There are several optional parameters in qatg
initialization. Most of them are related to the method of qATG. Check IV. Method of qATG for more details.
-
quantumRegisterName
: the name of the quantum register in the configuration quantum circuit. Default: "q". -
classicalRegisterName
: the name of the classical register in the configuration quantum circuit. Default: "c". -
gridSlice
: the slice number while operating grid search. Default:$21$ . -
gradientDescentSearchTime
: the maximum search time while operating gradient descent. Default:$800$ . -
gradientDescentStep
: the gradient descent step while operating gradient descent. Default:$0.01$ . -
maxTestTemplateSize
: the maximum number of test elements in one test template. Default:$50$ . -
minRequiredEffectSize
: the minimum required effect size that halts the operation of adding new test elements into the test template. Default:$3$ .
There are also several optional parameters in qatg.configurationSimulationSetup
.
-
oneQubitErrorProb
: the depolarizing error probability of single-qubit gates while simulating the configuration. Default:$0.001$ . -
twoQubitErrorProb
: the depolarizing error probability of two-qubit gates while simulating the configuration. Default:$0.1$ . -
zeroReadoutErrorProb
: the readout error probability of state 0 when measuring during the simulation. Should be an 1x2 array with sum 1, for example,$[0.985, 0.015]$ . Default:$[0.985, 0.015]$ . -
oneReadoutErrorProb
: the readout error probability of state 1 when measuring during the simulation. Should be an 1x2 array with sum 1, for example,$[0.015, 0.985]$ . Default:$[0.015, 0.985]$ . -
targetAlpha
: required alpha for the configuration. Default:$0.99$ . -
targetBeta
: required beta for the configuration. Default:$0.999$ . -
simulationShots
: measure shots of the simulation. This value should be big since it's exploring the unknown distribution after the simulation. Default:$200000$ . -
testSampleTime
: how many samples should the simulator sample while calculating overkill and test escape. Default:$10000$ .
There are also several optional parameters in createTestConfiguration
.
-
singleInitialState
: the initial state of the quantum circuit while generating single-qubit gate test configurations. Default:$[1, 0]$ . -
twoInitialState
: the initial state of the quantum circuit while generating two-qubit gate test configurations. Default:$[1, 0, 0, 0]$ . -
simulateConfiguration
: simulate the configuration after generate it or not. If true, thenconfigurationSimulationSetup
must be called beforecreateTestConfiguration
. If false, the repetition, simulate overkill and test escape will benumpy.nan
. Default: True.
Not yet done this part. You can see (paper) for more details.
As to make sense, the gateType
of each single-qubit fault should be included in basisGateSet
.