Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LRE Inference Functions #2447

Merged
merged 29 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
428128e
update readme
purva-thakre Jul 10, 2024
90f22dc
function for sample matrix - minus unit test for sample matrix
purva-thakre Jul 16, 2024
634ea80
sample matrix unit tests
purva-thakre Jul 16, 2024
0e297a5
func: coeffs + unit tests
purva-thakre Jul 17, 2024
8b2ad8c
additional unit tests: sample matrix square, raised errors
purva-thakre Jul 17, 2024
00b92c5
unit test: chunking
purva-thakre Jul 18, 2024
d61b1cc
try: abs all threshold for test_coeffs
purva-thakre Jul 21, 2024
7d8868b
docstring cleanup: vincent's comments
purva-thakre Jul 21, 2024
c92a38a
ignore sample matrix not square matrix from coverage report
purva-thakre Jul 21, 2024
c247619
linear_combination_coefficients return docstring, type
purva-thakre Jul 23, 2024
6290f93
additional tests: compare with scaling function
purva-thakre Jul 26, 2024
aef46ab
cleanup Except block
purva-thakre Jul 29, 2024
d382767
check test coverage
purva-thakre Jul 31, 2024
30c6914
temporarily diable mypy
purva-thakre Jul 31, 2024
f320b2b
new full basis terms func
purva-thakre Jul 31, 2024
378aad8
ignore special use cases from pytest coverage
purva-thakre Aug 1, 2024
f539153
make sure coeffs sum up to 1
purva-thakre Aug 1, 2024
f1d1635
more comments + test for exp function
purva-thakre Aug 1, 2024
3ff1578
remove symbolic monomial basis terms function
purva-thakre Aug 7, 2024
eb0f9d7
add to apidoc
purva-thakre Aug 8, 2024
fd6be18
nate's suggestions
purva-thakre Aug 14, 2024
42fd2b1
nate's suggestions: det minor + remove sum(coeffs)==1.0 unit tests
purva-thakre Aug 16, 2024
83880e3
nate's suggestions + default built in for types + concatenate block i…
purva-thakre Aug 20, 2024
7e55d5f
add more details to the docstring + rename coefficients function
purva-thakre Aug 23, 2024
80fe32c
ruff failure
purva-thakre Aug 23, 2024
48bae71
cleanup docstrings
purva-thakre Aug 26, 2024
d81bd6f
Update mitiq/lre/inference/multivariate_richardson.py
purva-thakre Aug 27, 2024
d97c2f3
Update mitiq/lre/inference/multivariate_richardson.py
purva-thakre Aug 27, 2024
f0c0293
update docstring
purva-thakre Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ mitiq.qem_methods()
| Readout-error mitigation | [REM](https://mitiq.readthedocs.io/en/latest/guide/rem.html) | [`mitiq.rem`](https://github.com/unitaryfund/mitiq/tree/main/mitiq/rem) | [1907.08518](https://arxiv.org/abs/1907.08518) <br>[2006.14044](https://arxiv.org/abs/2006.14044)
| Quantum Subspace Expansion | [QSE](https://mitiq.readthedocs.io/en/stable/guide/qse.html) | [`mitiq.qse`](https://github.com/unitaryfund/mitiq/tree/main/mitiq/qse) | [1903.05786](https://arxiv.org/abs/1903.05786)|
| Robust Shadow Estimation 🚧 | [RSE](https://mitiq.readthedocs.io/en/stable/guide/shadows.html)| [`mitiq.qse`](https://github.com/unitaryfund/mitiq/tree/main/mitiq/shadows) | [2011.09636](https://arxiv.org/abs/2011.09636) <br> [2002.08953](https://arxiv.org/abs/2002.08953)|
| Layerwise Richardson Extrapolation 🚧 | Coming soon | | [2402.04000](https://arxiv.org/abs/2402.04000) |
| Layerwise Richardson Extrapolation 🚧 | Coming soon | [`mitiq.lre`](https://github.com/unitaryfund/mitiq/tree/main/mitiq/lre) | [2402.04000](https://arxiv.org/abs/2402.04000) |


In addition, we also have a noise tailoring technique currently available with limited functionality:
Expand Down
8 changes: 7 additions & 1 deletion mitiq/lre/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@

"""Methods for scaling noise in circuits by layers and using multivariate extrapolation."""

from mitiq.lre.multivariate_scaling.layerwise_folding import multivariate_layer_scaling
from mitiq.lre.multivariate_scaling.layerwise_folding import multivariate_layer_scaling

from mitiq.lre.inference.multivariate_richardson import (
full_monomial_basis_terms,
linear_combination_coefficients,
sample_matrix,
)
228 changes: 228 additions & 0 deletions mitiq/lre/inference/multivariate_richardson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# 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.

"""Functions for multivariate richardson extrapolation as defined in
:cite:`Russo_2024_LRE`.
"""

import warnings
from collections import Counter
from itertools import combinations_with_replacement
from typing import Any, Dict, List, Optional

import numpy as np
from cirq import Circuit
from numpy.typing import NDArray
from sympy import Symbol
natestemen marked this conversation as resolved.
Show resolved Hide resolved

from mitiq.lre.multivariate_scaling.layerwise_folding import (
_get_scale_factor_vectors,
)


def _full_monomial_basis_term_exponents(
num_layers: int, degree: int
) -> List[Dict[int, int]]:
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
"""Exponents of monomial terms required to create the sample matrix."""
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
variables = [i for i in range(1, num_layers + 1)]
variable_combinations = []
for d in range(degree, -1, -1):
for var_tuple in combinations_with_replacement(variables, d):
variable_combinations.append(var_tuple)

variable_exp_counter = [
dict(Counter(term)) for term in variable_combinations
]

for combo_key in variable_exp_counter:
for j in variables:
if j not in combo_key:
combo_key[j] = 0

return variable_exp_counter[::-1]


def full_monomial_basis_terms(num_layers: int, degree: int) -> List[str]:
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
r"""Find the monomial basis terms for a number of layers in the input
and max degree d.

Number of layers in the input circuit dictate the number of variables
utilized in the combinations used for the polynomial.

Degree of the polynomial dictates the max and min degree of the monomial
terms.

Args:
num_layers: Number of layers in the input circuit.
degree: Degree of the multivariate polynomial.

Returns:
Monomial basis terms required for multivariate
extrapolation up to max degree
"""
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved

var_exp = _full_monomial_basis_term_exponents(num_layers, degree)
num_var = len(var_exp[0])
var_exp_sorted = []

for i in var_exp:
var_exp_sorted.append(dict(sorted(i.items())))

str_var = [Symbol(f"λ_{i}") for i in range(1, num_var + 1)]

var_prod = []
for i in var_exp_sorted:
var_prod_i = []
for j in range(1, num_var + 1):
if i[j] > 0:
var_prod_i.append((str_var[j - 1]) ** (i[j]))
else:
var_prod_i.append(1)
var_prod.append(var_prod_i)

return [np.prod(item) for item in var_prod]
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved


def sample_matrix(
input_circuit: Circuit,
degree: int,
fold_multiplier: int,
num_chunks: Optional[int] = None,
) -> NDArray[Any]:
r"""
Defines the sample matrix required for multivariate extrapolation as
defined in :cite:`Russo_2024_LRE`.

Args:
input_circuit: Circuit to be scaled.
degree: Degree of the multivariate polynomial.
fold_multiplier: Scaling gap required by unitary folding.
num_chunks: Number of desired approximately equal chunks. When the
number of chunks is the same as the layers in the input circuit,
the input circuit is unchanged.

Returns:
Matrix of the evaluated monomial basis terms from the scale factor
vectors.

Raises:
ValueError:
When the degree for the multinomial is not greater than or
equal to 1; when the fold multiplier to scale the circuit is
greater than/equal to 1; when the number of chunks for a
large circuit is 0 or when the number of chunks in a circuit is
greater than the number of layers in the input circuit.

"""
if degree < 1:
raise ValueError(
"Multinomial degree must be greater than or equal to 1."
)
if fold_multiplier < 1:
raise ValueError("Fold multiplier must be greater than or equal to 1.")
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved

scale_factor_vectors = _get_scale_factor_vectors(
input_circuit, degree, fold_multiplier, num_chunks
)
num_layers = len(scale_factor_vectors[0])

monomial_terms = full_monomial_basis_terms(num_layers, degree)

assert len(monomial_terms) == len(scale_factor_vectors)

# Evaluate the monomial terms using the values in the scale factor vectors
# and insert in the sample matrix
# each row is specific to each scale factor vector
# each column is a term in the monomial basis
variable_exp = _full_monomial_basis_term_exponents(num_layers, degree)
sample_matrix = np.empty((len(variable_exp), len(variable_exp)))

# replace first row and column of the sample matrix by 1s
sample_matrix[:, 0] = 1.0
sample_matrix[0, :] = 1.0
# skip first element of the tuple due to above replacements
variable_exp_wout_0_degree = variable_exp[1:]

# sort dict
variable_exp_wout_0_degree_list = []

for i in variable_exp_wout_0_degree:
variable_exp_wout_0_degree_list.append(dict(sorted(i.items())))

variable_exp_w_0_degree = variable_exp_wout_0_degree_list
# create a list of dict values

variable_exp_list = []
for i in variable_exp_w_0_degree:
val_i = list(i.values())
variable_exp_list.append(val_i)

for rows, i in enumerate(scale_factor_vectors[1:], start=1): # type: ignore[assignment]
for cols, j in enumerate(variable_exp_list, start=1):
evaluated_terms = []
for base, exp in zip(list(i), j):
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
evaluated_terms.append(base**exp)
sample_matrix[rows, cols] = np.prod(evaluated_terms)

return sample_matrix


def linear_combination_coefficients(
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
input_circuit: Circuit,
degree: int,
fold_multiplier: int,
num_chunks: Optional[int] = None,
) -> List[np.float64]:
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
r"""
Defines the sample matrix required for multivariate extrapolation as
defined in :cite:`Russo_2024_LRE`.
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved

Args:
input_circuit: Circuit to be scaled.
degree: Degree of the multivariate polynomial.
fold_multiplier: Scaling gap required by unitary folding.
num_chunks: Number of desired approximately equal chunks. When the
number of chunks is the same as the layers in the input circuit,
the input circuit is unchanged.

Returns:
List of the evaluated monomial basis terms using the scale factor
vectors.
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add error handling?

if degree < 1:
    raise ValueError("Degree must be a positive integer")
if fold_multiplier < 1:
    raise ValueError("Fold multiplier must be a positive integer")
if num_chunks is not None and num_chunks < 1:
    raise ValueError("Number of chunks must be a positive integer")

num_layers = len(
_get_scale_factor_vectors(
input_circuit, degree, fold_multiplier, num_chunks
)
)
input_sample_matrix = sample_matrix(
input_circuit, degree, fold_multiplier, num_chunks
)
try:
det = np.linalg.det(input_sample_matrix)
except RuntimeWarning:

Check warning on line 204 in mitiq/lre/inference/multivariate_richardson.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/inference/multivariate_richardson.py#L204

Added line #L204 was not covered by tests
# taken from https://stackoverflow.com/a/19317237
warnings.warn(

Check warning on line 206 in mitiq/lre/inference/multivariate_richardson.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/inference/multivariate_richardson.py#L206

Added line #L206 was not covered by tests
"To account for overflow error, required determinant of "
+ "large sample matrix is calculated through "
+ "`np.linalg.slogdet`."
)
sign, logdet = np.linalg.slogdet(input_sample_matrix)
det = np.exp(logdet)

Check warning on line 212 in mitiq/lre/inference/multivariate_richardson.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/inference/multivariate_richardson.py#L211-L212

Added lines #L211 - L212 were not covered by tests

if np.isinf(det):
raise ValueError(

Check warning on line 215 in mitiq/lre/inference/multivariate_richardson.py

View check run for this annotation

Codecov / codecov/patch

mitiq/lre/inference/multivariate_richardson.py#L215

Added line #L215 was not covered by tests
"Determinant of sample matrix cannot be calculated as "
+ "the matrix is too large. Consider chunking your"
+ " input circuit. "
)
assert det != 0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to check whether it's close to 0.0 and add an appropriate debug message in case it is not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed this with @natestemen yesterday. We are coming back to think about edge cases like this once the general LRE implementation is complete.

I'll go ahead and create an issue to log all the todos I need to tackle in the immediate future.


coeff_list = []
for i in range(num_layers):
sample_matrix_copy = input_sample_matrix.copy()
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
sample_matrix_copy[i] = np.array([[1] + [0] * (num_layers - 1)])
coeff_list.append(np.linalg.det(sample_matrix_copy) / det)
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved

return coeff_list
Loading