A quantum circuit simulator written in Swift and accelerated with Accelerate.framework in iOS/macOS and BLAS in Linux.
Along side the simulator there is a genetic algorithm to automatically generate circuits and an implementation of Gaussian elimination algorithm to solve systems of XOR equations.
The code written so far is mostly based on the content of: Quantum Computing for Computer Scientists, with a few tips from Automatic Quantum Computer Programming: A Genetic Programming Approach. It is also inspired by IBM Qiskit.
import SwiftQuantumComputing // for macOS
//: 1. Compose a list of quantum gates. Insert them in the same order
//: you want them to appear in the quantum circuit
let gates = [
Gate.controlledNot(target: 0, control: 2),
Gate.hadamard(target: 1),
Gate.matrix(matrix: Matrix([[Complex(0), Complex(1)], [Complex(1), Complex(0)]]), inputs: [2]),
Gate.not(target: 1),
Gate.oracle(truthTable: ["00", "11"], target: 0, controls: [2, 1]),
Gate.phaseShift(radians: 0, target: 2)
]
//: 2. (Optional) Draw the quantum circuit to see how it looks
let drawer = MainDrawerFactory().makeDrawer()
drawer.drawCircuit(gates)
//: 3. Build the quantum circuit with the list of gates
let circuit = MainCircuitFactory().makeCircuit(gates: gates)
//: 4. Use the quantum circuit
print("Statevector: \(circuit.statevector())\n")
print("Probabilities: \(circuit.probabilities())\n")
print("Summarized probabilities: \(circuit.summarizedProbabilities())\n")
print("Unitary: \(circuit.unitary())\n")
Check full code in Circuit.playground.
Check full code in Drawer.playground.
import SwiftQuantumComputing // for macOS
//: 1. Define a configuration for the genetic algorithm
let config = GeneticConfiguration(depth: (1..<50),
generationCount: 2000,
populationSize: (2500..<6500),
tournamentSize: 7,
mutationProbability: 0.2,
threshold: 0.48,
errorProbability: 0.000000000000001)
//: 2. Also the uses cases, i.e. the circuit outputs you want to get
//: when the oracle is configured with the different truth tables
let cases = [
GeneticUseCase(emptyTruthTableQubitCount: 1, circuitOutput: "00"),
GeneticUseCase(truthTable: ["0", "1"], circuitOutput: "00"),
GeneticUseCase(truthTable: ["0"], circuitOutput: "10"),
GeneticUseCase(truthTable: ["1"], circuitOutput: "10")
]
//: 3. And which gates can be used to find a solution
let gates: [ConfigurableGate] = [HadamardGate(), NotGate()]
//: 4. Now, run the genetic algorithm to find/evolve a circuit that solves
//: the problem modeled with the use cases
let evolvedCircuit = MainGeneticFactory().evolveCircuit(configuration: config,
useCases: cases,
gates: gates)
print("Solution found. Fitness score: \(evolvedCircuit.eval)")
for useCase in cases {
//: 5. (Optional) Draw the solution (check `Sources` folder in Playground for the source code)
let evolvedGates = configureEvolvedGates(in: evolvedCircuit, with: useCase)
drawCircuit(with: evolvedGates, useCase: useCase)
//: 6. (Optional) Check how well the solution found meets each use case
//: (check `Sources` folder in Playground for the source code)
let probs = probabilities(in: evolvedGates, useCase: useCase)
print(String(format: "Use case: [%@]. Input: %@ -> Output: %@. Probability: %.2f %%",
useCase.truthTable.truth.joined(separator: ", "),
useCase.circuit.input,
useCase.circuit.output,
(probs[useCase.circuit.output] ?? 0.0) * 100))
}
Check full code in Genetic.playground.
import SwiftQuantumComputing // for macOS
//: 1. Define system of XOR equations:
//: * `x6 ^ x4 ^ x2 ^ x1 = 0`
//: * ` x4 ^ x0 = 0`
//: * `x6 ^ x5 ^ x2 ^ x0 = 0`
//: * ` x4 ^ x3 ^ x1 ^ x0 = 0`
//: * ` x5 ^ x3 ^ x0 = 0`
//: * ` x4 ^ x3 ^ x1 = 0`
//: * ` x5 ^ x4 ^ x2 ^ x1 ^ x0 = 0`
let equations = [
"1010110",
"0010001",
"1100101",
"0011011",
"0101001",
"0011010",
"0110111"
]
//: 2. Build Gaussian elimination solver
let solver = MainXorGaussianEliminationSolverFactory().makeSolver()
//: 3. Use solver
print("Solutions: \(solver.findActivatedVariablesInEquations(equations))")
Check full code in XorGaussianElimination.playground.
Check following playgrounds for more examples:
- BernsteinVaziraniAlgorithm.playground - Bernstein–Vazirani algorithm.
- DeutschAlgorithm.playground - Deutsch's algorithm.
- DeutschJozsaAlgorithm.playground - Deutsch-Jozsa algorithm.
- SimonPeriodicityAlgorithm.playground - Simon's periodicity algorithm.
Documentation for the project can be found here.
As mentioned above, this package depends on BLAS if running on Linux, more exactly, Ubuntu.
This dependency is reflected in Package.swift
with CBLAS-Linux, which in turn expects to find the following file: /usr/include/x86_64-linux-gnu/cblas-netlib.h
. So, after installing BLAS (in case it is not already there):
sudo apt-get install libblas-dev
Check cblas-netlib.h
is in the expected location.