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

ProjectorSum object for TFQ #4364

Merged
merged 67 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
0339829
First retry at projectors
tonybruguier Jul 18, 2021
a5ac063
Delete soon-to-be-useless tests
tonybruguier Jul 18, 2021
e428f58
Delete more useless tests
tonybruguier Jul 18, 2021
3f61ecd
Remove ability to use tuples
tonybruguier Jul 18, 2021
6b13d7e
Restrict to only integer, still TODO to make it sparse
tonybruguier Jul 18, 2021
9a1de0c
Now only using integers
tonybruguier Jul 18, 2021
420d2c7
Some nits
tonybruguier Jul 18, 2021
e419db3
nit
tonybruguier Jul 19, 2021
b798ed7
Skeleton for ProjectorSum
tonybruguier Jul 19, 2021
d4600d7
JSON serialization
tonybruguier Jul 19, 2021
c648299
With multiplication
tonybruguier Jul 19, 2021
60b1846
Operations
tonybruguier Jul 19, 2021
f8fc7b4
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 20, 2021
69965e3
Fixes
tonybruguier Jul 20, 2021
6027dbc
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 20, 2021
6c0da89
Factor out ProjectorSum
tonybruguier Jul 20, 2021
33ff2c9
sparse
tonybruguier Jul 21, 2021
89d2b35
Delete dead code
tonybruguier Jul 21, 2021
fd63c73
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 21, 2021
a9281df
Revert "Factor out ProjectorSum"
tonybruguier Jul 21, 2021
7d3b8ed
Fix unit test
tonybruguier Jul 21, 2021
887ae7f
matrix() return sparse matrix
tonybruguier Jul 22, 2021
846af79
Coeff, random state vector in testing
tonybruguier Jul 22, 2021
e8d8374
Only qubits
tonybruguier Jul 23, 2021
df91f9e
Faster expectations
tonybruguier Jul 23, 2021
1cfecaf
docstrings
tonybruguier Jul 23, 2021
123a02c
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 23, 2021
23ff98e
Fix more merge issues
tonybruguier Jul 23, 2021
3db11fa
Bug fix with coefficient
tonybruguier Jul 23, 2021
20b2284
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 24, 2021
bc6df8d
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 24, 2021
02e512f
Docstrings
tonybruguier Jul 24, 2021
2623804
Fix docstring
tonybruguier Jul 24, 2021
e77642c
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 24, 2021
7363b90
Fix docstring
tonybruguier Jul 24, 2021
b340c01
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 25, 2021
53cdf51
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 25, 2021
557a1df
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 26, 2021
c9a0fca
Address some of the comments
tonybruguier Jul 27, 2021
e1d0130
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 27, 2021
6680935
Change output type
tonybruguier Jul 27, 2021
a6071c6
More test
tonybruguier Jul 27, 2021
b28ef4b
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 27, 2021
c06648e
Merge branch 'master' of github.com:quantumlib/Cirq into projector_st…
tonybruguier Jul 28, 2021
dcf1997
Simplify how to get 'idx_to_keep'
tonybruguier Jul 28, 2021
14d3717
Merge branch 'projector_strings' into projector_sums
tonybruguier Jul 28, 2021
d2c408f
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Jul 28, 2021
3b903a6
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Jul 29, 2021
5d53ca9
subtraction and negation too
tonybruguier Jul 29, 2021
f3b4b4c
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Jul 31, 2021
cca094d
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 2, 2021
5db120e
Address some comments
tonybruguier Aug 2, 2021
6887011
No longer copy
tonybruguier Aug 2, 2021
f69a96f
fix some test
tonybruguier Aug 2, 2021
7d6e713
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 5, 2021
4a06b7d
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 6, 2021
3925a2b
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 8, 2021
0cb8f5c
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 9, 2021
c9a95f7
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 10, 2021
3a5fc0b
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 11, 2021
2de88de
Address comments
tonybruguier Aug 11, 2021
4c78eb4
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 12, 2021
0f61a61
Add ability to add ProjectorStrings to ProjectorSums
tonybruguier Aug 12, 2021
4e1b12c
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 14, 2021
6892e37
Merge branch 'master' of github.com:quantumlib/Cirq into projector_sums
tonybruguier Aug 17, 2021
7fdc4e5
Address comments
tonybruguier Aug 17, 2021
6caaf63
Merge branch 'master' into projector_sums
CirqBot Aug 19, 2021
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
1 change: 1 addition & 0 deletions cirq-core/cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@
PhasedXZGate,
PhaseFlipChannel,
ProjectorString,
ProjectorSum,
RandomGateChannel,
qft,
Qid,
Expand Down
1 change: 1 addition & 0 deletions cirq-core/cirq/json_resolver_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def two_qubit_matrix_gate(matrix):
'PhasedXPowGate': cirq.PhasedXPowGate,
'PhasedXZGate': cirq.PhasedXZGate,
'ProjectorString': cirq.ProjectorString,
'ProjectorSum': cirq.ProjectorSum,
'RandomGateChannel': cirq.RandomGateChannel,
'QuantumFourierTransformGate': cirq.QuantumFourierTransformGate,
'RepetitionsStoppingCriteria': cirq.work.RepetitionsStoppingCriteria,
Expand Down
1 change: 1 addition & 0 deletions cirq-core/cirq/ops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
LinearCombinationOfOperations,
PauliSum,
PauliSumLike,
ProjectorSum,
)

from cirq.ops.mixed_unitary_channel import (
Expand Down
210 changes: 210 additions & 0 deletions cirq-core/cirq/ops/linear_combinations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from collections import defaultdict
from typing import (
AbstractSet,
Any,
Dict,
Iterable,
Mapping,
Expand All @@ -31,12 +32,14 @@
from sympy.logic.boolalg import And, Not, Or, Xor
from sympy.core.expr import Expr
from sympy.core.symbol import Symbol
from scipy.sparse import csr_matrix

from cirq import linalg, protocols, qis, value
from cirq._doc import document
from cirq.linalg import operator_spaces
from cirq.ops import identity, raw_types, pauli_gates, pauli_string
from cirq.ops.pauli_string import PauliString, _validate_qubit_mapping
from cirq.ops.projector import ProjectorString
from cirq.value.linear_dict import _format_terms

if TYPE_CHECKING:
Expand Down Expand Up @@ -739,3 +742,210 @@ def __format__(self, format_spec: str) -> str:

def __str__(self) -> str:
return self.__format__('.3f')


def _projector_string_from_projector_dict(projector_dict, coefficient=1.0):
return ProjectorString(dict(projector_dict), coefficient)


@value.value_equality(approximate=True)
class ProjectorSum:
def __init__(
self, linear_dict: Optional[value.LinearDict[FrozenSet[Tuple[raw_types.Qid, int]]]] = None
):
"""Constructor for ProjectorSum

Args:
linear_dict: A linear dictionary from a set of tuples of (Qubit, integer) to a complex
number. The tuple is a projector onto the qubit and the complex number is the
weight of these projections.
"""
self._linear_dict: value.LinearDict[FrozenSet[Tuple[raw_types.Qid, int]]] = (
linear_dict if linear_dict is not None else value.LinearDict({})
)

def _value_equality_values_(self):
return self._linear_dict

def _json_dict_(self) -> Dict[str, Any]:
linear_dict = []
for projector_dict, scalar in dict(self._linear_dict).items():
key = [[k, v] for k, v in dict(projector_dict).items()]
linear_dict.append([key, scalar])
return {
'cirq_type': self.__class__.__name__,
'linear_dict': linear_dict,
}

@classmethod
def _from_json_dict_(cls, linear_dict, **kwargs):
converted_dict = {}
for projector_string in linear_dict:
projector_dict = {x[0]: x[1] for x in projector_string[0]}
scalar = projector_string[1]
key = frozenset(projector_dict.items())
converted_dict[key] = scalar
return cls(linear_dict=value.LinearDict(converted_dict))

@classmethod
def from_projector_strings(
cls, terms: Union[ProjectorString, List[ProjectorString]]
) -> 'ProjectorSum':
"""Builds a ProjectorSum from one or more ProjectorString(s).

Args:
terms: Either a single ProjectorString or a list of ProjectorStrings.

Returns:
A ProjectorSum.
"""
if isinstance(terms, ProjectorString):
terms = [terms]
termdict: DefaultDict[FrozenSet[Tuple[raw_types.Qid, int]], value.Scalar] = defaultdict(
lambda: 0.0
)
for pstring in terms:
key = frozenset(pstring.projector_dict.items())
termdict[key] += pstring.coefficient
return cls(linear_dict=value.LinearDict(termdict))

def copy(self) -> 'ProjectorSum':
return ProjectorSum(self._linear_dict.copy())

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 ProjectorSum 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.
"""
return sum(
coeff * _projector_string_from_projector_dict(vec).matrix(projector_qids)
for vec, coeff in self._linear_dict.items()
)

def expectation_from_state_vector(
self,
state_vector: np.ndarray,
qid_map: Mapping[raw_types.Qid, int],
) -> float:
"""Compute the expectation value of this ProjectorSum given a state vector.

Projects the state vector onto the sum of projectors and computes the expectation of the
measurements.

Args:
state_vector: An array representing a valid state vector.
qubit_map: A map from all qubits used in this ProjectorSum to the indices of the qubits
that `state_vector` is defined over.
Returns:
The expectation value of the input state.
"""
return sum(
coeff
* _projector_string_from_projector_dict(vec).expectation_from_state_vector(
state_vector, qid_map
)
for vec, coeff in self._linear_dict.items()
)

def expectation_from_density_matrix(
self,
state: np.ndarray,
qid_map: Mapping[raw_types.Qid, int],
) -> float:
"""Expectation of the sum of projections from a density matrix.

Projects the density matrix onto the sum of projectors and computes the expectation of the
measurements.

Args:
state: An array representing a valid density matrix.
qubit_map: A map from all qubits used in this ProjectorSum to the indices of the qubits
that `state_vector` is defined over.
Returns:
The expectation value of the input state.
"""
return sum(
coeff
* _projector_string_from_projector_dict(vec).expectation_from_density_matrix(
state, qid_map
)
for vec, coeff in self._linear_dict.items()
)

def __iter__(self):
for vec, coeff in self._linear_dict.items():
yield _projector_string_from_projector_dict(vec, coeff)

def __len__(self) -> int:
return len(self._linear_dict)

def __truediv__(self, a: value.Scalar):
return self.__mul__(1 / a)

def __bool__(self) -> bool:
return bool(self._linear_dict)

def __iadd__(self, other: Union['ProjectorString', 'ProjectorSum']):
if isinstance(other, ProjectorString):
other = ProjectorSum.from_projector_strings(other)
elif not isinstance(other, ProjectorSum):
return NotImplemented
self._linear_dict += other._linear_dict
return self

def __add__(self, other: Union['ProjectorString', 'ProjectorSum']):
if isinstance(other, ProjectorString):
other = ProjectorSum.from_projector_strings(other)
elif not isinstance(other, ProjectorSum):
return NotImplemented
result = self.copy()
result += other
return result

def __isub__(self, other: Union['ProjectorString', 'ProjectorSum']):
if isinstance(other, ProjectorString):
other = ProjectorSum.from_projector_strings(other)
elif not isinstance(other, ProjectorSum):
return NotImplemented
self._linear_dict -= other._linear_dict
return self

def __sub__(self, other: Union['ProjectorString', 'ProjectorSum']):
if isinstance(other, ProjectorString):
other = ProjectorSum.from_projector_strings(other)
elif not isinstance(other, ProjectorSum):
return NotImplemented
result = self.copy()
result -= other
return result

def __neg__(self):
factory = type(self)
return factory(-self._linear_dict)

def __imul__(self, other: value.Scalar):
if not isinstance(other, numbers.Complex):
return NotImplemented
self._linear_dict *= other
return self

def __mul__(self, other: value.Scalar):
if not isinstance(other, numbers.Complex):
return NotImplemented
result = self.copy()
result *= other
return result

def __rmul__(self, other: value.Scalar):
if not isinstance(other, numbers.Complex):
return NotImplemented
result = self.copy()
result *= other
return result
Loading