Scotty 0.6.0 Released
This is a very important update that focuses on the simulator performance. In addition to the state vector memory allocation optimizations we rewrote the gate application algorithm from scratch. The new algorithm is three orders of magnitude faster than what we had before. In practical terms, it means that users can run much larger circuits in a fraction of the time required before. For example, a 15-qubit circuit with 1,000 gates now runs in under one second on a 4.2 GHz Intel Core i7 box. A 20-qubit circuit with 1,000 gates runs in about 20 seconds. Users can realistically run shallower circuits of up to 27 qubits with the max of 29 qubits.
In order to optimize for memory usage, we replaced the double-precision (
Double) complex number representation with regular
Floats. This cut our memory usage in half. Now, every complex number takes up 64 bits instead of 128. It means that
Matrix types were redefined as:
type Vector = Array[Float] type Matrix = Array[Array[Float]]
Multi-Trial Experiment Changes
runAndMeasure version of the method that ran multiple trials of the same circuit was renamed to
runExperiment to avoid confusion with the single shot
We also removed parallelism support for multiple trials since it doesn’t make sense to run experiments in parallel given that state initialization, gate application, and probability calculations are already parallelized.
Single-qubit gate implementations now live at the framework level. Some are implemented with matrices and some are expressed through other gates.
CircuitConnector was removed in favor of
CompositeGate. You can define
CompositeGates to describe multi-qubit unitary gates and operations. Some gates in the Scotty simulator now use this technique. For example, the
SWAP gate is implemented as a function that takes custom indexes as two parameters and returns a
def SWAP(i0: Int, i1: Int) = CompositeGate(CNOT(i0, i1), CNOT(i1, i0), CNOT(i0, i1))
Performance improvements forced us to introduce limitations to how
Controlled modifiers work. Now,
Dagger can only be applied to single-qubit gates and
Controlled can either be applied to other
Controlled gates or single-qubit gates. This behavior might change in the future.
QubitRegister can now be initialized from a binary string or an integer:
QubitRegister("1001") // is equivalent to QubitRegister(9)
Circuit also received a couple of helper methods for quick register initialization. Here are all the different ways you can set a custom register:
Circuit(CNOT(0, 2)).withRegister(QubitRegister(Qubit.one, Qubit.zero, Qubit.zero)) Circuit(CNOT(0, 2)).withRegister(Qubit.one, Qubit.zero, Qubit.zero) Circuit(CNOT(0, 2)).withRegister("100") Circuit(CNOT(0, 2)).withRegister(4)