diff --git a/qermit/frame_randomisation/frame_randomisation.py b/qermit/frame_randomisation/frame_randomisation.py index 1c2155ed..3184dff2 100644 --- a/qermit/frame_randomisation/frame_randomisation.py +++ b/qermit/frame_randomisation/frame_randomisation.py @@ -33,10 +33,17 @@ from enum import Enum from pytket import OpType from pytket.passes import auto_rebase_pass +from .h_series_randomisation import gen_h_series_randomised_circuit class FrameRandomisation(Enum): + @staticmethod + def HSeriesRandomisation( + circuit: Circuit, shots: int, + ) -> List[CircuitShots]: + return [CircuitShots(Circuit=gen_h_series_randomised_circuit(circuit), Shots=shots)] + @staticmethod def PauliFrameRandomisation( circuit: Circuit, shots: int, samples: int diff --git a/qermit/frame_randomisation/h_series_randomisation.py b/qermit/frame_randomisation/h_series_randomisation.py index 9223d021..172ad089 100644 --- a/qermit/frame_randomisation/h_series_randomisation.py +++ b/qermit/frame_randomisation/h_series_randomisation.py @@ -11,13 +11,17 @@ def get_wfh(): return wasm.WasmFileHandler(wasm_file) -def gen_randomised_circuit(circuit): +def gen_h_series_randomised_circuit(circuit): wfh = get_wfh() randomised_circuit = Circuit() + randomisation_reg_dict = {} for q_register in circuit.q_registers: randomised_circuit.add_q_register(q_register) + for qubit in q_register: + randomisation_reg = randomised_circuit.add_c_register(f"randomisation_{qubit.to_list()}", 4) + randomisation_reg_dict[qubit] = randomisation_reg for c_register in circuit.c_registers: randomised_circuit.add_c_register(c_register) @@ -39,16 +43,10 @@ def gen_randomised_circuit(circuit): randomised_circuit.Reset(qubit) randomised_circuit.add_wasm_to_reg("seed_randomisation", wfh, [seed_c_reg], []) - randomisation_reg = randomised_circuit.add_c_register("randomisation", 4) - - # rand_vals = [10, 7] - # command_count = 0 - for command in circuit: if command.op.type == OpType.ZZMax: - randomised_circuit.add_wasm_to_reg("write_randomisation", wfh, [], [randomisation_reg]) - # randomised_circuit.add_c_setreg(rand_vals[command_count], randomisation_reg) + randomised_circuit.add_wasm_to_reg("write_randomisation", wfh, [], [randomisation_reg_dict[command.args[0]]]) randomised_circuit.Z(command.qubits[0], condition=randomisation_reg[0]) randomised_circuit.Z(command.qubits[1], condition=randomisation_reg[1]) randomised_circuit.X(command.qubits[0], condition=randomisation_reg[2]) @@ -67,26 +65,9 @@ def gen_randomised_circuit(circuit): ) randomised_circuit.X(command.qubits[0], condition=randomisation_reg[2]) randomised_circuit.X(command.qubits[1], condition=randomisation_reg[3]) - - # randomised_circuit.Z(command.qubits[0], condition=randomisation_reg[4]) - # randomised_circuit.Z(command.qubits[1], condition=randomisation_reg[5]) - # randomised_circuit.X(command.qubits[0], condition=randomisation_reg[6]) - # randomised_circuit.X(command.qubits[1], condition=randomisation_reg[7]) - - # randomised_circuit.Z(command.qubits[0], condition=randomisation_reg[0]) - # randomised_circuit.Z(command.qubits[0], condition=randomisation_reg[2]) - # randomised_circuit.Z(command.qubits[0], condition=randomisation_reg[3]) - # randomised_circuit.X(command.qubits[0], condition=randomisation_reg[2]) - - # randomised_circuit.Z(command.qubits[1], condition=randomisation_reg[1]) - # randomised_circuit.Z(command.qubits[1], condition=randomisation_reg[2]) - # randomised_circuit.Z(command.qubits[1], condition=randomisation_reg[3]) - # randomised_circuit.X(command.qubits[1], condition=randomisation_reg[3]) randomised_circuit.Phase(0.5, condition=randomisation_reg[2]) randomised_circuit.Phase(0.5, condition=randomisation_reg[3]) randomised_circuit.Phase(-1, condition=randomisation_reg[2] & randomisation_reg[3]) - - # command_count += 1 - return randomised_circuit, wfh + return randomised_circuit diff --git a/tests/frame_randomisation_test.py b/tests/frame_randomisation_test.py index 5dd057b2..f847e39d 100644 --- a/tests/frame_randomisation_test.py +++ b/tests/frame_randomisation_test.py @@ -23,19 +23,25 @@ from pytket import Circuit from pytket.extensions.qiskit import AerBackend # type: ignore from pytket.extensions.quantinuum import QuantinuumBackend, QuantinuumAPIOffline -from qermit.frame_randomisation.h_series_randomisation import gen_randomised_circuit +from qermit.frame_randomisation.h_series_randomisation import gen_h_series_randomised_circuit, get_wfh + from pytket.unit_id import BitRegister from collections import Counter def test_h_series_randomisation(): + # These tests check that the ideal behaviour of the circuits + # is not altered by adding randomisation. api_offline = QuantinuumAPIOffline() backend = QuantinuumBackend( device_name="H1-1LE", api_handler = api_offline, ) + wasm_file_handler=get_wfh() + # Small circuit with just one ZZMax. + # The ideal output is 00. circuit = Circuit(3) meas_reg = BitRegister(name='measure', size=2) circuit.add_c_register(meas_reg) @@ -50,19 +56,100 @@ def test_h_series_randomisation(): bit=meas_reg[1] ) - randomised_circuit, wfh = gen_randomised_circuit(circuit) - + randomised_circuit = gen_h_series_randomised_circuit(circuit) compiled_circuit = backend.get_compiled_circuit(randomised_circuit, optimisation_level=0) n_shots = 100 result = backend.run_circuit( compiled_circuit, n_shots=n_shots, - wasm_file_handler=wfh, + wasm_file_handler=wasm_file_handler, no_opt=True ) assert result.get_counts(cbits=meas_reg) == Counter({(0,0,): n_shots}) + # To consecutive ZZMax gates. + # Has the effect of acting Z_0 Z_1. + # Checked by applying hadamard rotations. + # I deal outcome in rotate basis is 11. + circuit = Circuit(3) + meas_reg = BitRegister(name='measure', size=2) + circuit.add_c_register(meas_reg) + + circuit.H(0) + circuit.H(1) + + circuit.ZZMax(0,1) + circuit.ZZMax(0,1) + + circuit.H(0) + circuit.H(1) + + circuit.Measure( + qubit=circuit.qubits[0], + bit=meas_reg[0] + ) + circuit.Measure( + qubit=circuit.qubits[1], + bit=meas_reg[1] + ) + + randomised_circuit = gen_h_series_randomised_circuit(circuit) + compiled_circuit = backend.get_compiled_circuit(randomised_circuit, optimisation_level=0) + + n_shots = 100 + result = backend.run_circuit( + compiled_circuit, + n_shots=n_shots, + wasm_file_handler=wasm_file_handler, + no_opt=True + ) + assert result.get_counts(cbits=meas_reg) == Counter({(1,1,): n_shots}) + + # Slightly larger circuit. + # Ideal outcome in rotated basis is 101. + circuit = Circuit(3) + meas_reg = BitRegister(name='measure', size=3) + circuit.add_c_register(meas_reg) + + circuit.H(0) + circuit.H(1) + circuit.H(2) + + circuit.ZZMax(0,1) + circuit.ZZMax(1,2) + circuit.ZZMax(0,1) + circuit.ZZMax(1,2) + + circuit.H(0) + circuit.H(1) + circuit.H(2) + + circuit.Measure( + qubit=circuit.qubits[0], + bit=meas_reg[0] + ) + circuit.Measure( + qubit=circuit.qubits[1], + bit=meas_reg[1] + ) + circuit.Measure( + qubit=circuit.qubits[2], + bit=meas_reg[2] + ) + + randomised_circuit = gen_h_series_randomised_circuit(circuit) + compiled_circuit = backend.get_compiled_circuit(randomised_circuit, optimisation_level=0) + + n_shots = 100 + result = backend.run_circuit( + compiled_circuit, + n_shots=n_shots, + wasm_file_handler=wasm_file_handler, + no_opt=True + ) + assert result.get_counts(cbits=meas_reg) == Counter({(1,0,1,): n_shots}) + def test_frame_randomisation_circuits_task_gen(): c = Circuit(2).CX(0, 1).Rx(0.289, 1).CX(0, 1).measure_all() ufr_task = frame_randomisation_circuits_task_gen(