-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Avoid copying unnecessary buffers between simulation iterations #4789
Changes from 4 commits
993cf0c
6abb2b9
9fa2bed
a865b7e
3af3ec4
2a556e4
df67918
2d53c76
4f10146
280ad3e
5f821e4
5edf97f
7bc4908
412c1bc
0480241
b2fda13
a006a39
49cb93d
67141cb
8e8076b
3369294
7f7ff17
195b802
62addd1
2b948a9
5d260b1
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 |
---|---|---|
|
@@ -113,14 +113,14 @@ def _perform_measurement(self, qubits: Sequence['cirq.Qid']) -> List[int]: | |
"""Child classes that perform measurements should implement this with | ||
the implementation.""" | ||
|
||
def copy(self: TSelf) -> TSelf: | ||
def copy(self: TSelf, reuse_buffer: bool = False) -> TSelf: | ||
"""Creates a copy of the object.""" | ||
args = copy.copy(self) | ||
self._on_copy(args) | ||
self._on_copy(args, reuse_buffer) | ||
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. Make sure to do a 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 have added the deprecation warning and a test for it, but I am not sure whether I am doing it in the right way. I can continue improving it based on your feedback. |
||
args._log_of_measurement_results = self.log_of_measurement_results.copy() | ||
return args | ||
|
||
def _on_copy(self: TSelf, args: TSelf): | ||
def _on_copy(self: TSelf, args: TSelf, reuse_buffer: bool = False): | ||
"""Subclasses should implement this with any additional state copy | ||
functionality.""" | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,9 +174,10 @@ def _perform_measurement(self, qubits: Sequence['cirq.Qid']) -> List[int]: | |
) | ||
return bits | ||
|
||
def _on_copy(self, target: 'cirq.ActOnStateVectorArgs'): | ||
def _on_copy(self, target: 'cirq.ActOnStateVectorArgs', reuse_buffer: bool = False): | ||
target.target_tensor = self.target_tensor.copy() | ||
target.available_buffer = self.available_buffer.copy() | ||
if reuse_buffer: | ||
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.
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 understanding is: if the buffer is copied to the new object, then it can be "reused"; otherwise, the object might need to create its own buffer (from scratch). The point is, the context of the parameter is only the 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. In act_on_args.copy in line 118, it does a shallow copy, meaning that if we don't do anything, then the buffer instance itself is not copied. Thus if I'm not quite sure I catch the question about semantics, but whether-or-not-to-copy-the-buffer is context-dependent, not data-structure-dependent. If the calling function is running repetitions serially (as |
||
target.available_buffer = self.available_buffer.copy() | ||
|
||
def _on_kronecker_product( | ||
self, other: 'cirq.ActOnStateVectorArgs', target: 'cirq.ActOnStateVectorArgs' | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -68,7 +68,7 @@ def apply_operation(self, op: 'cirq.Operation'): | |||||||||||||||||||||||
protocols.act_on(op, self) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
@abc.abstractmethod | ||||||||||||||||||||||||
def copy(self: TSelfTarget) -> TSelfTarget: | ||||||||||||||||||||||||
def copy(self: TSelfTarget, reuse_buffer: bool = False) -> TSelfTarget: | ||||||||||||||||||||||||
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. Make sure to add Args to the docstring with an explanation of 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 have added the paragraph to the docstring, but I do not fully understand it. It seems that there are no buffers shared between the iterations of the simulation. Cirq/cirq-core/cirq/sim/simulator_base.py Lines 268 to 278 in b60b9f8
I cannot find where the shared buffer is stored. It is not in 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. Is this comment old? You have updated the function in 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 have not discussed it yet and I still hold the same opinion. I agree that without copying buffers would improve performance. I am just not sure about the name 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. Sure, how would you phrase it? My wording probably wasn't the best. 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. Can we say 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. Hmm, that sounds to me like it would just set the new object buffer to null. But I think I understand your point in that reuse_buffers could be confusing too. Maybe something more direct like shallow_copy_buffers? 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. Yes, I support a more direct way. But, is the buffer shallow copied? I only write
in 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. Well by "shallow copied", I mean the reference to Maybe clearer in both situations would be to call it 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. Agree. I will update the code soon. |
||||||||||||||||||||||||
"""Copies the object.""" | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
@property | ||||||||||||||||||||||||
|
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.
There's definitely a breaking change here, in that any external subclass of
ActOnArgs
(if one exists...) with its own definition ofcopy
will break whencopy
is called on it by Cirq code that uses both arguments.In hindsight, the right way to prevent this probably involves private classes (which Python is allergic to), but given how heavily internal this code is I think we can get away with this.
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.
We managed to make this non breaking with some reflection. Hence the test that still works. Warning messages are appropriately emitted when the new argument does not exist (and there are tests around that as well).
This could be a good reference for doing such things.
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.
Yes, if we check the signature before actually calling the
copy
(like the case inSimulatorBase._run
), we can avoid errors.