Pattern Manipulation

graphix.pattern module

class graphix.pattern.Pattern(input_nodes: Iterable[int] | None = None, cmds: Iterable[N | M | E | C | X | Z | S | T] | None = None, output_nodes: Iterable[int] | None = None)[source]

MBQC pattern class.

Pattern holds a sequence of commands to operate the MBQC (Pattern.seq), and provide modification strategies to improve the structure and simulation efficiency of the pattern accoring to measurement calculus.

ref: V. Danos, E. Kashefi and P. Panangaden. J. ACM 54.2 8 (2007)

list(self)

list of commands.

each command is a list [type, nodes, attr] which will be applied in the order of list indices.
type: one of {‘N’, ‘M’, ‘E’, ‘X’, ‘Z’, ‘S’, ‘C’}
nodes: int for {‘N’, ‘M’, ‘X’, ‘Z’, ‘S’, ‘C’} commands, tuple (i, j) for {‘E’} command
attr for N: none
attr for M: meas_plane, angle, s_domain, t_domain
attr for X: signal_domain
attr for Z: signal_domain
attr for S: signal_domain
attr for C: clifford_index, as defined in graphix.clifford
n_node

total number of nodes in the resource state

Type:

int

__init__(input_nodes: Iterable[int] | None = None, cmds: Iterable[N | M | E | C | X | Z | S | T] | None = None, output_nodes: Iterable[int] | None = None) None[source]

Construct a pattern.

Parameters:
  • input_nodes (Iterable[int] | None) – Optional. List of input qubits.

  • cmds (Iterable[Command] | None) – Optional. List of initial commands.

  • output_nodes (Iterable[int] | None) – Optional. List of output qubits.

add(cmd: N | M | E | C | X | Z | S | T) None[source]

Add command to the end of the pattern.

An MBQC command is an instance of graphix.command.Command.

Parameters:

cmd (graphix.command.Command) – MBQC command.

extend(*cmds: N | M | E | C | X | Z | S | T | Iterable[N | M | E | C | X | Z | S | T]) None[source]

Add sequences of commands.

Parameters:

cmds – sequences of commands

clear() None[source]

Clear the sequence of pattern commands.

replace(cmds: list[N | M | E | C | X | Z | S | T], input_nodes: list[int] | None = None) None[source]

Replace pattern with a given sequence of pattern commands.

Parameters:
  • cmds – list of commands

  • input_nodes – optional, list of input qubits (by default, keep the same input nodes as before)

reorder_output_nodes(output_nodes: Iterable[int]) None[source]

Arrange the order of output_nodes.

Parameters:

output_nodes (iterable of int) – output nodes order determined by user. each index corresponds to that of logical qubits.

reorder_input_nodes(input_nodes: Iterable[int]) None[source]

Arrange the order of input_nodes.

Parameters:

input_nodes (iterable of int) – input nodes order determined by user. each index corresponds to that of logical qubits.

simulate_pattern(backend: StatevectorBackend | Literal['statevector'] = 'statevector', input_state: State | Statevec | Iterable[State] | Iterable[ExpressionOrSupportsComplex] | Iterable[Iterable[ExpressionOrSupportsComplex]] | None = graphix.states.PlanarState(Plane.XY, 0), rng: Generator | None = None, **kwargs: Any) Statevec[source]
simulate_pattern(backend: DensityMatrixBackend | Literal['densitymatrix'], input_state: State | DensityMatrix | Iterable[State] | Iterable[ExpressionOrSupportsComplex] | Iterable[Iterable[ExpressionOrSupportsComplex]] | None = graphix.states.PlanarState(Plane.XY, 0), rng: Generator | None = None, **kwargs: Any) DensityMatrix
simulate_pattern(backend: TensorNetworkBackend | Literal['tensornetwork', 'mps'], input_state: State | Iterable[State] | Iterable[ExpressionOrSupportsComplex] | Iterable[Iterable[ExpressionOrSupportsComplex]] | None = graphix.states.PlanarState(Plane.XY, 0), rng: Generator | None = None, **kwargs: Any) MBQCTensorNet
simulate_pattern(backend: Backend[_StateT_co], input_state: Data | None = graphix.states.PlanarState(Plane.XY, 0), rng: Generator | None = None, **kwargs: Any) _StateT_co

Simulate the execution of the pattern by using graphix.simulator.PatternSimulator.

Parameters:
  • backend (Backend or {‘statevector’, ‘densitymatrix’, ‘tensornetwork’}, optional) – The simulator backend to use: either an instantiated backend or the name of a built-in backend. Default: 'statevector'.

  • input_state (Data or None, optional) – the output quantum state, in a representation compatible with the selected backend. Default: the |+> state (BasicStates.PLUS). If None, no input nodes are added by the simulator; input nodes must have been prepared in the backend before running the simulation.

  • rng (Generator, optional) – Random-number generator for measurements. This generator is used only in case of random branch selection (see RandomBranchSelector).

  • stacklevel (int, optional) – Stack level to use for warnings. Defaults to 1, meaning that warnings are reported at this function’s call site.

  • kwargs (keyword args for specified backend.)

Returns:

compute_max_degree() int[source]

Get max degree of a pattern.

Returns:

max_degree – max degree of a pattern

Return type:

int

compose(other: Pattern, mapping: Mapping[int, int], preserve_mapping: bool = False) tuple[Pattern, dict[int, int]][source]

Compose two patterns by merging subsets of outputs from self and a subset of inputs of other, and relabeling the nodes of other that were not merged.

Parameters:
  • other (Pattern) – Pattern to be composed with self.

  • mapping (Mapping[int, int]) – Partial relabelling of the nodes in other, with keys and values denoting the old and new node labels, respectively.

  • preserve_mapping (bool) – Boolean flag controlling the ordering of the output nodes in the returned pattern.

Returns:

  • p (Pattern) – composed pattern

  • mapping_complete (dict[int, int]) – Complete relabelling of the nodes in other, with keys and values denoting the old and new node label, respectively.

Notes

Let’s denote \((I_j, O_j, V_j, S_j)\) the ordered set of inputs and outputs, the computational space and the sequence of commands of pattern \(P_j\), respectively, with \(j = 1\) for pattern self and \(j = 2\) for pattern other. Let’s denote \(P\) the resulting pattern with \((I, O, V, S)\). Let’s denote \(K, U\) the sets of keys and values of mapping, \(M_1 = O_1 \cap U\) the set of merged outputs, and \(M_2 = \{k \in I_2 \cap K | k \rightarrow v, v \in M_1 \}\) the set of merged inputs.

The pattern composition requires that

  • \(K \subseteq V_2\).

  • For a pair \((k, v) \in (K, U)\)
    • \(U \cap V_1 \setminus O_1 = \emptyset\). If \(v \in O_1\), then \(k \in I_2\), otherwise an error is raised.

    • \(v\) can always satisfy \(v \notin V_1\), thereby allowing a custom relabelling.

The returned pattern follows this convention:

  • Nodes of pattern other not specified in mapping (i.e., \(V_2 \cap K^c\)) are relabelled in ascending order.

  • The sequence of the resulting pattern is \(S = S_2 S_1\), where nodes in \(S_2\) are relabelled according to mapping.

  • \(I = I_1 \cup (I_2 \setminus M_2)\).

  • \(O = (O_1 \setminus M_1) \cup O_2\).

  • Input (and, respectively, output) nodes in the returned pattern have the order of the pattern self followed by those of the pattern other. Merged nodes are removed.

  • If preserve_mapping = True and \(|M_1| = |I_2| = |O_2|\), then the outputs of the returned pattern are the outputs of pattern self, where the nth merged output is replaced by the output of pattern other corresponding to its nth input instead.

connected_nodes(node: int, prepared: set[int] | None = None) list[int][source]

Find nodes that are connected to a specified node.

These nodes must be in the statevector when the specified node is measured, to ensure correct computation. If connected nodes already exist in the statevector (prepared), then they will be ignored as they do not need to be prepared again.

Parameters:
  • node (int) – node index

  • prepared (list) – list of node indices, which are to be ignored

Returns:

node_list – list of nodes that are entangled with specified node

Return type:

list

remove_input_nodes() None[source]

Remove the input nodes from the pattern and replace them with N commands.

This removes the possibility of choosing the input state, fixing the input state to the plus state. .. seealso:: graphix.command.N

perform_pauli_measurements(ignore_pauli_with_deps: bool = False, *, stacklevel: int = 1) None[source]

Perform Pauli measurements in the pattern using efficient stabilizer simulator.

Parameters:
  • ignore_pauli_with_deps (bool) – Optional (False by default). If True, Pauli measurements with domains depending on other measures are preserved as-is in the pattern. If False, all Pauli measurements are preprocessed. Formally, measurements are swapped so that all Pauli measurements are applied first, and domains are updated accordingly.

  • stacklevel (int, optional) – Stack level to use for warnings. Defaults to 1, meaning that warnings are reported at this function’s call site.

  • seealso: (..) – measure_pauli():

to_ascii(left_to_right: bool = False, limit: int | None = 40, target: Container[command.CommandKind] | None = None) str[source]

Return the ASCII string representation of the pattern.

Parameters:
  • left_to_right (bool, optional) – If True, the first command will appear at the beginning of the resulting string. If False (the default), the first command will appear at the end of the string.

  • limit (int | None, optional) – If set to an int (default: 40), only first limit commands are printed, and an ellipsis is added at the end to indicate that some commands have been elided. If limit=None, there is no limit on the number of printed commands.

  • target (Container[command.CommandKind], optional) – If set, only commands of kinds specified in target are printed.

Examples

>>> from graphix import Circuit
>>> circuit = Circuit(3)
>>> circuit.ccx(0, 1, 2)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_ascii()
'Z(16,{11}) Z(18,{13}) Z(20,{7}) X(16,{15}) X(18,{14}) X(20,{19}) {17}[M(19)]{7} {10}[M(15,-pi/4)]{11} {17,12}[M(14)]{13} {17,9}[M(11)]{10} {0,1,5,10,13}[M(7,-pi/4)]{17} {1}[M(13,-7pi/4)]{12} {8}[M(10,-7pi/4)]{9} {17}[M(12)]{1} {6}[M(9)]{8} {8,3}[M(1,-pi/4)] {5}[M(8,-pi/4)]{6} {17,4}[M(6)]{5} [M(17)]{0} {3}[M(5,-7pi/4)]{4} M(0) {2}[M(4)]{3} [M(3)]{2} M(2) E(19,20) E(15,16) E(14,18) E(11,15) E(7,19) E(7,14) E(7,11) E(13,14) E(10,11) E(12,13) E(12,7) E(9,10) E(1,12) E(1,9) E(8,9)...(27 more commands)'
>>> pattern.to_ascii(left_to_right=True)
'N(3) N(4) N(5) N(6) N(7) N(8) N(9) N(10) N(11) N(12) N(13) N(14) N(15) N(16) N(17) N(18) N(19) N(20) E(2,3) E(3,4) E(4,5) E(4,1) E(0,17) E(5,6) E(17,7) E(6,8) E(6,7) E(8,9) E(1,9) E(1,12) E(9,10) E(12,7) E(12,13) E(10,11) E(13,14) E(7,11) E(7,14) E(7,19) E(11,15)...(27 more commands)'
>>> pattern.to_ascii(limit=None)
'Z(16,{11}) Z(18,{13}) Z(20,{7}) X(16,{15}) X(18,{14}) X(20,{19}) {17}[M(19)]{7} {10}[M(15,-pi/4)]{11} {17,12}[M(14)]{13} {17,9}[M(11)]{10} {0,1,5,10,13}[M(7,-pi/4)]{17} {1}[M(13,-7pi/4)]{12} {8}[M(10,-7pi/4)]{9} {17}[M(12)]{1} {6}[M(9)]{8} {8,3}[M(1,-pi/4)] {5}[M(8,-pi/4)]{6} {17,4}[M(6)]{5} [M(17)]{0} {3}[M(5,-7pi/4)]{4} M(0) {2}[M(4)]{3} [M(3)]{2} M(2) E(19,20) E(15,16) E(14,18) E(11,15) E(7,19) E(7,14) E(7,11) E(13,14) E(10,11) E(12,13) E(12,7) E(9,10) E(1,12) E(1,9) E(8,9) E(6,7) E(6,8) E(17,7) E(5,6) E(0,17) E(4,1) E(4,5) E(3,4) E(2,3) N(20) N(19) N(18) N(17) N(16) N(15) N(14) N(13) N(12) N(11) N(10) N(9) N(8) N(7) N(6) N(5) N(4) N(3)'
>>> from graphix.command import CommandKind
>>> pattern.to_ascii(target={CommandKind.M})
'{17}[M(19)]{7} {10}[M(15,-pi/4)]{11} {17,12}[M(14)]{13} {17,9}[M(11)]{10} {0,1,5,10,13}[M(7,-pi/4)]{17} {1}[M(13,-7pi/4)]{12} {8}[M(10,-7pi/4)]{9} {17}[M(12)]{1} {6}[M(9)]{8} {8,3}[M(1,-pi/4)] {5}[M(8,-pi/4)]{6} {17,4}[M(6)]{5} [M(17)]{0} {3}[M(5,-7pi/4)]{4} M(0) {2}[M(4)]{3} [M(3)]{2} M(2)'
>>> pattern.to_ascii(target={CommandKind.X, CommandKind.Z})
'Z(16,{11}) Z(18,{13}) Z(20,{7}) X(16,{15}) X(18,{14}) X(20,{19})'
to_unicode(left_to_right: bool = False, limit: int | None = 40, target: Container[command.CommandKind] | None = None) str[source]

Return the Unicode string representation of the pattern.

Parameters:
  • left_to_right (bool, optional) – If True, the first command will appear at the beginning of the resulting string. If False (the default), the first command will appear at the end of the string.

  • limit (int | None, optional) – If set to an int (default: 40), only first limit commands are printed, and an ellipsis is added at the end to indicate that some commands have been elided. If limit=None, there is no limit on the number of printed commands.

  • target (Container[command.CommandKind], optional) – If set, only commands of kinds specified in target are printed.

Examples

>>> from graphix import Circuit
>>> circuit = Circuit(3)
>>> circuit.ccx(0, 1, 2)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_unicode()
'Z₁₆¹¹ Z₁₈¹³ Z₂₀⁷ X₁₆¹⁵ X₁₈¹⁴ X₂₀¹⁹ ₁₇[M₁₉]⁷ ₁₀[M₁₅(-π/4)]¹¹ ₁₇₊₁₂[M₁₄]¹³ ₁₇₊₉[M₁₁]¹⁰ ₀₊₁₊₅₊₁₀₊₁₃[M₇(-π/4)]¹⁷ ₁[M₁₃(-7π/4)]¹² ₈[M₁₀(-7π/4)]⁹ ₁₇[M₁₂]¹ ₆[M₉]⁸ ₈₊₃[M₁(-π/4)] ₅[M₈(-π/4)]⁶ ₁₇₊₄[M₆]⁵ [M₁₇]⁰ ₃[M₅(-7π/4)]⁴ M₀ ₂[M₄]³ [M₃]² M₂ E₁₉₋₂₀ E₁₅₋₁₆ E₁₄₋₁₈ E₁₁₋₁₅ E₇₋₁₉ E₇₋₁₄ E₇₋₁₁ E₁₃₋₁₄ E₁₀₋₁₁ E₁₂₋₁₃ E₁₂₋₇ E₉₋₁₀ E₁₋₁₂ E₁₋₉ E₈₋₉...(27 more commands)'
>>> pattern.to_unicode(left_to_right=True)
'N₃ N₄ N₅ N₆ N₇ N₈ N₉ N₁₀ N₁₁ N₁₂ N₁₃ N₁₄ N₁₅ N₁₆ N₁₇ N₁₈ N₁₉ N₂₀ E₂₋₃ E₃₋₄ E₄₋₅ E₄₋₁ E₀₋₁₇ E₅₋₆ E₁₇₋₇ E₆₋₈ E₆₋₇ E₈₋₉ E₁₋₉ E₁₋₁₂ E₉₋₁₀ E₁₂₋₇ E₁₂₋₁₃ E₁₀₋₁₁ E₁₃₋₁₄ E₇₋₁₁ E₇₋₁₄ E₇₋₁₉ E₁₁₋₁₅...(27 more commands)'
>>> pattern.to_unicode(target={CommandKind.M})
'₁₇[M₁₉]⁷ ₁₀[M₁₅(-π/4)]¹¹ ₁₇₊₁₂[M₁₄]¹³ ₁₇₊₉[M₁₁]¹⁰ ₀₊₁₊₅₊₁₀₊₁₃[M₇(-π/4)]¹⁷ ₁[M₁₃(-7π/4)]¹² ₈[M₁₀(-7π/4)]⁹ ₁₇[M₁₂]¹ ₆[M₉]⁸ ₈₊₃[M₁(-π/4)] ₅[M₈(-π/4)]⁶ ₁₇₊₄[M₆]⁵ [M₁₇]⁰ ₃[M₅(-7π/4)]⁴ M₀ ₂[M₄]³ [M₃]² M₂'
>>> pattern.to_unicode(target={CommandKind.X, CommandKind.Z})
'Z₁₆¹¹ Z₁₈¹³ Z₂₀⁷ X₁₆¹⁵ X₁₈¹⁴ X₂₀¹⁹'
to_latex(left_to_right: bool = False, limit: int | None = 40, target: Container[command.CommandKind] | None = None) str[source]

Return a string containing the LaTeX representation of the pattern.

Parameters:
  • left_to_right (bool, optional) – If True, the first command will appear at the beginning of the resulting string. If False (the default), the first command will appear at the end of the string.

  • limit (int | None, optional) – If set to an int (default: 40), only first limit commands are printed, and an ellipsis is added at the end to indicate that some commands have been elided. If limit=None, there is no limit on the number of printed commands.

  • target (Container[command.CommandKind], optional) – If set, only commands of kinds specified in target are printed.

Examples

>>> from graphix import Circuit
>>> circuit = Circuit(3)
>>> circuit.ccx(0, 1, 2)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_latex()
'\\(Z_{16}^{11}\\,Z_{18}^{13}\\,Z_{20}^{7}\\,X_{16}^{15}\\,X_{18}^{14}\\,X_{20}^{19}\\,{}_{17}[M_{19}]^{7}\\,{}_{10}[M_{15}^{-\\frac{\\pi}{4}}]^{11}\\,{}_{17,12}[M_{14}]^{13}\\,{}_{17,9}[M_{11}]^{10}\\,{}_{0,1,5,10,13}[M_{7}^{-\\frac{\\pi}{4}}]^{17}\\,{}_{1}[M_{13}^{-\\frac{7\\pi}{4}}]^{12}\\,{}_{8}[M_{10}^{-\\frac{7\\pi}{4}}]^{9}\\,{}_{17}[M_{12}]^{1}\\,{}_{6}[M_{9}]^{8}\\,{}_{8,3}[M_{1}^{-\\frac{\\pi}{4}}]\\,{}_{5}[M_{8}^{-\\frac{\\pi}{4}}]^{6}\\,{}_{17,4}[M_{6}]^{5}\\,[M_{17}]^{0}\\,{}_{3}[M_{5}^{-\\frac{7\\pi}{4}}]^{4}\\,M_{0}\\,{}_{2}[M_{4}]^{3}\\,[M_{3}]^{2}\\,M_{2}\\,E_{19,20}\\,E_{15,16}\\,E_{14,18}\\,E_{11,15}\\,E_{7,19}\\,E_{7,14}\\,E_{7,11}\\,E_{13,14}\\,E_{10,11}\\,E_{12,13}\\,E_{12,7}\\,E_{9,10}\\,E_{1,12}\\,E_{1,9}\\,E_{8,9}\\)...(27 more commands)'
>>> pattern.to_latex(left_to_right=True)
'\\(N_{3}\\,N_{4}\\,N_{5}\\,N_{6}\\,N_{7}\\,N_{8}\\,N_{9}\\,N_{10}\\,N_{11}\\,N_{12}\\,N_{13}\\,N_{14}\\,N_{15}\\,N_{16}\\,N_{17}\\,N_{18}\\,N_{19}\\,N_{20}\\,E_{2,3}\\,E_{3,4}\\,E_{4,5}\\,E_{4,1}\\,E_{0,17}\\,E_{5,6}\\,E_{17,7}\\,E_{6,8}\\,E_{6,7}\\,E_{8,9}\\,E_{1,9}\\,E_{1,12}\\,E_{9,10}\\,E_{12,7}\\,E_{12,13}\\,E_{10,11}\\,E_{13,14}\\,E_{7,11}\\,E_{7,14}\\,E_{7,19}\\,E_{11,15}\\)...(27 more commands)'
>>> pattern.to_latex(target={CommandKind.M})
'\\({}_{17}[M_{19}]^{7}\\,{}_{10}[M_{15}^{-\\frac{\\pi}{4}}]^{11}\\,{}_{17,12}[M_{14}]^{13}\\,{}_{17,9}[M_{11}]^{10}\\,{}_{0,1,5,10,13}[M_{7}^{-\\frac{\\pi}{4}}]^{17}\\,{}_{1}[M_{13}^{-\\frac{7\\pi}{4}}]^{12}\\,{}_{8}[M_{10}^{-\\frac{7\\pi}{4}}]^{9}\\,{}_{17}[M_{12}]^{1}\\,{}_{6}[M_{9}]^{8}\\,{}_{8,3}[M_{1}^{-\\frac{\\pi}{4}}]\\,{}_{5}[M_{8}^{-\\frac{\\pi}{4}}]^{6}\\,{}_{17,4}[M_{6}]^{5}\\,[M_{17}]^{0}\\,{}_{3}[M_{5}^{-\\frac{7\\pi}{4}}]^{4}\\,M_{0}\\,{}_{2}[M_{4}]^{3}\\,[M_{3}]^{2}\\,M_{2}\\)'
>>> pattern.to_latex(target={CommandKind.X, CommandKind.Z})
'\\(Z_{16}^{11}\\,Z_{18}^{13}\\,Z_{20}^{7}\\,X_{16}^{15}\\,X_{18}^{14}\\,X_{20}^{19}\\)'
standardize() None[source]

Execute standardization of the pattern.

‘standard’ pattern is one where commands are sorted in the order of ‘N’, ‘E’, ‘M’ and then byproduct commands (‘X’ and ‘Z’) and finally Clifford commands (‘C’).

shift_signals(method: str = 'direct') dict[int, set[int]][source]

Perform signal shifting procedure.

Extract the t-dependence of the measurement into ‘S’ commands and commute them to the end of the command sequence where it can be removed. This procedure simplifies the dependence structure of the pattern.

Ref for the original ‘mc’ method:
  1. Danos, E. Kashefi and P. Panangaden. J. ACM 54.2 8 (2007)

Parameters:

method (str, optional) – ‘direct’ shift_signals is executed on a conventional Pattern sequence. ‘mc’ shift_signals is done using the original algorithm on the measurement calculus paper.

Returns:

signal_dict – For each node, the signal that have been shifted.

Return type:

dict[int, set[int]]

is_standard(strict: bool = False) bool[source]

Determine whether the command sequence is standard.

Parameters:

strict (bool, optional) – If True, ensures that C commands are the last ones.

Returns:

is_standard – True if the pattern is standard

Return type:

bool

extract_graph() nx.Graph[int][source]

Return the graph state from the command sequence, extracted from N and E commands.

Returns:

graph_state

Return type:

nx.Graph[int]

extract_nodes() set[int][source]

Return the set of nodes of the pattern.

extract_causal_flow() CausalFlow[BlochMeasurement][source]

Extract the causal flow structure from the current measurement pattern.

This method does not call the flow-extraction routine on the underlying open graph, but constructs the flow from the pattern corrections instead.

Returns:

The causal flow associated with the current pattern.

Return type:

CausalFlow[Measurement]

Raises:
  • FlowError – If the pattern: - Contains measurements in forbidden planes (XZ or YZ), - Is empty, or - Induces a correction function and a partial order which fail the well-formedness checks for a valid causal flow.

  • ValueError – If N commands in the pattern do not represent a \(|+\rangle\) state or if the pattern corrections form closed loops.

Notes

  • See optimization.StandardizedPattern.extract_causal_flow() for additional information on why it is required to standardized the pattern to extract a causal flow.

  • Applying the chain Pattern.extract_causal_flow().to_corrections().to_pattern() to a strongly deterministic pattern returns a new pattern implementing the same unitary transformation. This equivalence holds as long as the original pattern contains no Clifford commands, since those are discarded during open-graph extraction.

  • This method requires that all the measurements in the pattern are represented as Bloch measurements (i.e., there are no PauliMeasurement`s). Use :meth:`to_bloch() to convert all Pauli measurements.

extract_gflow() GFlow[BlochMeasurement][source]

Extract the generalized flow (gflow) structure from the current measurement pattern.

This method does not call the flow-extraction routine on the underlying open graph, but constructs the gflow from the pattern corrections instead.

Returns:

The gflow associated with the current pattern.

Return type:

GFlow[Measurement]

Raises:
  • FlowError – If the pattern is empty or if the extracted structure does not satisfy the well-formedness conditions required for a valid gflow.

  • ValueError – If N commands in the pattern do not represent a \(|+\rangle\) state or if the pattern corrections form closed loops.

Notes

The notes provided in self.extract_causal_flow() apply here as well.

extract_opengraph() OpenGraph[Measurement][source]

Extract the underlying resource-state open graph from the pattern.

Return type:

OpenGraph[Measurement]

Raises:

ValueError – If N commands in the pattern do not represent a \(|+\rangle\) state.

Notes

This operation loses all the information on the Clifford commands.

extract_measurement_commands() dict[int, M][source]

Return a dictionary mapping nodes to measurement commands.

Returns:

meas_dict – measurement commands indexed by nodes

Return type:

dict[int, command.M]

parallelize_pattern() None[source]

Optimize the pattern to reduce the depth of the computation by gathering measurement commands that can be performed simultaneously.

This optimized pattern runs efficiently on GPUs and quantum hardwares with depth (e.g. coherence time) limitations.

minimize_space() None[source]

Optimize the pattern to minimize the max_space property of the pattern.

The optimized pattern has significantly reduced space requirement (memory space for classical simulation, and maximum simultaneously prepared qubits for quantum hardwares).

draw_graph(flow_from_pattern: bool = True, show_pauli_measurement: bool = True, show_local_clifford: bool = False, show_measurement_planes: bool = False, show_loop: bool = True, node_distance: tuple[float, float] = (1, 1), figsize: tuple[int, int] | None = None, filename: Path | None = None) None[source]

Visualize the underlying graph of the pattern with flow or gflow structure.

Parameters:
  • flow_from_pattern (bool) – If True, the command sequence of the pattern is used to derive flow or gflow structure. If False, only the underlying graph is used.

  • show_pauli_measurement (bool) – If True, the nodes with Pauli measurement angles are colored light blue.

  • show_local_clifford (bool) – If True, indexes of the local Clifford operator are displayed adjacent to the nodes.

  • show_measurement_planes (bool) – If True, measurement planes are displayed adjacent to the nodes.

  • show_loop (bool) – whether or not to show loops for graphs with gflow. defaulted to True.

  • node_distance (tuple) – Distance multiplication factor between nodes for x and y directions.

  • figsize (tuple) – Figure size of the plot.

  • filename (Path | None) – If not None, filename of the png file to save the plot. If None, the plot is not saved. Default in None.

max_space() int[source]

Compute the maximum number of nodes that must be present in the graph (graph space) during the execution of the pattern.

For statevector simulation, this is equivalent to the maximum memory needed for classical simulation.

Returns:

n_nodes – max number of nodes present in the graph during pattern execution.

Return type:

int

to_qasm3(filename: Path | str, input_state: dict[int, State] | State = graphix.states.PlanarState(Plane.XY, 0)) None[source]

Export measurement pattern to OpenQASM 3.0 file.

See graphix.qasm3_exporter.pattern_to_qasm3().

Parameters:
  • filename (Path | str) – File name to export to. Example: "filename.qasm".

  • input_state (dict[int, State] | State, default BasicStates.PLUS) – The initial state for each input node. Only |0⟩ or |+⟩ states are supported.

is_parameterized() bool[source]

Return True if there is at least one measurement angle that is not just an instance of SupportsFloat.

A parameterized pattern is a pattern where at least one measurement angle is an expression that is not a number, typically an instance of sympy.Expr (but we don’t force to choose sympy here).

subs(variable: Parameter, substitute: ExpressionOrSupportsFloat) Pattern[source]

Return a copy of the pattern where all occurrences of the given variable in measurement angles are substituted by the given value.

xreplace(assignment: Mapping[Parameter, ExpressionOrSupportsFloat]) Pattern[source]

Return a copy of the pattern where all occurrences of the given keys in measurement angles are substituted by the given values in parallel.

check_runnability() None[source]

Check whether the pattern is runnable.

Raises RunnabilityError exception if it is not.

Notes

The runnability check can only guarantee the runnability of MBQC+LC patterns. Patterns that make use of custom :class:BaseN and :class:BaseM commands can have additional runnability constraints that are not checked by this method. For instance, in the Veriphix implementation of VBQC, blind measurements have hidden domains that cannot be checked.

map(f: Callable[[Measurement], Measurement]) Pattern[source]

Return a pattern where the function f has been applied to each measurement.

Parameters:

f (Callable[[Measurement], Measurement]) – Function applied to each measurement.

Returns:

The resulting pattern.

Return type:

Pattern

Example

>>> from graphix import Pattern, command
>>> from graphix.measurements import BlochMeasurement, Measurement
>>> pattern = Pattern(input_nodes=[0], cmds=[command.M(0, Measurement.XZ(0.25))])
>>> pattern.map(lambda m: BlochMeasurement(m.angle + 1, m.plane))
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XZ(1.25))])
infer_pauli_measurements(rel_tol: float = 1e-09, abs_tol: float = 0.0) Pattern[source]

Return an equivalent pattern in which Bloch measurements close to a Pauli measurement are replaced by Pauli measurements.

Parameters:
  • rel_tol (float, optional) – Relative tolerance for comparing angles, passed to math.isclose(). Default is 1e-9.

  • abs_tol (float, optional) – Absolute tolerance for comparing angles, passed to math.isclose(). Default is 0.0.

Returns:

An equivalent pattern in which Bloch measurements close to a Pauli measurement are replaced by Pauli measurements.

Return type:

Pattern

Example

>>> from graphix import Pattern, command
>>> from graphix.measurements import BlochMeasurement, Measurement
>>> pattern = Pattern(input_nodes=[0], cmds=[command.M(0, Measurement.XY(0.5))])
>>> pattern.infer_pauli_measurements()
Pattern(input_nodes=[0], cmds=[M(0, Measurement.Y)])
to_bloch() Pattern[source]

Return an equivalent pattern in which all measurements are represented as Bloch measurements.

Example

>>> from graphix import Pattern, command
>>> from graphix.measurements import BlochMeasurement, Measurement
>>> pattern = Pattern(input_nodes=[0], cmds=[command.M(0, Measurement.Y)])
>>> pattern.to_bloch()
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XY(0.5))])
graphix.pattern.measure_pauli(pattern: Pattern, *, ignore_pauli_with_deps: bool = False, stacklevel: int = 1) Pattern[source]

Perform Pauli measurement of a pattern by fast graph state simulator.

Uses the decorated-graph method implemented in graphix.graphsim to perform the measurements in Pauli bases, and then sort remaining nodes back into pattern together with Clifford commands. Users are required to ensure there are no input nodes with graphix.pattern.Pattern.remove_input_nodes() before using this function.

TODO: non-XY plane measurements in original pattern

Parameters:
  • pattern (graphix.pattern.Pattern object)

  • ignore_pauli_with_deps (bool) – Optional (False by default). If True, Pauli measurements with domains depending on other measures are preserved as-is in the pattern. If False, all Pauli measurements are preprocessed. Formally, measurements are swapped so that all Pauli measurements are applied first, and domains are updated accordingly.

  • stacklevel (int, optional) – Stack level to use for warnings. Defaults to 1, meaning that warnings are reported at this function’s call site.

Returns:

new_pattern – pattern with Pauli measurement removed. only returned if copy argument is True.

Return type:

graphix.Pattern object