From 2ac99db82f3e55eb3fc325e23d194e138fbf944a Mon Sep 17 00:00:00 2001 From: James Brown Date: Mon, 20 Nov 2023 15:59:28 -0500 Subject: [PATCH] added call to cmeasure_control finalize method --- tangelo/linq/circuit.py | 7 ++++++- tangelo/linq/target/target_cirq.py | 4 ++++ tangelo/linq/target/target_qulacs.py | 4 ++++ tangelo/linq/tests/test_simulator.py | 20 ++++++++++++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tangelo/linq/circuit.py b/tangelo/linq/circuit.py index 82281029e..48471f323 100644 --- a/tangelo/linq/circuit.py +++ b/tangelo/linq/circuit.py @@ -58,7 +58,7 @@ def __init__(self, gates: List[Gate] = None, n_qubits=None, name="no_name", cmea self._n_qubit_gate_counts: Dict[int, int] = dict() self._variational_gates: List[Gate] = [] self._probabilities: Dict[str, float] = dict() - self._cmeasure_control: Callable = cmeasure_control + self._cmeasure_control: Union[Callable, ClassicalControl, None] = cmeasure_control self._applied_gates: List[Gate] = [] if gates: @@ -415,6 +415,11 @@ def controlled_measurement_op(self, measure): elif isinstance(self._cmeasure_control, ClassicalControl): return Circuit(self._cmeasure_control.return_circuit(measure), n_qubits=self.width) + def finalize_cmeasure_control(self): + """Call the finalize method in cmeasure_control""" + if isinstance(self._cmeasure_control, ClassicalControl): + self._cmeasure_control.finalize() + def stack(*circuits): """ Take list of circuits as input, and stack them (e.g concatenate them along the diff --git a/tangelo/linq/target/target_cirq.py b/tangelo/linq/target/target_cirq.py index 94bff9f47..911f8f62b 100644 --- a/tangelo/linq/target/target_cirq.py +++ b/tangelo/linq/target/target_cirq.py @@ -160,6 +160,10 @@ def simulate_circuit(self, source_circuit: Circuit, return_statevector=False, in isamples = self.cirq.sample_state_vector(self._current_state, indices, repetitions=1) bitstr = measurements + "".join([str(int(q)) for q in isamples[0]]) samples[bitstr] = samples.get(bitstr, 0) + 1 + + # Call the finalize method of ClassicalControl, used to reset variables, perform computation etc. + source_circuit.finalize_cmeasure_control() + if self.n_shots: self.all_frequencies = {k: v / self.n_shots for k, v in samples.items()} frequencies = {k[:]: v / self.n_shots for k, v in samples.items()} diff --git a/tangelo/linq/target/target_qulacs.py b/tangelo/linq/target/target_qulacs.py index b3cc9d2fb..b60d80461 100644 --- a/tangelo/linq/target/target_qulacs.py +++ b/tangelo/linq/target/target_qulacs.py @@ -156,6 +156,10 @@ def simulate_circuit(self, source_circuit: Circuit, return_statevector=False, in else: bitstr = self._int_to_binstr(state.sampling(1)[0], source_circuit.width) samples[measurements+bitstr] = samples.get(measurements+bitstr, 0) + 1 + + # Call the finalize method of ClassicalControl, used to reset variables, perform computation etc. + source_circuit.finalize_cmeasure_control() + if self.n_shots: self.all_frequencies = {k: v / self.n_shots for k, v in samples.items()} frequencies = {k: v / self.n_shots for k, v in samples.items()} diff --git a/tangelo/linq/tests/test_simulator.py b/tangelo/linq/tests/test_simulator.py index 059c90ec7..c4eb0d4ba 100644 --- a/tangelo/linq/tests/test_simulator.py +++ b/tangelo/linq/tests/test_simulator.py @@ -711,18 +711,24 @@ def test_measurement_controlled_gates_class(self): for backend in installed_cmeasure_simulators: - sim = get_backend(backend, n_shots=1) + sim = get_backend(backend, n_shots=2) - # Unitary has eigenvalue (1/16+1/8+1/4+1/2)*pi with eigenvector |1> on qubit 1. - ugate = Gate("CPHASE", 1, control=0, parameter=np.pi/16+np.pi/8+np.pi/4+np.pi/2) + # Unitary has eigenvalue (1/16+1/8+1/2)*pi with eigenvector |1> on qubit 1. + # Measurement will be 0011010 = 0/64+0/32+1/16+1/8+0/4+1/2+0 + ugate = Gate("CPHASE", 1, control=0, parameter=np.pi/16+np.pi/8+np.pi/2) class IterativeQPE(ClassicalControl): def __init__(self, bits): self.bits = bits self.bitplace = bits*1 self.phase = 0 + self.measurements = [""] + self.energies = [0.] + self.n_runs = 0 def return_circuit(self, measurement) -> List[Gate]: + self.measurements[self.n_runs] += measurement + self.energies[self.n_runs] += int(measurement)/2**self.bitplace if self.bitplace > 0: self.bitplace -= 1 self.correction = [Gate("PHASE", 0, parameter=-2*np.pi*self.phase*2**(self.bitplace+1))] @@ -739,6 +745,9 @@ def return_circuit(self, measurement) -> List[Gate]: def finalize(self): self.bitplace = self.bits*1 self.phase = 0 + self.n_runs += 1 + self.measurements += [""] + self.energies += [0.] bits = 6 cfunc = IterativeQPE(bits) @@ -747,7 +756,10 @@ def finalize(self): f, _ = sim.simulate(circuit, save_mid_circuit_meas=True) assert_freq_dict_almost_equal(f, {"01": 1}, 1.e-7) - assert_freq_dict_almost_equal(circuit.success_probabilities, {"0011110": 1}, 1.e-7) + assert_freq_dict_almost_equal(circuit.success_probabilities, {"0011010": 1}, 1.e-7) + self.assertEqual(cfunc.measurements, ["0011010", "0011010", ""]) + energy = 1/16+1/8+1/2 + np.testing.assert_array_almost_equal(cfunc.energies, [energy, energy, 0.]) if __name__ == "__main__":