-
Notifications
You must be signed in to change notification settings - Fork 46
Add Statevec.to_dict and Statevec.to_prob_dict methods
#457
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
base: master
Are you sure you want to change the base?
Changes from all commits
b531b58
e2c620a
73ace3d
c26d413
e5d43e7
974ef7b
7fff4cd
f178b33
35b39c5
dfcbcbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
| import math | ||
| from collections.abc import Iterable | ||
| from dataclasses import dataclass | ||
| from typing import TYPE_CHECKING, SupportsComplex, SupportsFloat | ||
| from typing import TYPE_CHECKING, Literal, SupportsComplex, SupportsFloat | ||
|
|
||
| import numpy as np | ||
| import numpy.typing as npt | ||
|
|
@@ -25,6 +25,7 @@ | |
| from graphix.parameter import ExpressionOrFloat, ExpressionOrSupportsFloat, Parameter | ||
| from graphix.sim.data import Data | ||
|
|
||
| _ENCODING = Literal["LSB", "MSB"] | ||
|
|
||
| CZ_TENSOR = np.array( | ||
| [[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, -1]]]], | ||
|
|
@@ -214,7 +215,7 @@ def dims(self) -> tuple[int, ...]: | |
| @override | ||
| def nqubit(self) -> int: | ||
| """Return the number of qubits.""" | ||
| return len(self.psi.shape) | ||
| return self.psi.ndim | ||
|
|
||
| @override | ||
| def remove_qubit(self, qarg: int) -> None: | ||
|
|
@@ -427,6 +428,110 @@ def isclose(self, other: Statevec, *, rtol: float = 1e-09, atol: float = 0.0) -> | |
| """ | ||
| return math.isclose(self.fidelity(other), 1, rel_tol=rtol, abs_tol=atol) | ||
|
|
||
| def to_dict( | ||
| self, | ||
| encoding: _ENCODING = "MSB", | ||
| *, | ||
| rel_tol: float = 0.0, | ||
| abs_tol: float = 1e-8, | ||
| ) -> dict[str, complex]: | ||
| r"""Convert the statevector to dictionary form. | ||
|
|
||
| This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings | ||
| for the basis vectors and ``values`` are the corresponding complex amplitudes. Amplitudes below a certain threshold are filtered out. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| encoding : _ENCODING, default="MSB" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Private constants like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, I'll document as: Note however that running I guess we can maybe opt-out that rule when we implement #446 @emlynsg |
||
| Encoding for the basis kets. See notes for additional information. | ||
|
|
||
| rel_tol : float, default=0.0 | ||
| Relative tolerance used when deciding whether a coefficient should be | ||
| treated as zero. Values whose magnitude is within this relative tolerance | ||
| of zero are omitted from the resulting dictionary. | ||
|
|
||
| abs_tol : float, default=1e-8 | ||
| Absolute tolerance used when deciding whether a coefficient should be | ||
| treated as zero. Values whose magnitude is within this relative tolerance | ||
| of zero are omitted from the resulting dictionary. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, complex] | ||
| The statevector in dictionary form. | ||
|
|
||
| Notes | ||
| ----- | ||
| The encoding determines the bit ordering convention used when mapping basis states to dictionary | ||
| keys. Consider a tensor product of three qubits: | ||
|
|
||
| .. math:: | ||
|
|
||
| \lvert\psi\rangle = q_0 \otimes q_1 \otimes q_2. | ||
|
|
||
| If ``encoding == "MSB"`` the first qubit is represented in the Most Significant Bit -> ``q0q1q2``. This is the default representation in Graphix. | ||
| If ``encoding == "LSB"`` the first qubit is represented in the Least Significant Bit -> ``q2q1q1``. This is the default representation in other software packages such as Qiskit. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| Example | ||
| ------- | ||
| >>> from graphix.states import BasicStates | ||
| >>> from graphix.sim.statevec import Statevec | ||
| >>> sv = Statevec(data=[BasicStates.ZERO, BasicStates.ONE]) | ||
| >>> sv.to_dict() | ||
| {'01': np.complex128(1+0j)} | ||
| >>> sv.to_dict(encoding="LSB") | ||
| {'10': np.complex128(1+0j)} | ||
| """ | ||
|
|
||
| def format_encoding(i: int) -> str: | ||
| display_width = self.nqubit | ||
| output = f"{i:0{display_width}b}" | ||
| if encoding == "LSB": | ||
| return output[::-1] | ||
| return output | ||
|
|
||
| return { | ||
| format_encoding(i): amp | ||
| for i, amp in enumerate(self.flatten()) | ||
| if not math.isclose(abs(amp), 0, rel_tol=rel_tol, abs_tol=abs_tol) | ||
| } | ||
|
|
||
| def to_prob_dict( | ||
| self, encoding: _ENCODING = "MSB", *, rel_tol: float = 0.0, abs_tol: float = 1e-8 | ||
| ) -> dict[str, float]: | ||
| r"""Convert the statevector to a probability distirbution in a dictionary form. | ||
|
|
||
| This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings | ||
| for the basis vectors and ``values`` are the corresponding probabilities. Basis vector whose amplitude is below a certain threshold are filtered out. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| encoding: _ENCODING, default="MSB" | ||
| Encoding for the basis kets. See :meth:`to_dict` for additional information. | ||
|
|
||
| rel_tol : float, default=0.0 | ||
| Relative tolerance used when deciding whether a coefficient should be | ||
| treated as zero. Values whose magnitude is within this relative tolerance | ||
| of zero are omitted from the resulting dictionary. | ||
|
|
||
| abs_tol : float, default=1e-8 | ||
| Absolute tolerance used when deciding whether a coefficient should be | ||
| treated as zero. Values whose magnitude is within this relative tolerance | ||
| of zero are omitted from the resulting dictionary. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, float] | ||
| The probability distribution associated to the statevector in dictionary form. | ||
|
|
||
| See Also | ||
| -------- | ||
| .. :meth:`to_dict` | ||
| """ | ||
| return { | ||
| key: float(abs(amp) ** 2) for key, amp in self.to_dict(encoding, rel_tol=rel_tol, abs_tol=abs_tol).items() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This cast to |
||
| } | ||
|
|
||
| def subs(self, variable: Parameter, substitute: ExpressionOrSupportsFloat) -> Statevec: | ||
| """Return a copy of the state vector where all occurrences of the given variable in measurement angles are substituted by the given value.""" | ||
| result = Statevec() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Since
_ENCODINGappears to be used only for type checking, you could define it within theTYPE_CHECKINGblock. This would also allow moving thetyping.Literalimport there.