Skip to content

Quick Guide

Chin-Yang Jen edited this page Feb 6, 2022 · 7 revisions

qATG Quick Guide

v. Jan.2022
Authors: Chin-Yang Jen, Chin-Huan Wang, Cheng-Yun Hsieh, Yu-Min Li and James Chien-Mo Li

I. Introduction

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.

II. Quick Start

This guide leads you to generate your first test configuration.

Declare Faults

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.

  1. import qiskit.circuit.library as qGate is an important part in our project, since we need qiskit to work on our configuration. The parameter gateType of qatgFault must be one of the qiskit.circuit.library gates. Details is written in III. Detailed Arguments - About Faults' Gate Types.
  2. class myUFault(qatgFault): inherits our class qatgFault.
  3. In qatgFault there are two necessary arguments: gateType and qubit. The type of the fault would be gateType, and the fault will happen on qubit #qubit.
  4. 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.
  5. 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 have UGate(theta, phi, lambda) as our fault-free gate, self.createFaulty([theta, phi, lambda]) will return UGate(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 the qiskit.circuit.library gates, or other compatible types. Details is written in III. Detailed Arguments - About Faults' Gate Types.

Generate Test Templates

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:

  1. qatg(circuitSize, basisGateSet) returns a object with class qatg, which is our test generator. circuitSize gives the circuit size of the quantum circuit (and the qubits will be numbered into 0 ~ (circuitSize-1)), and basisGateSet is a list that contains the basis gates that the quantum circuit supports, only single-qubit gates. Note that every gate in basisGateSet should also be in qiskit.circuit.library, and the whole gate set should be universal. Check IV. Method of qATG - Transpile for detailed descriptions.
  2. 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.
  3. generator.createTestConfiguration(singleFaultList, twoFaultList) returns a list of configurations. The configuration is in type qatgConfiguration. 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.
  4. To get the configuration, use configuration.getConfigurationQuantumCircuit() for configuration in configurationList. It will return a qiskit circuit.

III. Detailed Arguments

qatgFault

About Faults' Gate Types

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

  1. For qiskit.circuit.library gates, we have qiskit.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.
  2. 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:
    1. 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.
    2. 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)
      
    3. 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)
      
    4. Note that our generator will call gate.to_matrix(), which is a qiskit method, and to_matrix() will return gate.__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 that gate.__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)
      
    5. Thus in createFaulty, we have:
      def createFaulty(self, parameters):
          return self.faultyGate
      

Description

qatgFault has an optional argument called description, where user can describe their fault verbally. It can help you debug if needed.

qatg

Initialization

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$.

Simulation Setup

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$.

Create Test Configuration

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, then configurationSimulationSetup must be called before createTestConfiguration. If false, the repetition, simulate overkill and test escape will be numpy.nan. Default: True.

IV. Method of qATG

Not yet done this part. You can see (paper) for more details.

Transpile

As to make sense, the gateType of each single-qubit fault should be included in basisGateSet.

V. Appendix