## Quantum Context and Simulator

### Quantum Context

First and foremost, Scotty is a high-level quantum framework that defines abstract quantum primitives. At the top of it all we have `QuantumContext`

—a trait with a handful of abstract methods. This is the heart of the framework and it’s meant to provide functions for quantum state and gate transitions that take place during circuit execution.

Here is a list of method signatures that `QuantumContext`

provides:

```
trait QuantumContext {
def tensorProduct(register: QubitRegister,
sp1: Superposition, sp2: Superposition): Superposition
def densityMatrix(vector: Vector): Matrix
def isUnitary(gate: TargetGate): Boolean
def probabilities(sp: Superposition): Seq[StateData]
def applyGate(state: Vector, gate: Gate): Unit
def run(circuit: Circuit): State
def measure(register: QubitRegister, state: Vector): Collapsed
def runAndMeasure(circuit: Circuit): Collapsed
def runExperiment(circuit: Circuit, trialsCount: Int): ExperimentResult
}
```

`Vector`

and `Matrix`

are defined in the following way:

```
type Vector = Array[Float]
type Matrix = Array[Array[Float]]
```

The framework makes no assumptions about the underlying state implementation. The only thing that’s expected is that `Vector`

and `Matrix`

arrays represent lists of complex numbers, each occupying two elements in the array for their real and imaginary components. There’s no built-in data type for complex numbers in Java, so we have to either represent them with objects (which is hugely inefficient for large arrays in most cases) or with two separate primitive elements. Scotty uses two floats to represent a complex number.

Java floats take up 32 bits each, so a complex number in Scotty takes up 64 bits. Since the state vector uses a Java array there’s a hard limit of `Integer.MAX_VALUE`

elements that it can have, which corresponds to elements in our case. It means that Scotty can represent states of up to 29 qubits.

There are many possible use cases where you’d want to roll out your own implementation of `QuantumContext`

. For example, if you have a distributed quantum simulator running in the cloud that you want to use to run bigger circuits then implementing `QuantumContext`

would make a lot of sense. The obvious benefit is that you get to keep your Scala programs and algorithms written with Scotty unmodified. Write once, run anywhere.

### Quantum Simulator

`QuantumSimulator`

is a built-in implementation of the `QuantumContext`

, which allows you to run up-to-29 qubit quantum circuit simulations. All simulation computations are (depending on your hardware) parallelizable on the CPU and you can control the underlying thread pool implementation by providing a custom execution context:

```
val ec = ExecutionContext.fromExecutor(
new java.util.concurrent.ForkJoinPool(8)
)
QuantumSimulator(ec)
```

`QuantumSimulator`

can also take a `Random`

instance. It’s useful when you need to specify a random seed:

```
QuantumSimulator(new Random(System.nanoTime))
```

The simulator has a `runExperiment`

method that runs multiple experiment trials. You can pass the number of trials to it and it will run them sequentially.

After all trials are done executing, the method returns an `ExperimentResult`

which contains a list of `Collapsed`

states after each experiment.

The `stateStats`

lazy variable is a list of tuples containing a binary representation of the collapsed state and the total number of state occurrences. Suppose, we entangle two qubits and run the experiment 1000 times:

```
QuantumSimulator()
.runExperiment(Circuit(H(0), CNOT(0, 1)), 1000)
.stateStats.toHumanString
```

As expected, we are going to end up with roughly 50% of both qubits being in the `00`

state and another 50% being in the `11`

state:

```
00: 483
01: 0
10: 0
11: 517
```

- Getting Started
- Quantum Context and Simulator
- Circuits and Qubits
- Superposition and Measurement
- Operations
- Standard Gates
- Modifiers and Custom Gates
- State Readers