From d794c044ab09b32778bc7632d904a9223db29639 Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Wed, 1 Nov 2023 17:43:36 +0400 Subject: [PATCH 01/10] bugfix for qibojit and qibolab --- src/qibo/backends/numpy.py | 2 +- src/qibo/result.py | 9 --------- tests/test_result.py | 20 -------------------- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index b064abd780..cf24b845ff 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -524,7 +524,7 @@ def execute_circuit_repeated(self, circuit, nshots, initial_state=None): if circuit.density_matrix: # this implies also it has_collapse assert circuit.has_collapse - final_state = np.asarray(final_states).mean(0) + final_state = self.to_numpy(final_states).mean(0) if circuit.measurements: qubits = [q for m in circuit.measurements for q in m.target_qubits] final_result = CircuitResult( diff --git a/src/qibo/result.py b/src/qibo/result.py index ac90822a3b..db922043ad 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -147,15 +147,6 @@ class MeasurementOutcomes: def __init__( self, measurements, backend, probabilities=None, samples=None, nshots=1000 ): - if probabilities is None and samples is None: - raise RuntimeError( - "You have to provide either the `probabilities` or the `samples` to build a `MeasurementOutcomes` object." - ) - if probabilities is not None and samples is not None: - raise RuntimeError( - "Both the `probabilities` and the `samples` were provided to build the `MeasurementOutcomes` object. Don't know which one to use." - ) - self.backend = backend self.measurements = measurements self.nshots = nshots diff --git a/tests/test_result.py b/tests/test_result.py index c802dda406..20f878195c 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -16,26 +16,6 @@ def test_circuit_result_error(backend): ) -def test_measurementoutcomes_errors(backend): - c = models.Circuit(1) - c.add(gates.M(0)) - samples = [np.array([1, 0]) for _ in range(5)] - with pytest.raises(Exception) as exc_info: - MeasurementOutcomes(c.measurements, backend) - assert ( - str(exc_info.value) - == "You have to provide either the `probabilities` or the `samples` to build a `MeasurementOutcomes` object." - ) - with pytest.raises(Exception) as exc_info: - MeasurementOutcomes( - c.measurements, backend, probabilities=np.array([1, 0]), samples=samples - ) - assert ( - str(exc_info.value) - == "Both the `probabilities` and the `samples` were provided to build the `MeasurementOutcomes` object. Don't know which one to use." - ) - - def test_measurement_gate_dump_load(backend): c = models.Circuit(2) c.add(gates.M(1, 0, basis=[gates.Z, gates.X])) From 80327a32f63ab2750f58f1fd0ee44acab2e85c9d Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Thu, 2 Nov 2023 10:20:09 +0400 Subject: [PATCH 02/10] fix to repeated_execution --- src/qibo/backends/numpy.py | 2 +- tests/test_callbacks.py | 1 + tests/test_models_circuit_execution.py | 36 ++++++++++++++++---------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index cf24b845ff..9623fde873 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -524,7 +524,7 @@ def execute_circuit_repeated(self, circuit, nshots, initial_state=None): if circuit.density_matrix: # this implies also it has_collapse assert circuit.has_collapse - final_state = self.to_numpy(final_states).mean(0) + final_state = self.np.mean(self.to_numpy(final_states), 0) if circuit.measurements: qubits = [q for m in circuit.measurements for q in m.target_qubits] final_result = CircuitResult( diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 6a0a70c75a..205099064d 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -94,6 +94,7 @@ def test_entropy_in_circuit(backend, density_matrix, base): target = [0, 0, np.log(2)] / np.log(base) values = [backend.to_numpy(x) for x in entropy] + print(target, values) backend.assert_allclose(values, target, atol=PRECISION_TOL) target_spectrum = [1.0] + list([0, 0, np.log(2), np.log(2)] / np.log(base)) diff --git a/tests/test_models_circuit_execution.py b/tests/test_models_circuit_execution.py index 0d908dfc86..bf493bc893 100644 --- a/tests/test_models_circuit_execution.py +++ b/tests/test_models_circuit_execution.py @@ -27,13 +27,13 @@ def create_circuit(theta=0.1234): # Run eager circuit c1 = create_circuit() - r1 = backend.execute_circuit(c1)._state + r1 = backend.execute_circuit(c1).state() # Run compiled circuit c2 = create_circuit() c2.compile(backend) - r2 = c2()._state - np.testing.assert_allclose(r1, r2) + r2 = c2().state() + np.testing.assert_allclose(backend.to_numpy(r1), backend.to_numpy(r2)) def test_compiling_twice_exception(backend): @@ -59,14 +59,22 @@ def test_memory_error(backend, accelerators): def test_repeated_execute(backend, accelerators): - c = Circuit(4, accelerators, density_matrix=True) - thetas = np.random.random(4) - c.add((gates.RY(i, t) for i, t in enumerate(thetas))) - target_state = backend.execute_circuit(c).state() - target_state = target_state - c.has_collapse = True - final_state = backend.execute_circuit(c, nshots=20)._state - backend.assert_allclose(final_state, target_state) + if accelerators is not None: + with pytest.raises(NotImplementedError): + c = Circuit(4, accelerators, density_matrix=True) + else: + c = Circuit(4, accelerators, density_matrix=True) + thetas = np.random.random(4) + c.add((gates.RY(i, t) for i, t in enumerate(thetas))) + target_state = backend.execute_circuit(c).state() + target_state = target_state + c.has_collapse = True + if accelerators is not None: + with pytest.raises(NotImplementedError): + final_state = backend.execute_circuit(c, nshots=20) + else: + final_state = backend.execute_circuit(c, nshots=20).state() + backend.assert_allclose(final_state, target_state) def test_final_state_property(backend): @@ -92,7 +100,7 @@ def test_density_matrix_circuit(backend): c.add(gates.H(1)) c.add(gates.CNOT(0, 1)) c.add(gates.H(2)) - final_rho = backend.execute_circuit(c, np.copy(initial_rho))._state + final_rho = backend.execute_circuit(c, np.copy(initial_rho)).state() h = np.array([[1, 1], [1, -1]]) / np.sqrt(2) cnot = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) @@ -122,8 +130,8 @@ def test_circuit_as_initial_state(backend, density_matrix): actual_circuit = c1 + c - output = backend.execute_circuit(c, c1)._state - target = backend.execute_circuit(actual_circuit)._state + output = backend.execute_circuit(c, c1).state() + target = backend.execute_circuit(actual_circuit).state() backend.assert_allclose(target, output) From 997167f4267f1f9c2eda1618e2f5585d21c45ac0 Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Thu, 2 Nov 2023 11:58:33 +0400 Subject: [PATCH 03/10] fix to measurementoutcomes.has_samples() --- src/qibo/result.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/qibo/result.py b/src/qibo/result.py index db922043ad..59e8d8cc44 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -229,10 +229,7 @@ def frequencies(self, binary=True, registers=False): return self._frequencies def has_samples(self): - if self._samples is not None: - return True - else: # pragma: no cover - return False + return self.measurements[0].result.has_samples() def samples(self, binary=True, registers=False): """Returns raw measurement samples. From fb93fd28b16f1858acf04ee5883881859264cb4f Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Thu, 2 Nov 2023 12:43:41 +0400 Subject: [PATCH 04/10] moved measurement reset inside repeated execution --- src/qibo/backends/numpy.py | 2 ++ src/qibo/result.py | 5 +---- tests/test_result.py | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index 9623fde873..7a949ff79b 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -521,6 +521,8 @@ def execute_circuit_repeated(self, circuit, nshots, initial_state=None): results.append(sample) if not circuit.density_matrix: samples.append("".join([str(s) for s in sample])) + for gate in circuit.measurements: + gate.result.reset() if circuit.density_matrix: # this implies also it has_collapse assert circuit.has_collapse diff --git a/src/qibo/result.py b/src/qibo/result.py index 59e8d8cc44..1b93cd2331 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -157,9 +157,6 @@ def __init__( self._frequencies = None self._repeated_execution_frequencies = None - for gate in self.measurements: - gate.result.reset() - def frequencies(self, binary=True, registers=False): """Returns the frequencies of measured samples. @@ -229,7 +226,7 @@ def frequencies(self, binary=True, registers=False): return self._frequencies def has_samples(self): - return self.measurements[0].result.has_samples() + return self.measurements[0].result.has_samples() or self._samples is not None def samples(self, binary=True, registers=False): """Returns raw measurement samples. diff --git a/tests/test_result.py b/tests/test_result.py index 20f878195c..cd62abdac6 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -56,6 +56,7 @@ def test_circuitresult_dump_load(backend, agnostic_load): # from samples and recover the same exact frequencies c.has_collapse = True result = backend.execute_circuit(c) + print(result.has_samples()) freq = result.frequencies() # set probabilities to trigger the warning result._probs = result.probabilities() From d9f7b46065b56195ecd0d1c4630af7afcaf01df8 Mon Sep 17 00:00:00 2001 From: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:45:01 +0400 Subject: [PATCH 05/10] Update tests/test_callbacks.py Co-authored-by: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> --- tests/test_callbacks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 205099064d..6a0a70c75a 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -94,7 +94,6 @@ def test_entropy_in_circuit(backend, density_matrix, base): target = [0, 0, np.log(2)] / np.log(base) values = [backend.to_numpy(x) for x in entropy] - print(target, values) backend.assert_allclose(values, target, atol=PRECISION_TOL) target_spectrum = [1.0] + list([0, 0, np.log(2), np.log(2)] / np.log(base)) From c2d9bc67eb6e451bb80e261ed019f3592dc020a8 Mon Sep 17 00:00:00 2001 From: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:56:00 +0400 Subject: [PATCH 06/10] Update src/qibo/backends/numpy.py Co-authored-by: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> --- src/qibo/backends/numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index 7a949ff79b..dc95a53fd5 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -526,7 +526,7 @@ def execute_circuit_repeated(self, circuit, nshots, initial_state=None): if circuit.density_matrix: # this implies also it has_collapse assert circuit.has_collapse - final_state = self.np.mean(self.to_numpy(final_states), 0) + final_state = np.mean(self.to_numpy(final_states), 0) if circuit.measurements: qubits = [q for m in circuit.measurements for q in m.target_qubits] final_result = CircuitResult( From ac3e56e985e8da7f9d1130cfd475506af62d9d4a Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:22:44 +0400 Subject: [PATCH 07/10] Fix numpy casting --- src/qibo/result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/result.py b/src/qibo/result.py index 1b93cd2331..2ae7fb498e 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -67,7 +67,7 @@ def state(self, numpy=False): The state in the computational basis. """ if numpy: - return np.asarray(self._state) + return self.backend.to_numpy(self._state) else: return self._state From 7c2df6a43a1657a716baf75dae98a4b7219615bc Mon Sep 17 00:00:00 2001 From: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:53:40 +0400 Subject: [PATCH 08/10] Update tests/test_result.py Co-authored-by: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> --- tests/test_result.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_result.py b/tests/test_result.py index cd62abdac6..20f878195c 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -56,7 +56,6 @@ def test_circuitresult_dump_load(backend, agnostic_load): # from samples and recover the same exact frequencies c.has_collapse = True result = backend.execute_circuit(c) - print(result.has_samples()) freq = result.frequencies() # set probabilities to trigger the warning result._probs = result.probabilities() From 25ea14d55a35ae2ba497da8391f621c1131e298d Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Thu, 2 Nov 2023 16:00:25 +0400 Subject: [PATCH 09/10] fix test --- tests/test_models_circuit_features.py | 7 ++++--- tests/test_result.py | 6 ++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/test_models_circuit_features.py b/tests/test_models_circuit_features.py index 44044e9364..9bf36933aa 100644 --- a/tests/test_models_circuit_features.py +++ b/tests/test_models_circuit_features.py @@ -312,13 +312,14 @@ def test_repeated_execute_probs_and_freqs(backend, nqubits): # Tensorflow seems to yield different results with same seed if backend.__class__.__name__ == "TensorflowBackend": if nqubits == 1: - test_frequencies = Counter({"1": 844, "0": 180}) + test_frequencies = Counter({"1": 801, "0": 223}) else: - test_frequencies = Counter({"11": 674, "10": 155, "01": 154, "00": 41}) + test_frequencies = Counter({"11": 662, "10": 163, "01": 160, "00": 39}) else: if nqubits == 1: test_frequencies = Counter({"1": 790, "0": 234}) else: test_frequencies = Counter({"11": 618, "10": 169, "01": 185, "00": 52}) - assert result.frequencies() == test_frequencies + for key in dict(test_frequencies).keys(): + backend.assert_allclose(result.frequencies()[key], test_frequencies[key]) diff --git a/tests/test_result.py b/tests/test_result.py index 20f878195c..0eaa9b7022 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -1,3 +1,5 @@ +from os import remove + import numpy as np import pytest @@ -27,8 +29,6 @@ def test_measurement_gate_dump_load(backend): @pytest.mark.parametrize("agnostic_load", [False, True]) def test_measurementoutcomes_dump_load(backend, agnostic_load): - from os import remove - c = models.Circuit(2) c.add(gates.M(1, 0, basis=[gates.Z, gates.X])) # just to trigger repeated execution and test MeasurementOutcomes @@ -48,8 +48,6 @@ def test_measurementoutcomes_dump_load(backend, agnostic_load): @pytest.mark.parametrize("agnostic_load", [False, True]) def test_circuitresult_dump_load(backend, agnostic_load): - from os import remove - c = models.Circuit(2, density_matrix=True) c.add(gates.M(1, 0, basis=[gates.Z, gates.X])) # trigger repeated execution to build the CircuitResult object From bc1baa376392747e863fc40ffd1fd984293990f2 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Thu, 2 Nov 2023 16:42:43 +0400 Subject: [PATCH 10/10] undo changes --- tests/test_models_circuit_features.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_models_circuit_features.py b/tests/test_models_circuit_features.py index 9bf36933aa..99b45b74c7 100644 --- a/tests/test_models_circuit_features.py +++ b/tests/test_models_circuit_features.py @@ -312,9 +312,9 @@ def test_repeated_execute_probs_and_freqs(backend, nqubits): # Tensorflow seems to yield different results with same seed if backend.__class__.__name__ == "TensorflowBackend": if nqubits == 1: - test_frequencies = Counter({"1": 801, "0": 223}) + test_frequencies = Counter({"1": 844, "0": 180}) else: - test_frequencies = Counter({"11": 662, "10": 163, "01": 160, "00": 39}) + test_frequencies = Counter({"11": 674, "10": 155, "01": 154, "00": 41}) else: if nqubits == 1: test_frequencies = Counter({"1": 790, "0": 234})