diff --git a/flake.nix b/flake.nix index e359360..f90c706 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,7 @@ ppkgs.tqdm ppkgs.qiskit ppkgs.qiskit-aer + ppkgs.matplotlib ])) ]; }; diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/best_circuits.png b/src/best_circuits.png new file mode 100644 index 0000000..1183ddf Binary files /dev/null and b/src/best_circuits.png differ diff --git a/src/ga_qas.py b/src/ga_qas.py index 9b4f262..e4b1d76 100755 --- a/src/ga_qas.py +++ b/src/ga_qas.py @@ -3,24 +3,22 @@ # "Genetic optimization of ansatz expressibility for enhanced variational quantum algorithm performance" import random -from quantum_circuit import ( - Gate, - GateType, - QuantumCircuit, - circ_from_layers, - sample_random_generator, -) + +import matplotlib.pyplot as plt + from qas_flow import Stream +from quantum_circuit import (Gate, GateType, QuantumCircuit, circ_from_layers, + sample_random_generator, single_typ) -DEPTH = 20 -QUBITS = 5 -GENERATIONS = 20 -GENERATION_SIZE = 20 -PARENT_AMOUNT = 5 -MUTATION_RATE = 0.1 +DEPTH: int = 6 +QUBITS: int = 6 +GENERATIONS: int = 40 +GENERATION_SIZE: int = 60 +PARENT_AMOUNT: int = 10 +MUTATION_RATE: float = 0.1 -gate_set = [ +gate_set: list[GateType] = [ GateType.H, GateType.RX, GateType.RY, @@ -30,8 +28,15 @@ gate_set = [ ] -def main(): - seed_rng = random.Random(1020381) +def plot_best_circuits(best_circuits: list[QuantumCircuit]) -> None: + fig, ax = plt.subplots() + + ax.plot([-circ.expressibility for circ in best_circuits]) + fig.savefig("best_circuits.png") + + +def main() -> None: + seed_rng: random.Random = random.Random(1020381) initial_population: list[QuantumCircuit] = ( Stream(sample_random_generator(random.Random(101020), QUBITS, DEPTH, gate_set)) .apply(lambda circ: print(circ)) @@ -49,6 +54,8 @@ def main(): main_rng = random.Random(2837175) + best_circuits: list[QuantumCircuit] = [] + for generation in range(GENERATIONS): print(f"starting generation {generation}") population.sort(key=lambda qc: qc.expressibility, reverse=True) @@ -68,22 +75,35 @@ def main(): if old_gate.single(): child_layers[layer_idx][gate_idx] = Gate( - main_rng.choice(gate_set), + main_rng.choice( + [gate for gate in gate_set if single_typ(gate)] + ), old_gate.qubits, old_gate.param_idx, ) else: child_layers[layer_idx][gate_idx] = Gate( old_gate.typ, - tuple(old_gate.qubits[::-1]), + (old_gate.qubits[1], old_gate.qubits[0]), old_gate.param_idx, ) child = circ_from_layers(child_layers, QUBITS) child.expressibility_estimate(2000, seed_rng.randint(1000, 1000000000)) offspring.append(child) + + offspring.sort(key=lambda qc: qc.expressibility, reverse=True) + if population[0].expressibility > offspring[0].expressibility: + print(f"best parent > best child") + best_circuits.append(population[0]) + else: + print(f"best child > best parent") + best_circuits.append(offspring[0]) population = offspring + plot_best_circuits(best_circuits) + plt.show() + if __name__ == "__main__": main() diff --git a/src/quantum_circuit.py b/src/quantum_circuit.py index e656ca8..f3d7e87 100644 --- a/src/quantum_circuit.py +++ b/src/quantum_circuit.py @@ -1,11 +1,12 @@ -from dataclasses import dataclass import math import random -from typing import override -import numpy as np +from dataclasses import dataclass from enum import IntEnum +from typing import override -from qiskit import QuantumCircuit as QiskitCircuit, transpile +import numpy as np +from qiskit import QuantumCircuit as QiskitCircuit +from qiskit import transpile from qiskit.circuit import ParameterVector, ParameterVectorElement from qiskit_aer import AerSimulator @@ -369,11 +370,10 @@ def sample_circuit_random( for loc in range(qubits): if loc in used_qubits: continue - gate_type = rng.choice( - gate_types - if loc + 1 < qubits - else [typ for typ in gate_types if single_typ(typ)] - ) + if loc + 1 < qubits: + gate_type = rng.choice(gate_types) + else: + gate_type = rng.choice([typ for typ in gate_types if single_typ(typ)]) match gate_type: case GateType.H: layer.append(Gate(gate_type, loc, params))