# Source code for mitiq.ddd.ddd

```
# Copyright (C) 2022 Unitary Fund
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""High-level digital dynamical decoupling (DDD) tools."""
from typing import (
Optional,
Callable,
Union,
Tuple,
Dict,
Any,
List,
)
from functools import wraps, partial
import numpy as np
from mitiq import Executor, Observable, QPROGRAM, QuantumResult
from mitiq.ddd.insertion import insert_ddd_sequences
[docs]def execute_with_ddd(
circuit: QPROGRAM,
executor: Union[Executor, Callable[[QPROGRAM], QuantumResult]],
observable: Optional[Observable] = None,
*,
rule: Callable[[int], QPROGRAM],
rule_args: Dict[str, Any] = {},
num_trials: int = 1,
full_output: bool = False,
) -> Union[float, Tuple[float, Dict[str, Any]]]:
r"""Estimates the error-mitigated expectation value associated to the
input circuit, via the application of digital dynamical decoupling (DDD).
Args:
circuit: The input circuit to execute with DDD.
executor: A Mitiq executor that executes a circuit and returns the
unmitigated ``QuantumResult`` (e.g. an expectation value).
observable: Observable to compute the expectation value of. If None,
the ``executor`` must return an expectation value. Otherwise,
the ``QuantumResult`` returned by ``executor`` is used to compute
the expectation of the observable.
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. Mitiq provides standard built-in rules
that can be directly imported from ``mitiq.ddd.rules``.
rule_args: An optional dictionary of keyword arguments for ``rule``.
num_trials: The number of independent experiments to average over.
A number larger than 1 can be useful to average over multiple
applications of a rule returning non-deterministic DDD sequences.
full_output: If ``False`` only the mitigated expectation value is
returned. If ``True`` a dictionary containing all DDD data is
returned too.
Returns:
The tuple ``(ddd_value, ddd_data)`` where ``ddd_value`` is the
expectation value estimated with DDD and ``ddd_data`` is a dictionary
containing all the raw data involved in the DDD process (e.g. the
circuit filled with DDD sequences). If ``full_output`` is false,
only ``ddd_value`` is returned.
"""
# Initialize executor
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)
]
results = executor.evaluate(
circuits_with_ddd,
observable,
force_run_all=True,
)
assert len(results) == num_trials
ddd_value = np.real_if_close(np.sum(results)) / num_trials
if not full_output:
return ddd_value
ddd_data = {
"ddd_value": ddd_value,
"ddd_trials": results,
"circuits_with_ddd": circuits_with_ddd,
}
return ddd_value, ddd_data
[docs]def mitigate_executor(
executor: Callable[[QPROGRAM], QuantumResult],
observable: Optional[Observable] = None,
*,
rule: Callable[[int], QPROGRAM],
rule_args: Dict[str, Any] = {},
num_trials: int = 1,
full_output: bool = False,
) -> Callable[[QPROGRAM], Union[float, Tuple[float, Dict[str, Any]]]]:
"""Returns a modified version of the input 'executor' which is
error-mitigated with digital dynamical decoupling (DDD).
Args:
executor: A function that executes a circuit and returns the
unmitigated `QuantumResult` (e.g. an expectation value).
observable: Observable to compute the expectation value of. If None,
the `executor` must return an expectation value. Otherwise,
the `QuantumResult` returned by `executor` is used to compute the
expectation of the observable.
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. Mitiq provides standard built-in rules
that can be directly imported from `mitiq.ddd.rules`.
rule_args: An optional dictionary of keyword arguments for `rule`.
num_trials: The number of independent experiments to average over.
A number larger than 1 can be useful to average over multiple
applications of a rule returning non-deterministic DDD sequences.
full_output: If False only the mitigated expectation value is returned.
If True a dictionary containing all DDD data is returned too.
Returns:
The error-mitigated version of the input executor.
"""
executor_obj = Executor(executor)
if not executor_obj.can_batch:
@wraps(executor)
def new_executor(
circuit: QPROGRAM,
) -> Union[float, Tuple[float, Dict[str, Any]]]:
return execute_with_ddd(
circuit,
executor,
observable,
rule=rule,
rule_args=rule_args,
num_trials=num_trials,
full_output=full_output,
)
else:
@wraps(executor)
def new_executor(
circuits: List[QPROGRAM],
) -> List[Union[float, Tuple[float, Dict[str, Any]]]]:
return [
execute_with_ddd(
circuit,
executor,
observable,
rule=rule,
rule_args=rule_args,
num_trials=num_trials,
full_output=full_output,
)
for circuit in circuits
]
return new_executor
[docs]def ddd_decorator(
observable: Optional[Observable] = None,
*,
rule: Callable[[int], QPROGRAM],
rule_args: Dict[str, Any] = {},
num_trials: int = 1,
full_output: bool = False,
) -> Callable[
[Callable[[QPROGRAM], QuantumResult]],
Callable[[QPROGRAM], Union[float, Tuple[float, Dict[str, Any]]]],
]:
"""Decorator which adds an error-mitigation layer based on digital
dynamical decoupling (DDD) to an executor function, i.e., a function which
executes a quantum circuit with an arbitrary backend and returns a
``QuantumResult`` (e.g. an expectation value).
Args:
observable: Observable to compute the expectation value of. If None,
the `executor` must return an expectation value. Otherwise,
the `QuantumResult` returned by `executor` is used to compute the
expectation of the observable.
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. Mitiq provides standard built-in rules
that can be directly imported from `mitiq.ddd.rules`.
rule_args: An optional dictionary of keyword arguments for `rule`.
num_trials: The number of independent experiments to average over.
A number larger than 1 can be useful to average over multiple
applications of a rule returning non-deterministic DDD sequences.
full_output: If False only the mitigated expectation value is returned.
If True a dictionary containing all DDD data is returned too.
Returns:
The error-mitigating decorator to be applied to an executor function.
"""
def decorator(
executor: Callable[[QPROGRAM], QuantumResult]
) -> Callable[[QPROGRAM], Union[float, Tuple[float, Dict[str, Any]]]]:
return mitigate_executor(
executor,
observable,
rule=rule,
rule_args=rule_args,
num_trials=num_trials,
full_output=full_output,
)
return decorator
```