-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow expectation values for density matrix, MPS, Clifford #3990
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Changes from all commits
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 |
---|---|---|
|
@@ -169,6 +169,9 @@ def __str__(self) -> str: | |
final = self._final_simulator_state | ||
return f'measurements: {samples}\noutput state: {final}' | ||
|
||
def expectation_from_state(self, obs: 'cirq.PauliSum'): | ||
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. Similar to the MPS simulator, there should be a way of calculating expectation values from the Clifford tableau without expanding it to the full state vector. |
||
return obs.expectation_from_state_vector(self.final_state.state_vector(), self.qubit_map) | ||
|
||
|
||
class CliffordSimulatorStepResult(simulator.StepResult['CliffordState']): | ||
"""A `StepResult` that includes `StateVectorMixin` methods.""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -302,7 +302,9 @@ def simulate_expectation_values_sweep( | |
""" | ||
|
||
|
||
class SimulatesFinalState(Generic[TSimulationTrialResult], metaclass=abc.ABCMeta): | ||
class SimulatesFinalState( | ||
Generic[TSimulationTrialResult], SimulatesExpectationValues, metaclass=abc.ABCMeta | ||
): | ||
"""Simulator that allows access to the simulator's final state. | ||
|
||
Implementors of this interface should implement the simulate_sweep | ||
|
@@ -372,6 +374,33 @@ def simulate_sweep( | |
""" | ||
raise NotImplementedError() | ||
|
||
def simulate_expectation_values_sweep( | ||
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. We should include a note that this is only a default implementation; depending on the simulator's behavior, there may be a more efficient simulation method that bypasses simulating the full state. |
||
self, | ||
program: 'cirq.Circuit', | ||
observables: Union['cirq.PauliSumLike', List['cirq.PauliSumLike']], | ||
params: 'study.Sweepable', | ||
qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT, | ||
initial_state: Any = None, | ||
permit_terminal_measurements: bool = False, | ||
) -> List[List[float]]: | ||
if not permit_terminal_measurements and program.are_any_measurements_terminal(): | ||
raise ValueError( | ||
'Provided circuit has terminal measurements, which may ' | ||
'skew expectation values. If this is intentional, set ' | ||
'permit_terminal_measurements=True.' | ||
) | ||
swept_evs = [] | ||
qubit_order = ops.QubitOrder.as_qubit_order(qubit_order) | ||
if not isinstance(observables, List): | ||
observables = [observables] | ||
pslist = [ops.PauliSum.wrap(pslike) for pslike in observables] | ||
for param_resolver in study.to_resolvers(params): | ||
result = self.simulate( | ||
program, param_resolver, qubit_order=qubit_order, initial_state=initial_state | ||
) | ||
swept_evs.append([result.expectation_from_state(obs) for obs in pslist]) | ||
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. My concern here: the fact that We could update the class docstring to say that users must implement |
||
return swept_evs | ||
|
||
|
||
class SimulatesIntermediateState( | ||
Generic[TStepResult, TSimulationTrialResult, TSimulatorState], | ||
|
@@ -736,6 +765,12 @@ def qubit_map(self) -> Dict[ops.Qid, int]: | |
def _qid_shape_(self) -> Tuple[int, ...]: | ||
return _qubit_map_to_shape(self.qubit_map) | ||
|
||
def expectation_from_state(self, obs: 'cirq.PauliSum'): | ||
"""Subclasses can implement this to allow expectation values derived | ||
from the final state. | ||
""" | ||
raise NotImplementedError() | ||
|
||
|
||
def _qubit_map_to_shape(qubit_map: Dict[ops.Qid, int]) -> Tuple[int, ...]: | ||
qid_shape: List[int] = [-1] * len(qubit_map) | ||
|
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.
I suspect there is a more efficient way to extract expectiation values from an MPS state than converting it into its full state vector form.