-
-
Notifications
You must be signed in to change notification settings - Fork 42
Description
Let me report a possible problem in the near-Clifford simulation. The below code initializes a surface quantum error correction code in a T+ state and calculates 200 shots of its logical measurements out of raw 'physical' ones in X basis. The logical measurements are then saved into the logical_measurements.json file. If one puts the default 'lightning.qubit' device of PennyLane, the statistics would be something like 170 0s against 30 1s, which approaches the predicted value of sqrt(2)/2 ~= 0.7. However, with the shown QRack device I get inconsistent results which is far from expectations (e.g. 91/109 or 114/86).
I'm using pennylane 0.43.1, pennylane_catalyst 0.13.0, pennylane_qrack 0.25.0 (compiled from source). The simulation is done with isTensorNetwork flag set to False.
Can we improve the precision of this simulation mode? Does it have a maximum-precision mode which would match the statevector method's precision? Please let me know, I will be glad to debug or adjust parameters.
--
The runnable program:
import json
import time
from contextlib import contextmanager
from signal import ITIMER_REAL, setitimer
from functools import reduce
import pennylane as qml
from catalyst import qjit, measure as catalyst_measure
num_shots = 200
nattempts = 1
timeout = 3000.0
dry_run = False
@contextmanager
def with_alarm(timeout: float):
timer_set = False
try:
if timeout is not None and 0 < timeout < float("inf"):
setitimer(ITIMER_REAL, timeout)
timer_set = True
yield
finally:
if timer_set:
setitimer(ITIMER_REAL, 0)
def dump_logical_observables(measurement_attempts) -> None:
""" For each observable, calculate its value from measurements (by xor-ing them) and dump to the
configured JSON file. """
logical_values_attempts = []
logical_measurements = {'q1_X_0': ('c_(0, 0, 0)_0', 'c_(1, 0, 0)_0', 'c_(2, 0, 0)_0', 'c_(2, 1, 1)_0', 'c_(0, 1, 1)_0')}
for attempt_shots in measurement_attempts:
if not attempt_shots:
continue
nshots = len(attempt_shots)
logical_values = {}
for lol, meas_labels in logical_measurements.items():
lo_shots = []
for i in range(nshots):
shot_dict = attempt_shots[i]
samples = [int(shot_dict[l]) for l in meas_labels]
lo_value = reduce(lambda a,b: a ^ b, samples)
lo_shots.append(int(lo_value))
logical_values[lol] = lo_shots
logical_values_attempts.append(logical_values)
with open("logical_measurements.json", "w") as f:
json.dump(logical_values_attempts, f)
if not dry_run:
@qjit
@qml.qnode(qml.device("qrack.simulator",wires=17,isTensorNetwork=False,isStabilizerHybrid=True,isOpenCL=True,isPaged=False,isCpuGpuHybrid=False,), shots=num_shots)
def pl_main():
# PennyLane Program Generated from Eka
# Initialize Wires from Eka quantum channels Ids
measurements = {}
qml.registers({'a643ceef-00bc-44cd-8514-b7b8cbe8bf95': 1, 'f0252ea6-ffa6-40f9-a8cf-aa886542e808': 1, '64a8a798-6799-4dde-8eb3-c4e1c3591cc8': 1, '18823f07-02b7-4965-9f2b-63737573cd92': 1, 'e299cd6f-5b93-4001-92bc-eff2ac056fff': 1, 'e6f6e48b-741f-471a-a0f6-20c0006971cd': 1, 'bf7ed026-3336-4705-a285-17c9b788d74d': 1, '3adeb324-cb13-4eaf-9c84-6d286ee08c4b': 1, '18788481-309e-4b4f-b8de-f81f5ebe0b49': 1, '123d3886-b07a-4655-a739-5f9ef84a1170': 1, '1fb8be97-58fa-48c3-812d-e946b2e6e58d': 1, 'c2e764ee-9cb3-4115-82e7-384bda96e261': 1, 'e6dd20b2-4b29-4abd-9bf5-25f109954f51': 1, '25b6c46e-948f-4ffd-a5a3-ca9c190d6598': 1, '7fb8aa79-b6a4-4a31-81fb-705992eee653': 1, 'd5c2ab4f-ac70-4df2-8413-60d7219cdc2c': 1, 'ca4f79db-08f6-4011-9d58-11f5a350911c': 1})
# Start of circuit: final circuit
# Start of circuit: inject t into block q1 and measure syndromes
# Start of circuit: inject t into block q1
# Start of circuit: resource state reset
catalyst_measure(5, reset=True)
qml.Hadamard([5])
qml.T([5])
# End of circuit: resource state reset
# Start of circuit: reset four quadrants
catalyst_measure(0, reset=True)
qml.Hadamard([0])
catalyst_measure(1, reset=True)
qml.Hadamard([1])
catalyst_measure(12, reset=True)
qml.Hadamard([12])
catalyst_measure(14, reset=True)
qml.Hadamard([14])
catalyst_measure(4, reset=True)
catalyst_measure(10, reset=True)
catalyst_measure(3, reset=True)
catalyst_measure(7, reset=True)
# End of circuit: reset four quadrants
# End of circuit: inject t into block q1
# Start of circuit: measure q1 syndromes 1 time(s)
# Start of circuit: measure q1 syndromes - cycle 0
catalyst_measure(6, reset=True)
catalyst_measure(15, reset=True)
catalyst_measure(8, reset=True)
catalyst_measure(13, reset=True)
catalyst_measure(2, reset=True)
catalyst_measure(16, reset=True)
catalyst_measure(11, reset=True)
catalyst_measure(9, reset=True)
qml.Hadamard([6])
qml.Hadamard([15])
qml.Hadamard([8])
qml.Hadamard([13])
qml.Hadamard([2])
qml.Hadamard([16])
qml.Hadamard([11])
qml.Hadamard([9])
qml.CZ([6, 4])
qml.CZ([15, 12])
qml.CNOT([8, 5])
qml.CNOT([13, 10])
qml.CNOT([2, 0])
qml.CZ([9, 7])
qml.CZ([6, 0])
qml.CZ([15, 5])
qml.CNOT([8, 7])
qml.CNOT([13, 12])
qml.CNOT([2, 1])
qml.CZ([9, 3])
qml.CZ([6, 5])
qml.CZ([15, 14])
qml.CNOT([8, 1])
qml.CNOT([13, 4])
qml.CNOT([16, 12])
qml.CZ([11, 10])
qml.CZ([6, 1])
qml.CZ([15, 7])
qml.CNOT([8, 3])
qml.CNOT([13, 5])
qml.CNOT([16, 14])
qml.CZ([11, 4])
qml.Hadamard([6])
qml.Hadamard([15])
qml.Hadamard([8])
qml.Hadamard([13])
qml.Hadamard([2])
qml.Hadamard([16])
qml.Hadamard([11])
qml.Hadamard([9])
measurements["c_(1, 1, 1)_0"] = catalyst_measure(6)
measurements["c_(2, 2, 1)_0"] = catalyst_measure(15)
measurements["c_(1, 2, 1)_0"] = catalyst_measure(8)
measurements["c_(2, 1, 1)_0"] = catalyst_measure(13)
measurements["c_(0, 1, 1)_0"] = catalyst_measure(2)
measurements["c_(3, 2, 1)_0"] = catalyst_measure(16)
measurements["c_(2, 0, 1)_0"] = catalyst_measure(11)
measurements["c_(1, 3, 1)_0"] = catalyst_measure(9)
# End of circuit: measure q1 syndromes - cycle 0
# End of circuit: measure q1 syndromes 1 time(s)
# End of circuit: inject t into block q1 and measure syndromes
# Start of circuit: measure q1 syndromes 1 time(s)
# Start of circuit: measure q1 syndromes - cycle 0
catalyst_measure(6, reset=True)
catalyst_measure(15, reset=True)
catalyst_measure(8, reset=True)
catalyst_measure(13, reset=True)
catalyst_measure(2, reset=True)
catalyst_measure(16, reset=True)
catalyst_measure(11, reset=True)
catalyst_measure(9, reset=True)
qml.Hadamard([6])
qml.Hadamard([15])
qml.Hadamard([8])
qml.Hadamard([13])
qml.Hadamard([2])
qml.Hadamard([16])
qml.Hadamard([11])
qml.Hadamard([9])
qml.CZ([6, 4])
qml.CZ([15, 12])
qml.CNOT([8, 5])
qml.CNOT([13, 10])
qml.CNOT([2, 0])
qml.CZ([9, 7])
qml.CZ([6, 0])
qml.CZ([15, 5])
qml.CNOT([8, 7])
qml.CNOT([13, 12])
qml.CNOT([2, 1])
qml.CZ([9, 3])
qml.CZ([6, 5])
qml.CZ([15, 14])
qml.CNOT([8, 1])
qml.CNOT([13, 4])
qml.CNOT([16, 12])
qml.CZ([11, 10])
qml.CZ([6, 1])
qml.CZ([15, 7])
qml.CNOT([8, 3])
qml.CNOT([13, 5])
qml.CNOT([16, 14])
qml.CZ([11, 4])
qml.Hadamard([6])
qml.Hadamard([15])
qml.Hadamard([8])
qml.Hadamard([13])
qml.Hadamard([2])
qml.Hadamard([16])
qml.Hadamard([11])
qml.Hadamard([9])
measurements["c_(1, 1, 1)_1"] = catalyst_measure(6)
measurements["c_(2, 2, 1)_1"] = catalyst_measure(15)
measurements["c_(1, 2, 1)_1"] = catalyst_measure(8)
measurements["c_(2, 1, 1)_1"] = catalyst_measure(13)
measurements["c_(0, 1, 1)_1"] = catalyst_measure(2)
measurements["c_(3, 2, 1)_1"] = catalyst_measure(16)
measurements["c_(2, 0, 1)_1"] = catalyst_measure(11)
measurements["c_(1, 3, 1)_1"] = catalyst_measure(9)
# End of circuit: measure q1 syndromes - cycle 0
# End of circuit: measure q1 syndromes 1 time(s)
# Start of circuit: measure logical x of q1
qml.Hadamard([0])
qml.Hadamard([1])
qml.Hadamard([3])
qml.Hadamard([4])
qml.Hadamard([5])
qml.Hadamard([7])
qml.Hadamard([10])
qml.Hadamard([12])
qml.Hadamard([14])
measurements["c_(0, 0, 0)_0"] = catalyst_measure(0)
measurements["c_(0, 1, 0)_0"] = catalyst_measure(1)
measurements["c_(0, 2, 0)_0"] = catalyst_measure(3)
measurements["c_(1, 0, 0)_0"] = catalyst_measure(4)
measurements["c_(1, 1, 0)_0"] = catalyst_measure(5)
measurements["c_(1, 2, 0)_0"] = catalyst_measure(7)
measurements["c_(2, 0, 0)_0"] = catalyst_measure(10)
measurements["c_(2, 1, 0)_0"] = catalyst_measure(12)
measurements["c_(2, 2, 0)_0"] = catalyst_measure(14)
# End of circuit: measure logical x of q1
# End of circuit: final circuit
return measurements
else:
pl_main = None
if not dry_run:
with with_alarm(timeout or float("inf")):
pl_main.compile()
times = []
measurements = []
print("Running", end="")
for _ in range(nattempts):
begin = time.time()
shot_results = []
if not dry_run:
with with_alarm(timeout or float("inf")):
raw = pl_main()
per_key_lists = {
k: v.astype(int).tolist() for k, v in raw.items()
}
nshots = (
len(next(iter(per_key_lists.values())))
if per_key_lists else 0
)
for i in range(nshots):
shot_results.append({
k: vals[i] for k, vals in per_key_lists.items()
})
end = time.time()
times.append(end - begin)
measurements.append(shot_results)
with open("running_times.json", "w") as f:
json.dump(times, f)
with open("measurements.json", "w") as f:
json.dump(measurements, f)
print(f", t={times[-1]}", end="", flush=True)
print(" (dry-run)" if dry_run else "")
if not dry_run:
dump_logical_observables(measurements)