Quantum circuit simulator in Swift
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.
Along side the simulator there is a genetic algorithm to automatically generate circuits as well as others useful algorithms for quantum computing.
Usage
Build & use a quantum circuit
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 matrix = Matrix([[Complex.one, Complex.zero, Complex.zero, Complex.zero],
[Complex.zero, Complex.one, Complex.zero, Complex.zero],
[Complex.zero, Complex.zero, Complex.zero, Complex.one],
[Complex.zero, Complex.zero, Complex.one, Complex.zero]])
let gates = [
Gate.hadamard(target: 3),
Gate.controlledMatrix(matrix: matrix, inputs: [3, 4], control: 1),
Gate.controlledNot(target: 0, control: 3),
Gate.matrix(matrix: matrix, inputs: [3, 2]),
Gate.not(target: 1),
Gate.oracle(truthTable: ["01", "10"], target: 3, controls: [0, 1]),
Gate.phaseShift(radians: 0.25, target: 0)
]
//: 2. (Optional) Draw the quantum circuit to see how it looks
let drawer = MainDrawerFactory().makeDrawer()
drawer.drawCircuit(gates).get()
//: 3. Build the quantum circuit with the list of gates
let circuit = MainCircuitFactory().makeCircuit(gates: gates)
//: 4. Use the quantum circuit
let statevector = circuit.statevector().get()
print("Statevector: \(statevector)\n")
print("Probabilities: \(statevector.probabilities())\n")
print("Summarized probabilities: \(statevector.summarizedProbabilities())\n")
let groupedProbs = statevector.groupedProbabilities(byQubits: [1, 0],
summarizedByQubits: [4, 3, 2]).get()
print("Grouped probabilities: \(groupedProbs)")
print("Unitary: \(circuit.unitary().get())\n")
Check full code in Circuit.playground.
Draw a quantum circuit
Check full code in Drawer.playground.
Use a genetic algorithm to automatically generate a quantum circuit
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).get()
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.
Other examples
Check following playgrounds for more examples:
- BernsteinVaziraniAlgorithm.playground - Bernstein–Vazirani algorithm.
- DeutschAlgorithm.playground - Deutsch's algorithm.
- DeutschJozsaAlgorithm.playground - Deutsch-Jozsa algorithm.
- GroverAlgorithm.playground - Grover's algorithm.
- ShorAlgorithm.playground - Shor's Algorithm.
- SimonPeriodicityAlgorithm.playground - Simon's periodicity algorithm.
Other algorithms
Euclidean Algorithm: Find greatest common divisor of two integers
import SwiftQuantumComputing // for macOS
//: 1. Define two integers
let a = 252
let b = 105
//: 2. Use Euclidean solver to find greatest common divisor of these integers
let gcd = EuclideanSolver.findGreatestCommonDivisor(a, b)
print("Greatest common divisor of \(a) & \(b): \(gcd)")
Check full code in EuclideanAlgorithm.playground.
Continued Fractions: Find an approximation to a given rational number
import SwiftQuantumComputing // for macOS
//: 1. Define rational value to approximate
let value = Rational(numerator: 15, denominator: 11)
//: 2. And a limit or maximum difference between approximation and original value
let limit = Rational(numerator: 1, denominator: 33)
//: 3. Use Continued Fractions solver to find a solution
let approximation = ContinuedFractionsSolver.findApproximation(of: value,
differenceBelowOrEqual: limit).get()
print("Approximation for \(value) (limit: \(limit)): \(approximation)")
Check full code in ContinuedFractions.playground.
Gaussian Elimination: Solve a system of XOR equations
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.
Documentation
Documentation for the project can be found here.
Linux
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.