graphix.pattern module

MBQC pattern according to Measurement Calculus.

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

class DrawPatternAnnotations(*values)[source]

Bases: Enum

Enumeration to indicate the possible annotations for Pattern.draw.

Flow = 1
XZCorrections = 2
class Pattern(input_nodes: Iterable[int] | None = None, cmds: Iterable[CommandType] | None = None, output_nodes: Iterable[int] | None = None)[source]

Bases: InplaceParameterizable, Simulable[Measurement]

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)

__init__(input_nodes: Iterable[int] | None = None, cmds: Iterable[CommandType] | 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[CommandType] | None) – Optional. List of initial commands.

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

add(cmd: CommandType) → None[source]

Add command to the end of the pattern.

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

Parameters:

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

extend(*cmds: CommandType | Iterable[CommandType]) → None[source]

Add sequences of commands.

Parameters:

cmds – sequences of commands

clear() → None[source]

Clear the sequence of pattern commands.

replace(cmds: list[CommandType], 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)

node_mapping(mapping: Mapping[Node, Node] | None = None, *, start: int = 0, avoids: Collection[Node] | None = None, preserves: Collection[Node] | None = None) → dict[Node, Node][source]

Compute an injective mapping of node indices.

The resulting mapping can be passed to reindex(). Fresh indices are allocated in increasing order, starting at start and skipping any values already used.

Parameters:
  • mapping (Mapping[Node, Node] | None, optional) – An initial (partial) mapping that will be extended. A ValueError is raised if the supplied mapping is not injective.

  • start (int, optional) – The starting index from which fresh indices are allocated.

  • avoids (Collection[Node] | None, optional) – Indices that must not be assigned to a node.

  • preserves (Collection[Node] | None, optional) – Nodes that should not appear in the mapping. Their index will not be changed by reindex().

Returns:

A dictionary that maps each node of self (except those listed in preserves) to a distinct integer index.

Return type:

dict[Node, Node]

Notes

The resulting dictionary is guaranteed to be an extension of mapping, i.e., all entries from mapping appear in the resulting dictionary. In particular, the constraints specified in avoids and preserves only affect nodes that are freshly generated by the function; they do not apply to the nodes already present in mapping.

reindex(mapping: Callable[[Node], Node] | Mapping[Node, Node] | None = None, *, copy: bool = False) → Pattern[source]

Return a pattern whose nodes have been re-indexed using f.

This method does not verify that f is injective. The semantic of the pattern is only preserved when f is injective. A non-injective mapping can even break the runnability of the resulting pattern.

Parameters:
  • mapping (Callable[[Node], Node] | Mapping[Node, Node] | None, optional) – A function or a mapping that translates the current node indices to new ones. Indices that are not present in the mapping are left unchanged. If f is omitted, a default mapping is computed by using node_mapping().

  • copy (bool, optional) – If True, the current pattern remains unchanged, and a new pattern is returned. The default is False, meaning that changes are performed in place.

Returns:

The re-indexed pattern. Equal to self if copy is False.

Return type:

Pattern

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.

property input_nodes: list[int]

List input nodes.

property output_nodes: list[int]

List all nodes that are either input_nodes or prepared with N commands and that have not been measured with an M command.

property n_node: int

Count of nodes that are either input_nodes or prepared with N commands.

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.

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(1)
>>> circuit.h(0)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_ascii()
'X(1,{0}) M(0,0) E(0,1) N(1)'
>>> pattern.to_ascii(left_to_right=True)
'N(1) E(0,1) M(0,0) X(1,{0})'
>>> from graphix.command import CommandKind
>>> pattern.to_ascii(target={CommandKind.M})
'M(0,0)'
>>> pattern.to_ascii(target={CommandKind.X, CommandKind.Z})
'X(1,{0})'
>>> circuit = Circuit(3)
>>> circuit.ccx(0, 1, 2)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_ascii(limit=5)
'X(24,{21}) Z(24,{20}) X(32,{31}) Z(32,{28})...(98 more commands)'
>>> pattern.to_ascii(limit=5, left_to_right=True)
'N(3) E(2,3) M(2,0) N(4)...(98 more commands)'
>>> pattern.to_ascii(limit=None)
'X(24,{21}) Z(24,{20}) X(32,{31}) Z(32,{28}) X(30,...E(4,1) [M(3,0)]{2} E(3,4) N(4) M(2,0) E(2,3) N(3)'
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(1)
>>> circuit.h(0)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_latex()
'\\(X_{1}^{0}\\,M_{0}^{0}\\,E_{0,1}\\,N_{1}\\)'
>>> pattern.to_latex(left_to_right=True)
'\\(N_{1}\\,E_{0,1}\\,M_{0}^{0}\\,X_{1}^{0}\\)'
>>> from graphix.command import CommandKind
>>> pattern.to_latex(target={CommandKind.M})
'\\(M_{0}^{0}\\)'
>>> pattern.to_latex(target={CommandKind.X, CommandKind.Z})
'\\(X_{1}^{0}\\)'
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(1)
>>> circuit.h(0)
>>> pattern = circuit.transpile().pattern
>>> pattern.to_unicode()
'X₁⁰ M₀(0) E₀₋₁ N₁'
>>> pattern.to_unicode(left_to_right=True)
'N₁ E₀₋₁ M₀(0) X₁⁰'
>>> from graphix.command import CommandKind
>>> pattern.to_unicode(target={CommandKind.M})
'M₀(0)'
>>> pattern.to_unicode(target={CommandKind.X, CommandKind.Z})
'X₁⁰'
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’).

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

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 in the measurement calculus paper.

Returns:

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

Return type:

dict[int, set[int]]

shift_signals_direct() → dict[int, set[int]][source]

Perform signal shifting procedure.

signals() → dict[int, set[int]][source]

Extract ‘t’ domain of measurement commands, turn them into signal ‘S’ commands and add to the command sequence.

This is used for shift_signals() method.

partial_order_layers() → tuple[frozenset[int], ...][source]

Extract the measurement order of the pattern in the form of layers.

This method standardizes the pattern, builds a directed acyclical graph (DAG) from measurement and correction domains, and then performs a topological sort.

Returns:

Measurement partial order between the pattern’s nodes in a layer form.

Return type:

tuple[frozenset[int], …]

Raises:

RunnabilityError – If the pattern is not runnable.

Notes

  • This function wraps optimization.StandardizedPattern.partial_order_layers(), and the returned object is described in the notes of this method.

to_causalflow() → 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

  • Applying the chain Pattern.to_causalflow().to_xzcorrections().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.

to_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.to_causalflow() apply here as well.

to_pauliflow() → PauliFlow[Measurement][source]

Extract the Pauli flow structure from the current measurement pattern.

This method does not call the flow-extraction routine on the underlying open graph, but reconstructs the Pauli flow from the pattern corrections instead (see graphix.flow.core.XZCorrections.to_pauliflow()). Contrary to to_causalflow() and to_gflow(), Pauli measurements are kept as axes rather than downcast to planar Bloch measurements, so that the Pauli-basis structure is preserved.

Returns:

The Pauli flow associated with the current pattern.

Return type:

PauliFlow[Measurement]

Raises:
  • FlowError – If the pattern is empty or if no Pauli flow is compatible with the pattern corrections.

  • 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.to_causalflow() apply here as well.

to_xzcorrections() → XZCorrections[Measurement][source]

Extract the XZ-corrections from the current measurement pattern.

Returns:

The XZ-corrections associated with the current pattern.

Return type:

XZCorrections[Measurement]

Raises:
  • XZCorrectionsError – If the extracted correction dictionaries are not well formed.

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

Notes

To ensure that applying the chain Pattern.to_xzcorrections().to_pattern() to a strongly deterministic pattern returns a new pattern implementing the same unitary transformation, XZ-corrections must be extracted from a standardized pattern. This requirement arises for the same reason that flow extraction also operates correctly on standardized patterns only. This equivalence holds as long as the original pattern contains no Clifford commands, since those are discarded during open-graph extraction. See docstring in optimization.StandardizedPattern.to_gflow() for additional information.

sort_measurement_commands(meas_order: list[int]) → list[M][source]

Convert measurement order to sequence of measurement commands.

Parameters:

meas_order (list of int) – optimal measurement order.

Returns:

meas_cmds – sorted measurement commands

Return type:

list of command

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]

max_degree() → int[source]

Get max degree of a pattern.

Returns:

max_degree – max degree of a pattern

Return type:

int

nodes() → set[int][source]

Return the set of nodes of the pattern.

isolated_nodes() → set[int][source]

Return the set of isolated nodes in the pattern.

Returns:

Set of the isolated nodes

Return type:

set[int]

to_opengraph() → OpenGraph[Measurement][source]

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

This method standardizes the pattern first to guarantee that Clifford commands are properly encoded in the resulting open graph. Specifically, Cliffords acting on measured nodes are absorbed into measurements, while Cliffords acting on output nodes are stored in OpenGraph.output_cliffords.

Return type:

OpenGraph[Measurement]

clifford_commands() → dict[int, Clifford][source]

Extract Clifford commands.

Returns:

vops

Return type:

dict

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

correction_commands() → list[X | Z][source]

Return the list of byproduct correction commands.

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(heuristics: Iterable[SpaceMinimizationHeuristic] | None = None, *, copy: bool = False) → Pattern[source]

Return a pattern that reduces the maximal space, i.e. the number of qubits simultaneously required to execute the pattern.

See graphix.space_minimization.minimize_space() for more information about the default heuristics.

To obtain a space-optimal pattern while preserving the measurement order, use minimize_space([]). This commutes the N and E commands so that the pattern is space-optimal among patterns with the same measurement order (see StandardizedPattern.to_space_optimal_pattern()).

Parameters:
  • heuristics (Iterable[SpaceMinimizationHeuristic] | None = None) – The heuristics to try in order. By default, DEFAULT_HEURISTICS is used.

  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

Returns:

The optimized pattern. Equal to self if copy is False.

Return type:

Pattern

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

space_list() → list[int][source]

Return the list of the number of nodes present in the graph (space) during each step of execution of the pattern (for N and M commands).

Returns:

N_list – time evolution of ‘space’ at each ‘N’ and ‘M’ commands of pattern.

Return type:

list

to_pattern() → Pattern[source]

Return self.

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

draw(*, annotations: DrawPatternAnnotations | None = DrawPatternAnnotations.Flow, flow_from_pattern: bool = True, stacklevel: int = 1, **options: Unpack[DrawKwargs]) → None[source]

Visualize the underlying graph of the pattern with annotations.

Parameters:
  • annotations (DrawPatternAnnotations | None, default=DrawPatternAnnotations.Flow) –

    Annotations to be shown.
    • DrawPatternAnnotations.Flow (default): show the pattern’s flow if it exists.

    • DrawPatternAnnotations.XZCorrections: show the pattern’s XZ-corrections.

    • None: show the underlying open graph only.

  • flow_from_pattern (bool, default=True) – If True, the command sequence of the pattern is used to derive a flow structure. If False, only the underlying open graph is used.

  • options (Unpack[DrawKwargs]) – Options controlling graph visualization. See VisualizationOptions.

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

Raises:

PatternError – If the underlying open graph does not have flow.

Notes

If flow_from_pattern==True but the pattern is not compatible with a causal flow, gflow, or Pauli flow, an attempt to extract the flow from the underlying open graph will be made while warning the user.

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).

replace_parameter(variable: Parameter, substitute: ExpressionOrSupportsFloat, *, copy: bool = False) → Pattern[source]

Substitute all occurrences of the given variable in measurement angles by the given value.

Parameters:
  • variable (Parameter) – The symbolic expression to be replaced within the measurement angles.

  • substitute (ExpressionOrSupportsFloat) – The value or symbolic expression to substitute in place of variable.

  • copy (bool, optional) – If True, the current object remains unchanged and a new object is returned. The default is False, meaning that changes are performed in place.

Returns:

The object with the updated measurement parameters. Equal to self if copy is False.

Return type:

Self

replace_parameters(assignment: Mapping[Parameter, ExpressionOrSupportsFloat], *, copy: bool = False) → Pattern[source]

Substitute all occurrences of the given keys in measurement angles by the given values in parallel.

Parameters:
  • assignment (Mapping[Parameter, ExpressionOrSupportsFloat]) – A dictionary-like mapping where keys are the Parameter objects to be replaced and values are the new expressions or numerical values.

  • copy (bool, optional) – If True, the current object remains unchanged and a new object is returned. The default is False, meaning that changes are performed in place.

Returns:

The object with the updated measurement parameters. Equal to self if copy is False.

Return type:

Self

copy() → Pattern[source]

Return a copy of the pattern.

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.

apply(f: Callable[[Measurement], Measurement], *, copy: bool = False) → Pattern[source]

Apply the function f to each measurement.

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

  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

Returns:

The resulting pattern. If copy is False, the result is self.

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.apply(lambda m: BlochMeasurement(m.angle + 1, m.plane))
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XZ(1.25))])
>>> pattern
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XZ(1.25))])
map(f: Callable[[Measurement], Measurement]) → Pattern[source]

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

Equivalent to self.apply(f, copy=True).

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))])
>>> pattern
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XZ(0.25))])
infer_pauli_measurements(*, rel_tol: float = 1e-09, abs_tol: float = 0.0, copy: bool = False) → Pattern[source]

Replace Bloch measurements close to a Pauli measurement 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.

  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

Returns:

A pattern in which Bloch measurements close to a Pauli measurement are replaced by Pauli measurements. If copy is False, the result is self.

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)])
blochify(*, copy: bool = False) → Pattern[source]

Represent all measurements as Bloch measurements.

Parameters:

copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

Returns:

A pattern in which all measurements are Bloch measurements. If copy is False, the result is self.

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.Y)])
>>> pattern.blochify()
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XY(0.5))])
>>> pattern
Pattern(input_nodes=[0], cmds=[M(0, Measurement.XY(0.5))])
to_bloch() → Pattern[source]

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

Equivalent to self.blochify(copy=True).

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))])
>>> pattern
Pattern(input_nodes=[0], cmds=[M(0, Measurement.Y)])
perform_pauli_pushing(*, leave_nodes: Set[int] | None = None, copy: bool = False, standardize: bool = False, stacklevel: int = 1) → Pattern[source]

Move Pauli measurements before the other measurements.

If you need to recover the cut between Pauli measurements and non-Pauli measurements or the shifted signal, you can use from_standardizedpattern() instead.

Parameters:
  • leave_nodes (AbstractSet[Node], optional) – Nodes that should not be moved. This constraint only applies to Pauli nodes and has no effect on non-Pauli nodes.

  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

  • standardize (bool, optional) – If True, the pattern is returned in standardized form. The default is False: the nodes are prepared on a need-by-need basis, minimizing space usage.

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

Returns:

The pattern in which Pauli measurements have been moved before the other measurements. If copy is False, the result is self.

Return type:

Pattern

Notes

This function relies on StandardizedPattern.perform_pauli_pushing().

remove_pauli_measurements(*, copy: bool = False, standardize: bool = False, stacklevel: int = 1) → Pattern[source]

Remove non-input Pauli measurements from the given pattern.

See remove_pauli_measurements() for more information.

Parameters:
  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

  • standardize (bool, optional) – If True, the pattern is returned in standardized form. The default is False: the nodes are prepared on a need-by-need basis, minimizing space usage.

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

Returns:

The pattern in which Pauli measurements have been moved before the other measurements. If copy is False, the result is self.

Return type:

Pattern

remove_local_clifford_commands(*, copy: bool = False) → Pattern[source]

Return an equivalent pattern where local Clifford commands have been replaced by MBQC commands.

See remove_local_clifford_commands() for more information.

Parameters:
  • copy (bool, optional) – If True, the current pattern remains unchanged and a new pattern is returned. The default is False, meaning that changes are performed in place.

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

Returns:

The pattern in which local Clifford commands have been replaced by MBQC commands. If copy is False, the result is self.

Return type:

Pattern

exception PatternError[source]

Bases: Exception

Exception subclass to handle pattern errors.

class RunnabilityErrorReason(*values)[source]

Bases: Enum

Describe the reason for a pattern not being runnable.

AlreadyActive = 1

A node is prepared whereas it has already been prepared or it is an input node.

AlreadyMeasured = 2

A node is measured for a second time.

NotYetActive = 3

A node is entangled, measured or corrected whereas it has not been prepared yet and it is not an input node.

NotYetMeasured = 4

A node appears in the domain of a measurement of a correction whereas it has not been measured yet.

DomainSelfLoop = 5

A node appears in the domain of its own measurement. This is a particular case of NotYetMeasured, introduced to make the error message clearer.

exception RunnabilityError(cmd: CommandType, node: int, reason: RunnabilityErrorReason)[source]

Bases: PatternError

Error raised by :method:`Pattern.check_runnability`.

cmd: CommandType
node: int
reason: RunnabilityErrorReason
__init__(cmd: CommandType, node: int, reason: RunnabilityErrorReason) → None
assert_permutation(original: list[int], user: list[int]) → None[source]

Check that the provided NumPy user guide node list is a permutation from original.

class ExtractedSignal(s_domain: set[int], t_domain: set[int], signal: set[int])[source]

Bases: object

Return data structure for extract_signal.

__init__(s_domain: set[int], t_domain: set[int], signal: set[int]) → None
s_domain: set[int]

New s_domain for the measure command.

t_domain: set[int]

New t_domain for the measure command.

signal: set[int]

Domain for the shift command.

extract_signal(plane: Plane, s_domain: set[int], t_domain: set[int]) → ExtractedSignal[source]

Extract signal from domains.

shift_outcomes(outcomes: Mapping[int, Literal[0, 1]], signal_dict: Mapping[int, Set[int]]) → dict[int, Literal[0, 1]][source]

Update outcomes with shifted signals.

Shifted signals (as returned by the method Pattern.shift_signals()) affect classical outputs (measurements) while leaving the quantum state invariant.

This method updates the given outcomes by swapping the measurements affected by signals. This can be used either to transform the results into measurements observed in the unshifted pattern, or vice versa.

Parameters:
  • outcomes (Mapping[int, Outcome]) – Classical outputs.

  • signal_dict (Mapping[int, AbstractSet[int]]) – For each node, the signal that has been shifted (as returned by Pattern.shift_signals()).

Returns:

shifted_outcomes – Classical outputs updated with shifted signals.

Return type:

dict[int, int]