Skip to content

Commit

Permalink
main functions without corrected mypy errors, unit tests and docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
purva-thakre committed Sep 11, 2024
1 parent 1a3705c commit 6614641
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 1 deletion.
5 changes: 5 additions & 0 deletions docs/source/apidoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ See Ref. {cite}`Czarnik_2021_Quantum` for more details on these methods.

### Layerwise Richardson Extrapolation

```{eval-rst}
.. automodule:: mitiq.lre.lre
:members:
```

```{eval-rst}
.. automodule:: mitiq.lre.multivariate_scaling.layerwise_folding
:members:
Expand Down
4 changes: 3 additions & 1 deletion mitiq/lre/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
from mitiq.lre.inference.multivariate_richardson import (
multivariate_richardson_coefficients,
sample_matrix,
)
)

from mitiq.lre.lre import execute_with_lre, mitigate_executor, lre_decorator
112 changes: 112 additions & 0 deletions mitiq/lre/lre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright (C) Unitary Fund
#
# This source code is licensed under the GPL license (v3) found in the
# LICENSE file in the root directory of this source tree.

"""Extrapolation methods for Layerwise Richardson Extrapolation (LRE)"""

from functools import wraps
from typing import Callable, Optional, Union

import numpy as np
from cirq import Circuit

from mitiq import Executor, Observable, QuantumResult
from mitiq.lre import (
multivariate_layer_scaling,
multivariate_richardson_coefficients,
)
from mitiq.zne.scaling import fold_gates_at_random


def execute_with_lre(
input_circuit: Circuit,
executor: Union[Executor, Callable[[Circuit], QuantumResult]],
shots: int,
degree: int,
fold_multiplier: int,
folding_method: Callable[[Circuit, float], Circuit] = fold_gates_at_random,
num_chunks: Optional[int] = None,
observable: Optional[Observable] = None,
)-> float:
noise_scaled_circuits = multivariate_layer_scaling(
input_circuit, degree, fold_multiplier, num_chunks, folding_method
)
linear_combination_coeffs = multivariate_richardson_coefficients(
input_circuit, degree, fold_multiplier, num_chunks
)
normalized_shots_list = shots // len(linear_combination_coeffs)
rescaled_shots_list = [normalized_shots_list] * len(
linear_combination_coeffs
)

lre_exp_values = []
for circuit_shots, scaled_circuit in zip(
rescaled_shots_list, noise_scaled_circuits
):
circ_exp_val = executor(scaled_circuit, shots=circuit_shots)
lre_exp_values.append(circ_exp_val)

# verify the linear combination coefficients and the calculated expectation
# values have the same length
assert len(lre_exp_values) == len(linear_combination_coeffs)

return np.dot(lre_exp_values, linear_combination_coeffs)


def mitigate_executor(
executor: Union[Executor, Callable[[Circuit], QuantumResult]],
shots: int,
degree: int,
fold_multiplier: int,
folding_method: Callable[[Circuit, float], Circuit] = fold_gates_at_random,
num_chunks: Optional[int] = None,
observable: Optional[Observable] = None,
) -> Callable[[Circuit], float]:
@wraps(executor)
def new_executor(input_circuit: Circuit) -> float:
return execute_with_lre(

Check warning on line 68 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L66-L68

Added lines #L66 - L68 were not covered by tests
input_circuit,
executor,
shots,
degree,
fold_multiplier,
folding_method,
num_chunks,
observable,
)

return new_executor

Check warning on line 79 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L79

Added line #L79 was not covered by tests


def lre_decorator(
shots: int,
degree: int,
fold_multiplier: int,
folding_method: Callable[[Circuit, float], Circuit] = fold_gates_at_random,
num_chunks: Optional[int] = None,
observable: Optional[Observable] = None,
) -> Callable[
[Callable[[Circuit], QuantumResult]], Callable[[Circuit], float]
]:
# Raise an error if the decorator is used without parenthesis
if callable(observable):
raise TypeError(

Check warning on line 94 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L93-L94

Added lines #L93 - L94 were not covered by tests
"Decorator must be used with parentheses (i.e., @lre_decorator()) "
"with explicit arguments for shots, degree and fold_multiplier."
)

def decorator(

Check warning on line 99 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L99

Added line #L99 was not covered by tests
executor: Callable[[Circuit], QuantumResult],
) -> Callable[[Circuit], float]:
return mitigate_executor(

Check warning on line 102 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L102

Added line #L102 was not covered by tests
executor,
shots,
degree,
fold_multiplier,
folding_method,
num_chunks,
observable,
)

return decorator

Check warning on line 112 in mitiq/lre/lre.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/lre.py#L112

Added line #L112 was not covered by tests
30 changes: 30 additions & 0 deletions mitiq/lre/tests/test_lre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Unit tests for the LRE extrapolation methods."""

from cirq import DensityMatrixSimulator, depolarize

from mitiq import benchmarks
from mitiq.lre import execute_with_lre

test_cirq = benchmarks.generate_rb_circuits(
n_qubits=1,
num_cliffords=2,
)[0]


def execute(circuit, noise_level=0.025, shots=1000):
"""Returns Tr[ρ |0⟩⟨0|] where ρ is the state prepared by the circuit
executed with depolarizing noise.
"""
# Replace with code based on your frontend and backend.
mitiq_circuit = circuit
noisy_circuit = mitiq_circuit.with_noise(depolarize(p=noise_level))
rho = DensityMatrixSimulator().simulate(noisy_circuit).final_density_matrix
return rho[0, 0].real


def test_lre_exp_value():
noisy_val = execute(test_cirq)
ideal_val = execute(test_cirq, noise_level=0, shots=1000)
assert abs(ideal_val - noisy_val) > 0
lre_exp_val = execute_with_lre(test_cirq, execute, 1000, 2, 2)
assert lre_exp_val > noisy_val

0 comments on commit 6614641

Please sign in to comment.