-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Projectors for TensorFlow quantum #4331
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
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
0339829
First retry at projectors
tonybruguier a5ac063
Delete soon-to-be-useless tests
tonybruguier e428f58
Delete more useless tests
tonybruguier 3f61ecd
Remove ability to use tuples
tonybruguier 6b13d7e
Restrict to only integer, still TODO to make it sparse
tonybruguier 9a1de0c
Now only using integers
tonybruguier 420d2c7
Some nits
tonybruguier e419db3
nit
tonybruguier b798ed7
Skeleton for ProjectorSum
tonybruguier d4600d7
JSON serialization
tonybruguier c648299
With multiplication
tonybruguier 60b1846
Operations
tonybruguier f8fc7b4
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier 69965e3
Fixes
tonybruguier 6027dbc
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier 6c0da89
Factor out ProjectorSum
tonybruguier 33ff2c9
sparse
tonybruguier 89d2b35
Delete dead code
tonybruguier fd63c73
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier 846af79
Coeff, random state vector in testing
tonybruguier e8d8374
Only qubits
tonybruguier df91f9e
Faster expectations
tonybruguier 1cfecaf
docstrings
tonybruguier 20b2284
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier 2623804
Fix docstring
tonybruguier b340c01
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier 557a1df
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier c9a0fca
Address some of the comments
tonybruguier a6071c6
More test
tonybruguier c06648e
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier dcf1997
Simplify how to get 'idx_to_keep'
tonybruguier File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -250,6 +250,7 @@ | |
PhasedXPowGate, | ||
PhasedXZGate, | ||
PhaseFlipChannel, | ||
ProjectorString, | ||
RandomGateChannel, | ||
qft, | ||
Qid, | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import itertools | ||
from typing import ( | ||
Any, | ||
Dict, | ||
Iterable, | ||
List, | ||
Mapping, | ||
Optional, | ||
Union, | ||
) | ||
|
||
import numpy as np | ||
from scipy.sparse import csr_matrix | ||
|
||
from cirq import value | ||
from cirq.ops import raw_types | ||
|
||
|
||
def _check_qids_dimension(qids): | ||
"""A utility to check that we only have Qubits.""" | ||
for qid in qids: | ||
if qid.dimension != 2: | ||
raise ValueError(f"Only qubits are supported, but {qid} has dimension {qid.dimension}") | ||
|
||
|
||
@value.value_equality | ||
class ProjectorString: | ||
def __init__( | ||
self, | ||
projector_dict: Dict[raw_types.Qid, int], | ||
coefficient: Union[int, float, complex] = 1, | ||
): | ||
"""Contructor for ProjectorString | ||
|
||
Args: | ||
projector_dict: A python dictionary mapping from cirq.Qid to integers. A key value pair | ||
represents the desired computational basis state for that qubit. | ||
coefficient: Initial scalar coefficient. Defaults to 1. | ||
""" | ||
_check_qids_dimension(projector_dict.keys()) | ||
self._projector_dict = projector_dict | ||
self._coefficient = complex(coefficient) | ||
|
||
@property | ||
def projector_dict(self) -> Dict[raw_types.Qid, int]: | ||
return self._projector_dict | ||
|
||
@property | ||
def coefficient(self) -> complex: | ||
return self._coefficient | ||
|
||
def matrix(self, projector_qids: Optional[Iterable[raw_types.Qid]] = None) -> csr_matrix: | ||
"""Returns the matrix of self in computational basis of qubits. | ||
|
||
Args: | ||
projector_qids: Ordered collection of qubits that determine the subspace | ||
in which the matrix representation of the ProjectorString is to | ||
be computed. Qbits absent from self.qubits are acted on by | ||
the identity. Defaults to the qubits of the projector_dict. | ||
|
||
Returns: | ||
A sparse matrix that is the projection in the specified basis. | ||
""" | ||
projector_qids = self._projector_dict.keys() if projector_qids is None else projector_qids | ||
_check_qids_dimension(projector_qids) | ||
idx_to_keep = [ | ||
[self._projector_dict[qid]] if qid in self._projector_dict else [0, 1] | ||
for qid in projector_qids | ||
] | ||
|
||
total_d = np.prod([qid.dimension for qid in projector_qids]) | ||
|
||
ones_idx = [] | ||
for idx in itertools.product(*idx_to_keep): | ||
d = total_d | ||
kron_idx = 0 | ||
for i, qid in zip(idx, projector_qids): | ||
d //= qid.dimension | ||
kron_idx += i * d | ||
ones_idx.append(kron_idx) | ||
|
||
return csr_matrix( | ||
([self._coefficient] * len(ones_idx), (ones_idx, ones_idx)), shape=(total_d, total_d) | ||
) | ||
|
||
def _get_idx_to_keep(self, qid_map: Mapping[raw_types.Qid, int]): | ||
num_qubits = len(qid_map) | ||
idx_to_keep: List[Any] = [slice(0, 2)] * num_qubits | ||
for q in self.projector_dict.keys(): | ||
idx_to_keep[qid_map[q]] = self.projector_dict[q] | ||
return tuple(idx_to_keep) | ||
|
||
def expectation_from_state_vector( | ||
self, | ||
state_vector: np.ndarray, | ||
qid_map: Mapping[raw_types.Qid, int], | ||
) -> complex: | ||
"""Expectation of the projection from a state vector. | ||
|
||
Computes the expectation value of this ProjectorString on the provided state vector. | ||
|
||
Args: | ||
state_vector: An array representing a valid state vector. | ||
qubit_map: A map from all qubits used in this ProjectorString to the | ||
indices of the qubits that `state_vector` is defined over. | ||
Returns: | ||
The expectation value of the input state. | ||
""" | ||
_check_qids_dimension(qid_map.keys()) | ||
num_qubits = len(qid_map) | ||
index = self._get_idx_to_keep(qid_map) | ||
return self._coefficient * np.sum( | ||
np.abs(np.reshape(state_vector, (2,) * num_qubits)[index]) ** 2 | ||
) | ||
|
||
def expectation_from_density_matrix( | ||
self, | ||
state: np.ndarray, | ||
qid_map: Mapping[raw_types.Qid, int], | ||
) -> complex: | ||
"""Expectation of the projection from a density matrix. | ||
|
||
Computes the expectation value of this ProjectorString on the provided state. | ||
|
||
Args: | ||
state: An array representing a valid density matrix. | ||
qubit_map: A map from all qubits used in this ProjectorString to the | ||
indices of the qubits that `state_vector` is defined over. | ||
Returns: | ||
The expectation value of the input state. | ||
""" | ||
_check_qids_dimension(qid_map.keys()) | ||
num_qubits = len(qid_map) | ||
index = self._get_idx_to_keep(qid_map) * 2 | ||
result = np.reshape(state, (2,) * (2 * num_qubits))[index] | ||
while any(result.shape): | ||
result = np.trace(result, axis1=0, axis2=len(result.shape) // 2) | ||
return self._coefficient * result | ||
|
||
def __repr__(self) -> str: | ||
return ( | ||
f"cirq.ProjectorString(projector_dict={self._projector_dict}," | ||
+ f"coefficient={self._coefficient})" | ||
) | ||
|
||
def _json_dict_(self) -> Dict[str, Any]: | ||
return { | ||
'cirq_type': self.__class__.__name__, | ||
'projector_dict': list(self._projector_dict.items()), | ||
'coefficient': self._coefficient, | ||
} | ||
|
||
@classmethod | ||
def _from_json_dict_(cls, projector_dict, coefficient, **kwargs): | ||
return cls(projector_dict=dict(projector_dict), coefficient=coefficient) | ||
|
||
def _value_equality_values_(self) -> Any: | ||
projector_dict = sorted(self._projector_dict.items()) | ||
return (tuple(projector_dict), self._coefficient) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.