From 28b6291c5bbe312a44d61ffa2c6cf5b30bf64649 Mon Sep 17 00:00:00 2001 From: bdg221 Date: Tue, 17 Dec 2024 12:27:59 -0800 Subject: [PATCH 1/5] separated generate circuits and ddd value into separate functions --- mitiq/ddd/ddd.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/mitiq/ddd/ddd.py b/mitiq/ddd/ddd.py index 07c68f2c28..a868e737a3 100644 --- a/mitiq/ddd/ddd.py +++ b/mitiq/ddd/ddd.py @@ -59,13 +59,11 @@ def execute_with_ddd( if not isinstance(executor, Executor): executor = Executor(executor) - rule_partial: Callable[[int], QPROGRAM] - rule_partial = partial(rule, **rule_args) - # Insert DDD sequences in (a copy of) the input circuit - circuits_with_ddd = [ - insert_ddd_sequences(circuit, rule_partial) for _ in range(num_trials) - ] + circuits_with_ddd = generate_circuits_with_ddd( + circuit, rule, rule_args, num_trials + ) + results = executor.evaluate( circuits_with_ddd, observable, @@ -74,7 +72,11 @@ def execute_with_ddd( assert len(results) == num_trials - ddd_value = np.sum(results) / num_trials + ddd_value = generate_ddd_value(results, num_trials) + + # Brian test TODO check and remove + # check that np.average(results) == np.sum(results) / num_trials + if not full_output: return ddd_value @@ -86,6 +88,29 @@ def execute_with_ddd( return ddd_value, ddd_data +# TODO rename and docstring +def generate_ddd_value(results: list[float]) -> float: + return np.average(results) + + +# TODO rename and docstring +def generate_circuits_with_ddd( + circuit: QPROGRAM, + rule: Callable[[int], QPROGRAM], + rule_args: Dict[str, Any] = {}, + num_trials: int = 1, +) -> list[QPROGRAM]: + rule_partial: Callable[[int], QPROGRAM] + rule_partial = partial(rule, **rule_args) + + # Insert DDD sequences in (a copy of) the input circuit + circuits_with_ddd = [ + insert_ddd_sequences(circuit, rule_partial) for _ in range(num_trials) + ] + + return circuits_with_ddd + + def mitigate_executor( executor: Callable[[QPROGRAM], QuantumResult], observable: Optional[Observable] = None, From 73018015207293035e4d95f229bb4a59ece431c3 Mon Sep 17 00:00:00 2001 From: bdg221 Date: Fri, 20 Dec 2024 07:38:26 -0800 Subject: [PATCH 2/5] Add docstrings and test --- mitiq/ddd/__init__.py | 2 +- mitiq/ddd/ddd.py | 30 ++++++++++++++++++++++++------ mitiq/ddd/tests/test_ddd.py | 18 +++++++++++++++++- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/mitiq/ddd/__init__.py b/mitiq/ddd/__init__.py index fb2258640d..4a639b28a6 100644 --- a/mitiq/ddd/__init__.py +++ b/mitiq/ddd/__init__.py @@ -14,4 +14,4 @@ insert_ddd_sequences, ) -from mitiq.ddd.ddd import execute_with_ddd, mitigate_executor, ddd_decorator +from mitiq.ddd.ddd import execute_with_ddd, mitigate_executor, ddd_decorator, generate_circuits_with_ddd, generate_ddd_value diff --git a/mitiq/ddd/ddd.py b/mitiq/ddd/ddd.py index a868e737a3..edc9317222 100644 --- a/mitiq/ddd/ddd.py +++ b/mitiq/ddd/ddd.py @@ -72,10 +72,7 @@ def execute_with_ddd( assert len(results) == num_trials - ddd_value = generate_ddd_value(results, num_trials) - - # Brian test TODO check and remove - # check that np.average(results) == np.sum(results) / num_trials + ddd_value = generate_ddd_value(results) if not full_output: return ddd_value @@ -88,18 +85,39 @@ def execute_with_ddd( return ddd_value, ddd_data -# TODO rename and docstring def generate_ddd_value(results: list[float]) -> float: + """Averages over the DDD results to get the expectation value from using + DDD. + + Args: + results: Results as obtained from running circuits. + + Returns: + The expectation value estimated with DDD. + """ return np.average(results) -# TODO rename and docstring def generate_circuits_with_ddd( circuit: QPROGRAM, rule: Callable[[int], QPROGRAM], rule_args: Dict[str, Any] = {}, num_trials: int = 1, ) -> list[QPROGRAM]: + """Generates a list of circuits with DDD sequences inserted. + + Args: + circuit: The quantum circuit to be modified with DD. + rule: A function that takes as main argument a slack length (i.e. the + number of idle moments) of a slack window (i.e. a single-qubit idle + window in a circuit) and returns the DDD sequence of gates to be + applied in that window. + rule_args: An optional dictionary of keyword arguments for ``rule``. + num_trials: The number of circuits to generate with DDD insertions. + + Returns: + A list of circuits with DDD inserted. + """ rule_partial: Callable[[int], QPROGRAM] rule_partial = partial(rule, **rule_args) diff --git a/mitiq/ddd/tests/test_ddd.py b/mitiq/ddd/tests/test_ddd.py index 13aae0685c..73ca08b64f 100644 --- a/mitiq/ddd/tests/test_ddd.py +++ b/mitiq/ddd/tests/test_ddd.py @@ -12,7 +12,12 @@ from pytest import mark from mitiq import QPROGRAM, SUPPORTED_PROGRAM_TYPES, Executor -from mitiq.ddd import ddd_decorator, execute_with_ddd, mitigate_executor +from mitiq.ddd import ( + ddd_decorator, + execute_with_ddd, + generate_circuits_with_ddd, + mitigate_executor, +) from mitiq.ddd.rules import xx, xyxy, yy from mitiq.interface import convert_from_mitiq, convert_to_mitiq from mitiq.interface.mitiq_cirq import compute_density_matrix @@ -226,3 +231,14 @@ def exec_xx_small_spacing(circuit): # What is important to test is getting different results. assert not np.isclose(unmitigated, mitigated_small_spacing) assert not np.isclose(mitigated_large_spacing, mitigated_small_spacing) + + +@mark.parametrize("num_trials", [1, 3, 5]) +def test_num_trials_generates_circuits(num_trials: int): + """Test that the number of generated circuits follows num_trials.""" + + circuits = generate_circuits_with_ddd( + circuit_cirq_a, rule=xx, num_trials=num_trials + ) + + assert num_trials == len(circuits) From 52f93a9078027e743df67e34e5148265787222fc Mon Sep 17 00:00:00 2001 From: bdg221 Date: Fri, 20 Dec 2024 07:40:50 -0800 Subject: [PATCH 3/5] Cast a float for mypy --- mitiq/ddd/ddd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitiq/ddd/ddd.py b/mitiq/ddd/ddd.py index edc9317222..b5a2e3bdcb 100644 --- a/mitiq/ddd/ddd.py +++ b/mitiq/ddd/ddd.py @@ -95,7 +95,7 @@ def generate_ddd_value(results: list[float]) -> float: Returns: The expectation value estimated with DDD. """ - return np.average(results) + return float(np.average(results)) def generate_circuits_with_ddd( From a23f7b70cdc13d8d28e76e546207accade230df3 Mon Sep 17 00:00:00 2001 From: bdg221 Date: Fri, 20 Dec 2024 09:51:19 -0800 Subject: [PATCH 4/5] Use combine_results to match ZNE and PEC --- mitiq/ddd/__init__.py | 2 +- mitiq/ddd/ddd.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mitiq/ddd/__init__.py b/mitiq/ddd/__init__.py index 4a639b28a6..a6292ab3f3 100644 --- a/mitiq/ddd/__init__.py +++ b/mitiq/ddd/__init__.py @@ -14,4 +14,4 @@ insert_ddd_sequences, ) -from mitiq.ddd.ddd import execute_with_ddd, mitigate_executor, ddd_decorator, generate_circuits_with_ddd, generate_ddd_value +from mitiq.ddd.ddd import execute_with_ddd, mitigate_executor, ddd_decorator, generate_circuits_with_ddd, combine_results diff --git a/mitiq/ddd/ddd.py b/mitiq/ddd/ddd.py index b5a2e3bdcb..7bb9d3de08 100644 --- a/mitiq/ddd/ddd.py +++ b/mitiq/ddd/ddd.py @@ -72,7 +72,7 @@ def execute_with_ddd( assert len(results) == num_trials - ddd_value = generate_ddd_value(results) + ddd_value = combine_results(results) if not full_output: return ddd_value @@ -85,7 +85,7 @@ def execute_with_ddd( return ddd_value, ddd_data -def generate_ddd_value(results: list[float]) -> float: +def combine_results(results: list[float]) -> float: """Averages over the DDD results to get the expectation value from using DDD. From 048c925f6174fc89389b015c7b766085823caeea Mon Sep 17 00:00:00 2001 From: nate stemen Date: Fri, 20 Dec 2024 10:52:29 -0800 Subject: [PATCH 5/5] increase num_trials testing --- mitiq/ddd/tests/test_ddd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitiq/ddd/tests/test_ddd.py b/mitiq/ddd/tests/test_ddd.py index 73ca08b64f..7995ce8e9d 100644 --- a/mitiq/ddd/tests/test_ddd.py +++ b/mitiq/ddd/tests/test_ddd.py @@ -233,7 +233,7 @@ def exec_xx_small_spacing(circuit): assert not np.isclose(mitigated_large_spacing, mitigated_small_spacing) -@mark.parametrize("num_trials", [1, 3, 5]) +@mark.parametrize("num_trials", [1, 10, 20, 30]) def test_num_trials_generates_circuits(num_trials: int): """Test that the number of generated circuits follows num_trials."""