Gates in qsearch

The classes representing quantum gates are found in gates.py, and are subclasses of qsearch.gates.Gate. You will need to work with Gate objects to crate custom gatesets, and you will get a Gate object as a return value from compilation.

# Here are some examples of what you can do with Gate objects
U3 = qsearch.U3Gate()
CNOT = qsearch.CNOTGate()

# get the matrix that a gate represents in a numpy matrix format
U3_unitary = U3.matrix([np.pi/2, np.pi/4, np./pi/6]) # the array of parameters must be provided
CNOT_unitary = CNOT.matrix([]) # cnot takes no parameters so an empty array is provided

# combine multiple gates to form a larger circuit
mycircuit = ProductGate(KroneckerGate(U3,U3), CNOT) # note that mycircuit is itself an instance of Gate

Provided Gates

For more information, see the API documentation in qsearch.gates.

Custom Gates

There is an existing gate that can be customized to your needs. However it will not show up when you assembly the circuit to OpenQASM or Qiskit.

  • UGate - represents the gate deqsribed by the unitary U passed to __init__, and takes up qudits qudits.

You can also write your own Gate subclasses the required functions are:

  • __init__ - you must customize the initializer to set self.num_inputs to the number of parameters for the gate (e.g. 3 for U3 or ZXZXZ, 0 for CNOT), and self.qudits to the number of qudits used by the gate (e.g. 1 for U3 or ZXZXZ, 2 for CNOT).

  • matrix(v) - here you generate and return the matrix represented by your gate when passed the parameters provided in the array v.

Assembling with Custom Gates

If you want your code to output your custom gates when assembling, you must implement assemble as well.

  • assemble(v, i) - here you are given v, the list of parameters needed for your gate, and i, the index of the first qubit in the set of qubits that your gate is assigned. You must return an array of the form [gate1, gate2] where gate1 and gate2 are tuples that represent gates that the assembler will be able to interpret. For example, ZXZXZGate returns an array for 5 tuples, one for each of the Z and X gates that it is based on, but U3Gate only returns an array of 1 tuple because the assembler interprets it as a single gate. The tuples take the form ("gate", gatename, parameters, indices), where the word “gate” is included to specify that this tuple represents a well defined gate as opposed to a Kronecker product of gates, gatename is a string that will be used to look up the relevant format to print this gate when assembling, and parameters is a list of the parameters formatted and organized the way they are needed to fill the format specified in the assembler, and indices is a list of the indices of the involved qubits.

Faster Solving with Jacobians

If you would like to take advantage of faster solvers that can take advantage of the Jacobian (marked with Jac in their name), and your custom gate uses one or more parameters, you will need to implement mat_jac as well.

  • mat_jac(v) - here you generate and return a tuple (U, [J1, ... ,Jn]) where U is the same matrix you would return in matrix, and [J1, ... ,Jn] is a list of matrix derivatives, where J1 is the matrix of derivatives with respect to the first parameter in v, and so on for all the parameters in v. If your custom gate is constant (self.num_inputs == 0), then you can take advantage of Jacobian solvers without implementing mat_jac yourself.