-
Notifications
You must be signed in to change notification settings - Fork 104
Add a phased classical action for SelectedMajoranaFermion #1778
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: main
Are you sure you want to change the base?
Changes from all commits
8a546b1
7d9760f
a80e56b
17b197c
6ccedf1
e78143b
0ab0153
68e1c34
8ddf870
60e02f4
9305db5
b133c37
a0ba13c
8811944
059c26e
ba4c7df
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 | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,7 @@ | |||||||||||||||||||||||||||||||
| # limitations under the License. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| from functools import cached_property | ||||||||||||||||||||||||||||||||
| from typing import Iterator, Sequence, Tuple, Union | ||||||||||||||||||||||||||||||||
| from typing import Dict, Iterator, Sequence, Tuple, Union | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import attrs | ||||||||||||||||||||||||||||||||
| import cirq | ||||||||||||||||||||||||||||||||
|
|
@@ -25,6 +25,7 @@ | |||||||||||||||||||||||||||||||
| from qualtran._infra.data_types import BQUInt | ||||||||||||||||||||||||||||||||
| from qualtran._infra.gate_with_registers import total_bits | ||||||||||||||||||||||||||||||||
| from qualtran.bloqs.multiplexers.unary_iteration_bloq import UnaryIterationGate | ||||||||||||||||||||||||||||||||
| from qualtran.simulation.classical_sim import ClassicalValT | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @attrs.frozen | ||||||||||||||||||||||||||||||||
|
|
@@ -137,5 +138,54 @@ def nth_operation( # type: ignore[override] | |||||||||||||||||||||||||||||||
| yield self.target_gate(target[target_idx]).controlled_by(control) | ||||||||||||||||||||||||||||||||
| yield cirq.CZ(*accumulator, target[target_idx]) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def on_classical_vals(self, **vals) -> Dict[str, 'ClassicalValT']: | ||||||||||||||||||||||||||||||||
| if self.target_gate != cirq.X and self.target_gate != cirq.Z: | ||||||||||||||||||||||||||||||||
| return NotImplemented | ||||||||||||||||||||||||||||||||
| if len(self.control_registers) != 1 or len(self.selection_registers) != 1: | ||||||||||||||||||||||||||||||||
| return NotImplemented | ||||||||||||||||||||||||||||||||
| control_name = self.control_registers[0].name | ||||||||||||||||||||||||||||||||
| control = vals[control_name] | ||||||||||||||||||||||||||||||||
| selection_name = self.selection_registers[0].name | ||||||||||||||||||||||||||||||||
| selection = vals[selection_name] | ||||||||||||||||||||||||||||||||
| target = vals['target'] | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # When target_gate == cirq.X, flip the selection-th bit in target. The ith bit of a | ||||||||||||||||||||||||||||||||
| # size N regirster is addressed with the unsigned integer 2^(N - 1 - i) in our big | ||||||||||||||||||||||||||||||||
| # endian convention. | ||||||||||||||||||||||||||||||||
| if control and self.target_gate == cirq.X: | ||||||||||||||||||||||||||||||||
| max_selection = self.selection_registers[0].dtype.iteration_length_or_zero() - 1 | ||||||||||||||||||||||||||||||||
| target = (2 ** (max_selection - selection)) ^ target | ||||||||||||||||||||||||||||||||
|
Comment on lines
+155
to
+157
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. If
Suggested change
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. Having selection > max_selection indicates an invalid input vals, so it is working as intended for there to be an error. |
||||||||||||||||||||||||||||||||
| # When target_gate == cirq.Z, the action is only in the phase. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return {control_name: control, selection_name: selection, 'target': target} | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def basis_state_phase(self, **vals) -> Union[complex, None]: | ||||||||||||||||||||||||||||||||
| if self.target_gate != cirq.X and self.target_gate != cirq.Z: | ||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||
| if len(self.control_registers) != 1 or len(self.selection_registers) != 1: | ||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||
| control_name = self.control_registers[0].name | ||||||||||||||||||||||||||||||||
| control = vals[control_name] | ||||||||||||||||||||||||||||||||
| selection_name = self.selection_registers[0].name | ||||||||||||||||||||||||||||||||
| selection = vals[selection_name] | ||||||||||||||||||||||||||||||||
| target = vals['target'] | ||||||||||||||||||||||||||||||||
| if control: | ||||||||||||||||||||||||||||||||
| max_selection = self.selection_registers[0].dtype.iteration_length_or_zero() - 1 | ||||||||||||||||||||||||||||||||
| # This gate applies Z in positions 0 through (selection - 1). The effect is | ||||||||||||||||||||||||||||||||
| # a phase of plus or minus 1 depending on the parity of the number of ones | ||||||||||||||||||||||||||||||||
| # in those positions. For an N-bit big endien integer, the first j bits can | ||||||||||||||||||||||||||||||||
| # be isolated by shifting right by N - j. | ||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||
| # The target gate X has no additional phase, so calculate as in the | ||||||||||||||||||||||||||||||||
| # previous paragraph. | ||||||||||||||||||||||||||||||||
| if self.target_gate == cirq.X: | ||||||||||||||||||||||||||||||||
| num_phases = (target >> (max_selection - selection + 1)).bit_count() | ||||||||||||||||||||||||||||||||
|
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. explain how this works
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. Done. |
||||||||||||||||||||||||||||||||
| # The taget gate Z is applied in position selection, so consider the full | ||||||||||||||||||||||||||||||||
| # range 0 through selection. | ||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||
| num_phases = (target >> (max_selection - selection)).bit_count() | ||||||||||||||||||||||||||||||||
|
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. explain how this works and why it's different from the
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. Comment added. Switching this to an elif produced a lint warning that num_phases might not be defined. I could fix that by adding |
||||||||||||||||||||||||||||||||
| return 1 if (num_phases % 2) == 0 else -1 | ||||||||||||||||||||||||||||||||
|
Comment on lines
+172
to
+187
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. If
Suggested change
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. Same as above. |
||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def __str__(self): | ||||||||||||||||||||||||||||||||
| return f'SelectedMajoranaFermion({self.target_gate})' | ||||||||||||||||||||||||||||||||
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.
can you add a comment describing how this logic works
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.
Done.
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.
Can you be even more explicit with how the bit twiddling operations correspond to the promised action of the subroutine
"flip the selection-th bit in target. the selection-th bit is addressed with the unsigned integer 2^(N - i) in our big endian convention"
or something like that
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.
Done.