File size: 3,913 Bytes
bc6498b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
#!/usr/bin/env python3
"""Fixed Guppy Grover emulator for n=2 and n=3"""
from guppylang import guppy
from guppylang.std.builtins import result
from guppylang.std.quantum import qubit, h, x, cx, cz, measure
import math
import argparse
import csv
import json
@guppy
def grover_n2_marked_11() -> None:
"""Grover for n=2, marking |11⟩"""
# Initialize qubits
q0 = qubit()
q1 = qubit()
# Initial superposition
h(q0)
h(q1)
# Grover iteration (optimal is 1 iteration for n=2)
# Oracle for |11⟩
cz(q0, q1)
# Diffusion operator
h(q0)
h(q1)
x(q0)
x(q1)
h(q1)
cx(q0, q1)
h(q1)
x(q0)
x(q1)
h(q0)
h(q1)
# Measure
r0 = measure(q0)
r1 = measure(q1)
result("b0", r0)
result("b1", r1)
@guppy
def grover_n2_marked_10() -> None:
"""Grover for n=2, marking |10⟩"""
q0 = qubit()
q1 = qubit()
# Initial superposition
h(q0)
h(q1)
# Oracle for |10⟩
x(q1) # Flip phase for |10⟩
cz(q0, q1)
x(q1)
# Diffusion
h(q0)
h(q1)
x(q0)
x(q1)
h(q1)
cx(q0, q1)
h(q1)
x(q0)
x(q1)
h(q0)
h(q1)
# Measure
r0 = measure(q0)
r1 = measure(q1)
result("b0", r0)
result("b1", r1)
def run_grover_n2(pattern, shots=1000):
"""Run Grover for n=2 qubits"""
if pattern == 3: # |11⟩
sim = grover_n2_marked_11.emulator(n_qubits=2)
sim = sim.with_shots(shots)
results = sim.run()
elif pattern == 2: # |10⟩
sim = grover_n2_marked_10.emulator(n_qubits=2)
sim = sim.with_shots(shots)
results = sim.run()
else:
raise ValueError(f"Pattern {pattern} not implemented")
# Count successes
success_count = 0
pattern_bits = format(pattern, '02b')
for shot in results.results:
bits = ""
for entry in shot.entries:
if entry[0] == 'b0':
bits = str(entry[1]) + bits[1:] if len(bits) > 0 else str(entry[1])
elif entry[0] == 'b1':
bits = bits[0] + str(entry[1]) if len(bits) > 0 else "0" + str(entry[1])
if bits == pattern_bits:
success_count += 1
return success_count / shots
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--n", type=int, default=2, choices=[2])
ap.add_argument("--pattern", type=int, default=3)
ap.add_argument("--shots", type=int, default=1000)
ap.add_argument("--csv", type=str, default="guppy_results.csv")
args = ap.parse_args()
# Run for different k values (for n=2, optimal k=1)
print(f"\n{'='*60}")
print(f"GUPPY/SELENE GROVER EMULATOR - n={args.n}, pattern={args.pattern:02b}")
print(f"{'='*60}\n")
# For n=2, we run the circuit (which has k=1 built in)
p_success = run_grover_n2(args.pattern, args.shots)
k_opt = 1 # Optimal for n=2
results = {
"n": args.n,
"pattern": format(args.pattern, '02b'),
"k": k_opt,
"shots": args.shots,
"p_success": round(p_success, 3),
"backend": "guppy/selene"
}
print(f"Results: {json.dumps(results, indent=2)}")
# Save to CSV
with open(args.csv, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["n", "m", "marked", "k", "backend", "shots", "p_success", "wall_s", "k_opt"])
writer.writerow([args.n, 1, format(args.pattern, '02b'), k_opt, "guppy", args.shots, p_success, None, k_opt])
print(f"\n✅ Results saved to {args.csv}")
# Theoretical comparison
theoretical = 1.0 # For n=2, k=1 gives 100% success
print(f"\nTheoretical p_success: {theoretical:.3f}")
print(f"Achieved p_success: {p_success:.3f}")
print(f"Difference: {abs(theoretical - p_success):.3f}")
if __name__ == "__main__":
main() |