refactoring

This commit is contained in:
Noa Aarts 2026-01-27 09:34:23 +01:00
parent 19e90b3d21
commit 421fb17062
Signed by: noa
GPG key ID: 1850932741EFF672
2 changed files with 77 additions and 52 deletions

View file

@ -20,10 +20,20 @@ PARENT_AMOUNT = 5
MUTATION_RATE = 0.1
gate_set = [
GateType.H,
GateType.RX,
GateType.RY,
GateType.RZ,
GateType.CRX,
GateType.CX,
]
def main():
seed_rng = random.Random(1020381)
initial_population: list[QuantumCircuit] = (
Stream(sample_random_generator(random.Random(101020), QUBITS, DEPTH))
Stream(sample_random_generator(random.Random(101020), QUBITS, DEPTH, gate_set))
.apply(lambda circ: print(circ))
.apply(
lambda circ: circ.expressibility_estimate(
@ -55,23 +65,20 @@ def main():
layer = child_layers[layer_idx]
gate_idx = main_rng.randrange(len(layer))
old_gate = child_layers[layer_idx][gate_idx]
match old_gate.type:
case GateType.H | GateType.RX | GateType.RY | GateType.RZ:
child_layers[layer_idx][gate_idx] = Gate(
main_rng.choice(
[GateType.H, GateType.RX, GateType.RY, GateType.RZ]
),
old_gate.qubits,
old_gate.param_idx,
)
case GateType.CRX | GateType.CX:
child_layers[layer_idx][gate_idx] = Gate(
old_gate.type,
tuple(old_gate.qubits[::-1]),
old_gate.param_idx,
)
case _:
print(f"unhandled gate: {old_gate}")
if old_gate.single():
child_layers[layer_idx][gate_idx] = Gate(
main_rng.choice(gate_set),
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.param_idx,
)
child = circ_from_layers(child_layers, QUBITS)
child.expressibility_estimate(2000, seed_rng.randint(1000, 1000000000))
offspring.append(child)

View file

@ -25,21 +25,40 @@ class GateType(IntEnum):
CZ = 8
CRX = 9
H = 10
I = 11
def single_typ(typ: GateType) -> bool:
match typ:
case GateType.I | GateType.H | GateType.RX | GateType.RY | GateType.RZ:
return True
case (
GateType.RXX
| GateType.RYY
| GateType.RZZ
| GateType.CX
| GateType.CZ
| GateType.CRX
):
return False
@dataclass(frozen=True)
class Gate:
type: GateType
typ: GateType
qubits: int | tuple[int, int]
param_idx: int
def to_json(self):
return {
"type": int(self.type),
"type": int(self.typ),
"qubits": self.qubits,
"param_idx": self.param_idx,
}
def single(self) -> bool:
return single_typ(self.typ)
def haar_fidelity_pdf(F: np.ndarray, d: int) -> np.ndarray:
# p(F) = (d-1) * (1-F)^(d-2), for F in [0,1]
@ -71,7 +90,7 @@ class QuantumCircuit:
path_counts = [1 for _ in range(self.qubits)]
for layer in self.gates:
for gate in layer:
if gate.type <= 3 or isinstance(gate.qubits, int):
if gate.typ <= 3 or isinstance(gate.qubits, int):
continue
(q1, q2) = gate.qubits
# same logic as your existing file
@ -99,33 +118,35 @@ class QuantumCircuit:
for layer in self.gates:
for gate in layer:
if gate.type == GateType.RX:
if gate.typ == GateType.RX:
theta = thetas[gate.param_idx]
qc.rx(theta, gate.qubits)
elif gate.type == GateType.RY:
elif gate.typ == GateType.RY:
theta = thetas[gate.param_idx]
qc.ry(theta, gate.qubits)
elif gate.type == GateType.RZ:
elif gate.typ == GateType.RZ:
theta = thetas[gate.param_idx]
qc.rz(theta, gate.qubits)
elif gate.type == GateType.H:
elif gate.typ == GateType.H:
qc.h(gate.qubits)
elif gate.type == GateType.RXX:
elif gate.typ == GateType.I:
qc.id(gate.qubits)
elif gate.typ == GateType.RXX:
theta = thetas[gate.param_idx]
qc.rxx(theta, *gate.qubits)
elif gate.type == GateType.RYY:
elif gate.typ == GateType.RYY:
theta = thetas[gate.param_idx]
qc.ryy(theta, *gate.qubits)
elif gate.type == GateType.RZZ:
elif gate.typ == GateType.RZZ:
theta = thetas[gate.param_idx]
qc.rzz(theta, *gate.qubits)
elif gate.type == GateType.CX:
elif gate.typ == GateType.CX:
qc.cx(*gate.qubits)
elif gate.type == GateType.CRX:
elif gate.typ == GateType.CRX:
theta = thetas[gate.param_idx]
qc.crx(theta, *gate.qubits)
else:
raise ValueError(f"Unknown gate type: {gate.type}")
raise ValueError(f"Unknown gate type: {gate.typ}")
return qc, thetas
def to_qiskit_for_expressibility(self) -> tuple[QiskitCircuit, ParameterVector]:
@ -205,7 +226,7 @@ class QuantumCircuit:
idx = 0
for gate in layer:
match gate.type:
match gate.typ:
case GateType.RX:
strs[gate.qubits] = strs[gate.qubits][:-2] + "RX"
case GateType.RY:
@ -311,23 +332,23 @@ def circ_from_layers(layers: list[list[Gate]], qubits: int) -> QuantumCircuit:
for layer in layers:
new_layer = []
for gate in layer:
match gate.type:
match gate.typ:
case GateType.H:
new_layer.append(Gate(gate.type, gate.qubits, params))
new_layer.append(Gate(gate.typ, gate.qubits, params))
total_single += 1
case GateType.RX | GateType.RY | GateType.RZ:
new_layer.append(Gate(gate.type, gate.qubits, params))
new_layer.append(Gate(gate.typ, gate.qubits, params))
params += 1
total_single += 1
case GateType.RXX | GateType.RYY | GateType.RZZ:
new_layer.append(Gate(gate.type, gate.qubits, params))
new_layer.append(Gate(gate.typ, gate.qubits, params))
params += 1
total_double += 1
case GateType.CX | GateType.CZ:
new_layer.append(Gate(gate.type, gate.qubits, params))
new_layer.append(Gate(gate.typ, gate.qubits, params))
total_double += 1
case GateType.CRX:
new_layer.append(Gate(gate.type, gate.qubits, params))
new_layer.append(Gate(gate.typ, gate.qubits, params))
params += 1
total_double += 1
gates.append(new_layer)
@ -335,7 +356,7 @@ def circ_from_layers(layers: list[list[Gate]], qubits: int) -> QuantumCircuit:
def sample_circuit_random(
rng: random.Random, qubits: int, depth: int
rng: random.Random, qubits: int, depth: int, gate_types: list[GateType]
) -> QuantumCircuit:
params = 0
total_single = 0
@ -349,14 +370,9 @@ def sample_circuit_random(
if loc in used_qubits:
continue
gate_type = rng.choice(
[
GateType.RX,
GateType.RY,
GateType.RZ,
GateType.CX,
GateType.CRX,
GateType.H,
]
gate_types
if loc + 1 < qubits
else [typ for typ in gate_types if single_typ(typ)]
)
match gate_type:
case GateType.H:
@ -368,13 +384,13 @@ def sample_circuit_random(
params += 1
total_single += 1
used_qubits.add(loc)
case GateType.RXX | GateType.RYY | GateType.RZZ if loc + 1 < qubits:
case GateType.RXX | GateType.RYY | GateType.RZZ:
layer.append(Gate(gate_type, (loc, loc + 1), params))
params += 1
total_double += 1
used_qubits.add(loc)
used_qubits.add(loc + 1)
case GateType.CX | GateType.CZ if loc + 1 < qubits:
case GateType.CX | GateType.CZ:
layer.append(
Gate(
gate_type,
@ -385,7 +401,7 @@ def sample_circuit_random(
total_double += 1
used_qubits.add(loc)
used_qubits.add(loc + 1)
case GateType.CRX if loc + 1 < qubits:
case GateType.CRX:
layer.append(
Gate(
gate_type,
@ -404,6 +420,8 @@ def sample_circuit_random(
return QuantumCircuit(qubits, gates, total_single, total_double, params)
def sample_random_generator(rng: random.Random, qubits: int, depth: int):
def sample_random_generator(
rng: random.Random, qubits: int, depth: int, gates: list[GateType]
):
while True:
yield sample_circuit_random(rng, qubits, depth)
yield sample_circuit_random(rng, qubits, depth, gates)