-
Notifications
You must be signed in to change notification settings - Fork 1
Implement Feedforward modules #40
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
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
d59e767
implement feedforward module
masa10-f 5189866
add odd_neighbors
masa10-f 263a496
fix mypy error
masa10-f c98cd14
implement focus_flow module
masa10-f dc1c81c
udpate docs
masa10-f a4967f4
make version branch
masa10-f 567ef35
fix type union error in py39
masa10-f e938fa3
fix name conflict
masa10-f 6bde21f
ignore private method use in test
masa10-f 358ccd4
add test of focus_flow
masa10-f 74c4a38
fix logic in check_causality
masa10-f 4177e48
add test of feedforward module
masa10-f 35918a7
remove docstrings
masa10-f 28981c6
make flow/gflow checker private
masa10-f 8d15fdc
privatize type aliases
masa10-f c07a7d7
omit private alias from doc
masa10-f 9156d33
simplify odd_neighbors
masa10-f 91aba84
update test of feedforward
masa10-f ffc93f8
add test of odd_neighbors
masa10-f e5a5954
ruff
masa10-f 5ea3719
remove type alias
masa10-f ebc2e95
resolve sphinx bug
masa10-f 70884a7
Merge branch 'master' into feedforward
masa10-f 042d0d8
update odd_neighbors
masa10-f File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| Feedforward | ||
| =========== | ||
|
|
||
| :mod:`graphix_zx.feedforward` module | ||
| ++++++++++++++++++++++++++++++++++++ | ||
|
|
||
| .. automodule:: graphix_zx.feedforward | ||
|
|
||
| Functions | ||
| --------- | ||
|
|
||
| .. autofunction:: graphix_zx.feedforward.dag_from_flow | ||
|
|
||
| .. autofunction:: graphix_zx.feedforward.check_causality |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| Focus Flow | ||
| ========== | ||
|
|
||
| :mod:`graphix_zx.focus_flow` module | ||
| +++++++++++++++++++++++++++++++++++ | ||
|
|
||
| .. automodule:: graphix_zx.focus_flow | ||
|
|
||
| Functions | ||
| --------- | ||
|
|
||
| .. autofunction:: graphix_zx.focus_flow.is_focused | ||
| .. autofunction:: graphix_zx.focus_flow.focus_gflow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,3 +9,5 @@ Module reference | |
| matrix | ||
| graphstate | ||
| random_objects | ||
| feedforward | ||
| focus_flow | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| """Feedforward correction functions. | ||
|
|
||
| This module provides: | ||
|
|
||
| - `dag_from_flow`: Construct a directed acyclic graph (DAG) from a flowlike object. | ||
| - `check_causality`: Check if the flowlike object is causal with respect to the graph state. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| from collections.abc import Iterable, Mapping | ||
| from collections.abc import Set as AbstractSet | ||
| from typing import Any | ||
|
|
||
| from graphix_zx.graphstate import BaseGraphState, odd_neighbors | ||
|
|
||
| if sys.version_info >= (3, 10): | ||
| from typing import TypeGuard | ||
| else: | ||
| from typing_extensions import TypeGuard | ||
|
|
||
|
|
||
| def _is_flow(flowlike: Mapping[int, Any]) -> TypeGuard[Mapping[int, int]]: | ||
| r"""Check if the flowlike object is a flow. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| flowlike : `collections.abc.Mapping`\[`int`, `typing.Any`\] | ||
| A flowlike object to check | ||
|
|
||
| Returns | ||
| ------- | ||
| `bool` | ||
| True if the flowlike object is a flow, False otherwise | ||
| """ | ||
| return all(isinstance(v, int) for v in flowlike.values()) | ||
|
|
||
|
|
||
| def _is_gflow(flowlike: Mapping[int, Any]) -> TypeGuard[Mapping[int, AbstractSet[int]]]: | ||
| r"""Check if the flowlike object is a GFlow. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| flowlike : `collections.abc.Mapping`\[`int`, `typing.Any`\] | ||
| A flowlike object to check | ||
|
|
||
| Returns | ||
| ------- | ||
| `bool` | ||
| True if the flowlike object is a GFlow, False otherwise | ||
| """ | ||
| return all(isinstance(v, AbstractSet) for v in flowlike.values()) | ||
|
|
||
|
|
||
| def dag_from_flow( | ||
| flowlike: Mapping[int, int] | Mapping[int, AbstractSet[int]], graph: BaseGraphState, *, check: bool = True | ||
| ) -> dict[int, set[int]]: | ||
| r"""Construct a directed acyclic graph (DAG) from a flowlike object. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| flowlike : `collections.abc.Mapping`\[`int`, `int`\] | `collections.abc.Mapping`\[`int`, `collections.abc.Set`\[`int`\]`\] | ||
| A flowlike object | ||
| graph : `BaseGraphState` | ||
| The graph state | ||
| check : `bool`, optional | ||
| Raise an error if a cycle is detected, by default True | ||
|
|
||
| Returns | ||
| ------- | ||
| `dict`\[`int`, `set`\[`int`\]\] | ||
| The directed acyclic graph | ||
|
|
||
| Raises | ||
| ------ | ||
| TypeError | ||
| If the flowlike object is not a Flow or GFlow | ||
| ValueError | ||
| If a cycle is detected in the graph | ||
| """ # noqa: E501 | ||
| dag = {} | ||
| outputs = graph.physical_nodes - set(flowlike) | ||
| for node in flowlike: | ||
| if _is_flow(flowlike): | ||
| target_nodes = {flowlike[node]} | graph.neighbors(node) - {node} | ||
| elif _is_gflow(flowlike): | ||
| target_nodes = set(flowlike[node] | odd_neighbors(flowlike[node], graph) - {node}) | ||
| else: | ||
| msg = "Invalid flowlike object" | ||
| raise TypeError(msg) | ||
| dag[node] = target_nodes | ||
| for output in outputs: | ||
| dag[output] = set() | ||
|
|
||
| if check and not _check_dag(dag): | ||
| msg = "Cycle detected in the graph" | ||
| raise ValueError(msg) | ||
|
|
||
| return dag | ||
|
|
||
|
|
||
| def _check_dag(dag: Mapping[int, Iterable[int]]) -> bool: | ||
| r"""Check if a directed acyclic graph (DAG) does not contain a cycle. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| dag : `collections.abc.Mapping`\[`int`, `collections.abc.Iterable`\[`int`\]\] | ||
| directed acyclic graph | ||
|
|
||
| Returns | ||
| ------- | ||
| `bool` | ||
| True if the graph is valid, False otherwise | ||
| """ | ||
| for node, children in dag.items(): | ||
| for child in children: | ||
| if node in dag[child]: | ||
| return False | ||
| return True | ||
|
|
||
|
|
||
| def check_causality(graph: BaseGraphState, flowlike: Mapping[int, int] | Mapping[int, AbstractSet[int]]) -> bool: | ||
| r"""Check if the flowlike object is causal with respect to the graph state. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| graph : `BaseGraphState` | ||
| The graph state | ||
| flowlike : `collections.abc.Mapping`\[`int`, `int`\] | `collections.abc.Mapping`\[`int`, `collections.abc.Set`\[`int`\]\] | ||
| The flowlike object | ||
|
|
||
| Returns | ||
| ------- | ||
| `bool` | ||
| True if the flowlike object is causal, False otherwise | ||
| """ # noqa: E501 | ||
| dag = dag_from_flow(flowlike, graph, check=False) | ||
| return _check_dag(dag) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| """Focus flow algorithm. | ||
|
|
||
| This module provides: | ||
|
|
||
| - `is_focused`: Check if a flowlike object is focused. | ||
| - `focus_gflow`: Focus a flowlike object. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from graphlib import TopologicalSorter | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| from graphix_zx.common import Plane | ||
| from graphix_zx.feedforward import _is_flow, _is_gflow, check_causality, dag_from_flow | ||
| from graphix_zx.graphstate import odd_neighbors | ||
|
|
||
| if TYPE_CHECKING: | ||
| from collections.abc import Iterable, Mapping, Sequence | ||
| from collections.abc import Set as AbstractSet | ||
|
|
||
| from graphix_zx.graphstate import BaseGraphState | ||
|
|
||
|
|
||
| def is_focused(flowlike: Mapping[int, int] | Mapping[int, AbstractSet[int]], graph: BaseGraphState) -> bool: | ||
| r"""Check if a flowlike object is focused. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| flowlike : `collections.abc.Mapping`\[`int`, `int`\] | `collections.abc.Mapping`\[`int`, `collections.abc.Set`\[`int`\]\]` | ||
| flowlike object | ||
| graph : `BaseGraphState` | ||
| graph state | ||
|
|
||
| Returns | ||
| ------- | ||
| `bool` | ||
| True if the flowlike object is focused, False otherwise | ||
|
|
||
| Raises | ||
| ------ | ||
| TypeError | ||
| If the flowlike object is not a Flow or GFlow | ||
| """ # noqa: E501 | ||
| meas_bases = graph.meas_bases | ||
| outputs = set(graph.output_node_indices) | ||
|
|
||
| focused = True | ||
| for node in set(flowlike) - outputs: | ||
| if _is_flow(flowlike): | ||
| for child in graph.neighbors(flowlike[node]) - outputs: | ||
| focused &= node == child | ||
| elif _is_gflow(flowlike): | ||
| for child in flowlike[node]: | ||
| if child in outputs: | ||
| continue | ||
| focused &= (meas_bases[child].plane == Plane.XY) or (node == child) | ||
|
|
||
| for child in odd_neighbors(flowlike[node], graph): | ||
| if child in outputs: | ||
| continue | ||
| focused &= (meas_bases[child].plane != Plane.XY) or (node == child) | ||
| else: | ||
| msg = "Invalid flowlike object" | ||
| raise TypeError(msg) | ||
|
|
||
| return focused | ||
|
|
||
|
|
||
| def focus_gflow( | ||
| flowlike: Mapping[int, int] | Mapping[int, AbstractSet[int]], graph: BaseGraphState | ||
| ) -> dict[int, set[int]]: | ||
| r"""Focus a flowlike object. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| flowlike : `collections.abc.Mapping`\[`int`, `int`\] | `collections.abc.Mapping`\[`int`, `collections.abc.Set`\[`int`\]\] | ||
| flowlike object | ||
| graph : `BaseGraphState` | ||
| graph state | ||
|
|
||
| Returns | ||
| ------- | ||
| `dict`\[`int`, `set`\[`int`\]\] | ||
| focused flowlike object | ||
|
|
||
| Raises | ||
| ------ | ||
| TypeError | ||
| If the flowlike object is not a Flow or GFlow | ||
| ValueError | ||
| if the flowlike object is not causal with respect to the graph state | ||
| """ # noqa: E501 | ||
| if _is_flow(flowlike): | ||
| flowlike = {key: {value} for key, value in flowlike.items()} | ||
| elif _is_gflow(flowlike): | ||
| flowlike = {key: set(value) for key, value in flowlike.items()} | ||
| else: | ||
| msg = "Invalid flowlike object" | ||
| raise TypeError(msg) | ||
| if not check_causality(graph, flowlike): | ||
| msg = "The flowlike object is not causal with respect to the graph state" | ||
| raise ValueError(msg) | ||
| outputs = graph.physical_nodes - set(flowlike) | ||
| dag = dag_from_flow(flowlike, graph) | ||
| topo_order = list(TopologicalSorter(dag).static_order()) | ||
|
|
||
| for output in outputs: | ||
| topo_order.remove(output) | ||
|
|
||
| for target in topo_order: | ||
| flowlike = _focus(target, flowlike, graph, topo_order) | ||
|
|
||
| return flowlike | ||
|
|
||
|
|
||
| def _focus( | ||
| target: int, gflow: dict[int, set[int]], graph: BaseGraphState, topo_order: Sequence[int] | ||
| ) -> dict[int, set[int]]: | ||
| r"""Subroutine of the focus_gflow function. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| target : `int` | ||
| target node to be focused | ||
| gflow : `dict`\[`int`, `set`\[`int`\]\] | ||
| gflow object | ||
| graph : `BaseGraphState` | ||
| graph state | ||
| topo_order : `collections.abc.Sequence`\[`int`\] | ||
| topological order of the graph state | ||
|
|
||
| Returns | ||
| ------- | ||
| `dict`\[`int`, `set`\[`int`\] | ||
| flowlike object after focusing the target node | ||
| """ | ||
| k = 0 | ||
| s_k = _find_unfocused_corrections(target, gflow, graph) | ||
| while s_k: | ||
| gflow = _update_gflow(target, gflow, s_k, topo_order) | ||
| s_k = _find_unfocused_corrections(target, gflow, graph) | ||
|
|
||
| k += 1 | ||
|
|
||
| return gflow | ||
|
|
||
|
|
||
| def _find_unfocused_corrections(target: int, gflow: dict[int, set[int]], graph: BaseGraphState) -> set[int]: | ||
| r"""Subroutine of the _focus function. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| target : `int` | ||
| target node | ||
| gflow : `dict`\[`int`, `set`\[`int`\] | ||
| flowlike object | ||
| graph : `BaseGraphState` | ||
| graph state | ||
|
|
||
| Returns | ||
| ------- | ||
| `set`\[`int`\] | ||
| set of unfocused corrections | ||
| """ | ||
| meas_bases = graph.meas_bases | ||
| non_outputs = set(gflow) - set(graph.output_node_indices) | ||
|
|
||
| s_xy_candidate = odd_neighbors(gflow[target], graph) & non_outputs - {target} | ||
| s_xz_candidate = gflow[target] & non_outputs - {target} | ||
| s_yz_candidate = gflow[target] & non_outputs - {target} | ||
|
|
||
| s_xy = {node for node in s_xy_candidate if meas_bases[node].plane == Plane.XY} | ||
| s_xz = {node for node in s_xz_candidate if meas_bases[node].plane == Plane.XZ} | ||
| s_yz = {node for node in s_yz_candidate if meas_bases[node].plane == Plane.YZ} | ||
|
|
||
| return s_xy | s_xz | s_yz | ||
|
|
||
|
|
||
| def _update_gflow( | ||
| target: int, gflow: dict[int, set[int]], s_k: Iterable[int], topo_order: Sequence[int] | ||
| ) -> dict[int, set[int]]: | ||
| r"""Subroutine of the _focus function. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| target : `int` | ||
| target node | ||
| gflow : `dict`\[`int`, `set`\[`int`\] | ||
| flowlike object | ||
| s_k : `Iterable`\[`int`\] | ||
| unfocused correction | ||
| topo_order : `collections.abc.Sequence`\[`int`\] | ||
| topological order of the graph state | ||
|
|
||
| Returns | ||
| ------- | ||
| `dict`\[`int`, `set`\[`int`\] | ||
| gflow object after updating the target node | ||
| """ | ||
| minimal_in_s_k = min(s_k, key=topo_order.index) | ||
| gflow[target] ^= gflow[minimal_in_s_k] | ||
|
|
||
| return gflow | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.