Modifiers and Custom Gates
Gate Modifiers
Scotty provides two modifiers that can be applied to some gates: Controlled
and Dagger
.
Controlled
implements the ControlGate
trait. You can use it by setting the control index and the target gate. The target gate can be a controlled gate or a target gate (but not a swap gate). The simulator allows for as many qubits in between control and target qubit indexes as you want. You can also have qubits set in any order.
Dagger
is a modifier that takes the complex conjugate transpose of a single-qubit gate matrix.
You can mix and match modifiers and gates in any way you see fit as long as the final controlled gate is a TargetGate
:
Controlled(0, Dagger(Y(1))
Custom Gates
Scotty provides two abstractions for custom gates: DefGate
and CompositeGate
. DefGate
lets you to define single-qubit gates with your own matrix.
Here is how you can define a simple square root of NOT gate:
import scotty.quantum.math.Complex
val matrix = Array(
Array(Complex(0.5, 0.5), Complex(0.5, -0.5)),
Array(Complex(0.5, -0.5), Complex(0.5, 0.5))
).toFloat
def SqrtNot(index: Int) = DefGate(matrix, index)
Now you can use SqrtNot
as any other gate:
QuantumSimulator().run(Circuit(X(1), SqrtNot(1)))
Complex
is a complex number representation provided by the framework. It has two Float
parameters: one for the real part and one for the imaginary part. Gates use a more bare-bones representation of the matrix for performance reasons: Array[Array[Float]]
. It represents complex numbers by putting real and imaginary float components next to each other. You can still define your gates with the Complex
helper but you have to use the implicit toFloat
method to convert your matrix array before passing it to DefGate
.
To define a custom parametric gate use another DefGate
constructor that takes a MatrixGen
(which is a shorthand for type Seq[Float] => Matrix
) and a list of Double
parameters. Here’s an example of a custom phase shift gate:
import scotty.quantum.math.Complex
val matrix = (params: Seq[Double]) => Array(
Array(Complex(1), Complex(0)),
Array(Complex(0), Complex(Math.cos(params(0)), Math.sin(params(0))))
).toFloat
def QuarterPhase(phi: Double, index: Int) = DefGate(matrix, phi / 4, index)
Here’s how you can use it:
QuarterPhase(Math.PI, 0)
Finally, you can define CompositeGate
s to describe multi-qubit unitary gates. Some gates in the Scotty simulator use this technique. For example, the SWAP
gate is implemented as a function that takes custom indexes as two parameters and returns a CompositeGate
:
def SWAP(i0: Int, i1: Int) = CompositeGate(CNOT(i0, i1), CNOT(i1, i0), CNOT(i0, i1))
You can use this approach to define your own gates and unitary operations.
- Getting Started
- Quantum Context and Simulator
- Circuits and Qubits
- Superposition and Measurement
- Operations
- Standard Gates
- Modifiers and Custom Gates
- State Readers