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