Closed thierry-martinez closed 2 months ago
@thierry-martinez Thanks! Me and @masa10-f think it's time to deprecate localpattern.
@thierry-martinez we should also deprecate standardize_and_transpile
of Circuit
class! I believe it would be good to deprecate LocalPattern
and standardize_and_transpile
in this PR. could you update this branch?
I changed shift_signals
and standardize
to use direct
as the default method, and added warnings to other methods as well as to Circuit.standardize_and_transpile
, and to Pattern.standardize_and_shift_signals
. Without LocalPattern
, there is no longer a benefit to perform these operations simultaneously.
The CI fails on windows-2022
(with all Python versions except 3.8) with the following error:
.tox\py39\lib\site-packages\matplotlib\cbook.py:32: in <module>
from matplotlib import _api, _c_internal_utils
E ImportError: DLL load failed while importing _c_internal_utils: The specified module could not be found.
I don't think this failure is related to a change in this PR, though.
@thierry-martinez LGTM!
@shinich1 @masa10-f Could you check the code correctly implements the measurement calculus?
By the way, do you intend to use the measurement calculus for non-Untiary case? As far I understand, signal shifting requires correction set to be consistent with a gflow or Pauli flow, otherwise it can destruct the computation. I guess we need to check determinism before.(This can be discussed in another place as it might be out of this PR)
We may better turn off RUF003
...
It's going too far that we cannot use Greek letters.
@thierry-martinez
Could you kindly add "RUF003"
to the ignore
section in pyprojec.toml
or use # noqa: RUF003
, and then revert the changes?
Could you kindly add "RUF003" to the ignore section in pyprojec.toml or use # noqa: RUF003 , and then revert the changes?
Done in ad8396f. More precisely, the proof comments are now written as multi-line strings, which enables noqa: RUF001
to be applied to the whole block instead of applying noqa: RUF003
on each single comment line.
I'm a little against this approach (ad8396f) as it forces python interpreter to evaluate the literal as string, whereas comments are simply discarded. How about using https://docs.astral.sh/ruff/settings/#lint_allowed-confusables ?
I agree that using allowed-confusables
is a better approach, especially since it allows α
to appear in other contexts where it can be useful. This has been addressed in commit ceaebaf. However, I don't believe using string literal for comments forces the Python interpreter to evaluate anything. You can verify this by checking the disassembly: string literal statements are compiled into NOP
in the bytecode.
I made two substantial changes yesterday that may warrant additional reviews:
standardize_direct
and shift_signals_direct
more robust with respect to aliasing by ensuring they instantiate new commands and domains instead of modifying them in-place. These functions are now correct even if some command or domain instances are shared between patterns.standardize_direct
to correctly commute C
commands within the pattern. Previous implementations of standardize ignored C
commands.You can verify this by checking the disassembly: string literal statements are compiled into NOP in the bytecode.
I checked it. You're right!
@masa10-f Are you sure that the initial pattern in your example has gflow? I get (None, None)
when I run gflow_from_pattern
on it.
from graphix.command import E, M, N, X, Z
from graphix.gflow import gflow_from_pattern
from graphix.pattern import Pattern
from graphix.pauli import Plane
pattern = Pattern(input_nodes=[1, 2])
pattern.extend(
[
N(node=0),
N(node=3),
N(node=4),
N(node=5),
N(node=6),
E(nodes=(0, 1)),
E(nodes=(0, 3)),
E(nodes=(0, 4)),
E(nodes=(1, 3)),
E(nodes=(2, 4)),
E(nodes=(3, 4)),
E(nodes=(3, 5)),
E(nodes=(4, 6)),
M(node=1, plane=Plane.XY, angle=0.0, s_domain=set(), t_domain=set()),
M(node=2, plane=Plane.XY, angle=0.0, s_domain=set(), t_domain=set()),
M(node=0, plane=Plane.XZ, angle=0.0, s_domain={1, 2}, t_domain={1}),
M(node=3, plane=Plane.XY, angle=0.0, s_domain={0}, t_domain={0, 1, 2}),
M(node=4, plane=Plane.XY, angle=0.0, s_domain={2}, t_domain={1}),
Z(node=6, domain={2}),
Z(node=5, domain={0}),
X(node=5, domain={3}),
X(node=6, domain={4}),
]
)
assert gflow_from_pattern(pattern) == (None, None)
@masa10-f Are you sure that the initial pattern in your example has gflow? I get (None, None) when I run gflow_from_pattern on it.
I'm sorry for confusing you. It does not have gflow in the current convention, but has in the RHS convention we discussed in the thread. I generated the initial pattern with the following code
graph = nx.Graph()
graph.add_nodes_from([0, 1, 2, 3, 4, 5, 6]) # 0 is XZ gadget
graph.add_edges_from(
[
(0, 1),
(0, 3),
(0, 4),
(1, 3),
(2, 4),
(3, 4),
(3, 5),
(4, 6),
]
)
input_nodes = [1, 2]
output_nodes = [5, 6]
meas_planes = {
0: Plane.XZ,
1: Plane.XY,
2: Plane.XY,
3: Plane.XY,
4: Plane.XY,
}
meas_angles = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
pattern = generate_from_graph(
graph, meas_angles, input_nodes, output_nodes, meas_planes
)
pattern.standardize()
With the following modification into standardization, because I didn't notice the convention was changed into LHS.
if cmd.plane == Plane.XY:
if z_cmd := z_dict.pop(cmd.node, None):
cmd.t_domain ^= z_cmd.domain
if x_cmd := x_dict.pop(cmd.node, None):
cmd.s_domain ^= x_cmd.domain
elif cmd.plane == Plane.XZ:
if z_cmd := z_dict.pop(cmd.node, None):
cmd.s_domain ^= z_cmd.domain
if x_cmd := x_dict.pop(cmd.node, None):
cmd.s_domain ^= x_cmd.domain
cmd.t_domain ^= x_cmd.domain
elif cmd.plane == Plane.YZ:
if z_cmd := z_dict.pop(cmd.node, None):
cmd.s_domain ^= z_cmd.domain
if x_cmd := x_dict.pop(cmd.node, None):
cmd.t_domain ^= x_cmd.domain
By the way, do you intend to use the measurement calculus for non-Untiary case? As far I understand, signal shifting requires correction set to be consistent with a gflow or Pauli flow, otherwise it can destruct the computation. I guess we need to check determinism before.(This can be discussed in another place as it might be out of this PR)
Signal shifting inverts some classical outcomes: if the pattern is not deterministic, the relationship between the measures and the quantic state is affected, as illustrated in test_shift_signals_plane
(in this test, the pattern is not deterministic, so has no flow of any kind). I just exposed in my last commit fd8f8c4 the function pattern.shift_outcomes
which converts back and forth outcomes between unshifted and shifted patterns.
Signal shifting inverts some classical outcomes: if the pattern is not deterministic, the relationship between the measures and the quantic state is affected, as illustrated in test_shift_signals_plane (in this test, the pattern is not deterministic, so has no flow of any kind). I just exposed in my last commit fd8f8c4 the function pattern.shift_outcomes which converts back and forth outcomes between unshifted and shifted patterns.
Thank you for your reply! I found an error when I added an extra Pauli correction on the output in the test case. Is it fixable within this algorithm? I haven't ever tried this approach, so I'll consider it more.
pattern = Pattern(input_nodes=[0])
for i in (1, 2, 3):
pattern.add(N(node=i))
pattern.add(E(nodes=[0, i]))
pattern.add(M(node=0, angle=0.5))
pattern.add(M(node=1, angle=0.5))
pattern.add(M(node=2, angle=0.5, plane=plane, s_domain=[0], t_domain=[1]))
pattern.add(Z(node=3, domain=[2])) # <- added
I added the extra Z correction on the output node(X also has error). Then the results are not consistent with standardized ones. I guess the errors are close to Pauli in this case, but it can be more complex in a longer pattern.
FAILED tests/test_pattern.py::TestPattern::test_shift_signals_plane[global-Plane.XY] - assert 1.0007415106216804e-16 == 1 ± 1.0e-06
FAILED tests/test_pattern.py::TestPattern::test_shift_signals_plane[global-Plane.YZ] - assert 0.0 == 1 ± 1.0e-06
FAILED tests/test_pattern.py::TestPattern::test_shift_signals_plane[global-Plane.XZ] - assert 8.326672684688674e-17 == 1 ± 1.0e-06
@masa10-f Nice catch! The problem you discovered is in the global
method: the implementation modifies domains in-place and, therefore, does not support aliasing. The test performed a shallow copy between the reference pattern and the shifted pattern, causing the domain on Z
to be modified in both. I fixed the test in 27396fa by making a deep copy instead of a shallow copy. I preferred not to change the implementation of the global
method itself since we plan to deprecate it anyway, and I am not sure to what extent we plan to ensure robustness against aliasing.
@thierry-martinez Thanks! I apologize for missing that the error only occurs with the global method. I understand that it preserves the operator sum representation in all cases. This PR looks good to merge.
@thierry-martinez just looked through again and this looks ready to go. please squash and merge!
Thank you, @EarlMilktea . Are you ok for merging?
@thierry-martinez LGTM! Thank you for great work!
Merged! Thanks!
This PR proposes more direct implementations for
standardize
andshift_signals
. Here are some benchmarks, with random circuits: