Full API documentation

Below is listed the documentation for all the supported functions, classes and methods in PyZX. Some functionality of PyZX is still experimental or not well-tested (like the ZH-diagram interface and rewrite rules), so it is not listed here.

Graph API

ZX-graphs are internally represented by instances of classes that implement the methods of BaseGraph. These methods are listed below. The only complete implementation currently is GraphS.

class GraphS

Purely Pythonic implementation of BaseGraph.

To create a graph of a specific backend a convenience method Graph is supplied:

Graph(backend=None)

Returns an instance of an implementation of BaseGraph. By default GraphS is used. Currently backend is allowed to be simple (for the default), or ‘graph_tool’ and ‘igraph’. This method is the preferred way to instantiate a ZX-diagram in PyZX.

Return type

BaseGraph

Example

To construct an empty ZX-diagram, just write:

g = zx.Graph()

Below you can find full documentation of all the functions supplied by a Graph in PyZX.

class BaseGraph

Base class for letting graph backends interact with PyZX. For a backend to work with PyZX, there should be a class that implements all the methods of this class. For implementations of this class see GraphS or GraphIG.

add_edge(edge, edgetype=1)

Adds a single edge of the given type

Return type

None

add_edge_smart(e, edgetype)

Like add_edge, but does the right thing if there is an existing edge.

add_edge_table(etab)

Takes a dictionary mapping (source,target) –> (#edges, #h-edges) specifying that #edges regular edges must be added between source and target and $h-edges Hadamard edges. The method selectively adds or removes edges to produce that ZX diagram which would result from adding (#edges, #h-edges), and then removing all parallel edges using Hopf/spider laws.

Return type

None

add_edges(edges, edgetype=1)

Adds a list of edges to the graph.

Return type

None

add_to_phase(vertex, phase)

Add the given phase to the phase value of the given vertex.

Return type

None

add_vertex(ty=0, qubit=-1, row=-1, phase=None, ground=False)

Add a single vertex to the graph and return its index. The optional parameters allow you to respectively set the type, qubit index, row index and phase of the vertex.

Return type

TypeVar(VT, bound= int)

add_vertices(amount)

Add the given amount of vertices, and return the indices of the new vertices added to the graph, namely: range(g.vindex() - amount, g.vindex())

Return type

List[TypeVar(VT, bound= int)]

adjoint()

Returns a new graph equal to the adjoint of this graph.

Return type

BaseGraph

apply_effect(effect)

Inserts an effect into the outputs of the graph. effect should be a string with every character representing an output effect for each qubit. The possible types of effects are one of ‘0’, ‘1’, ‘+’, ‘-’ for the respective kets. If ‘/’ is specified this output is skipped.

Return type

None

apply_state(state)

Inserts a state into the inputs of the graph. state should be a string with every character representing an input state for each qubit. The possible types of states are on of ‘0’, ‘1’, ‘+’, ‘-’ for the respective kets. If ‘/’ is specified this input is skipped.

Return type

None

auto_detect_io()

Adds every vertex that is of boundary-type to the list of inputs or outputs. Whether it is an input or output is determined by looking whether its neighbor is further to the right or further to the left of the input. Inputs and outputs are sorted by vertical position. Raises an exception if boundary vertex does not have a unique neighbor or if this neighbor is on the same horizontal position.

clone()

This method should return an identical copy of the graph, without any relabeling

Used in lookahead extraction.

Return type

BaseGraph

compose(other)

Inserts a graph after this one. The amount of qubits of the graphs must match. Also available by the operator graph1 + graph2

Return type

None

connected(v1, v2)

Returns whether vertices v1 and v2 share an edge.

Return type

bool

copy(adjoint=False, backend=None)

Create a copy of the graph. If adjoint is set, the adjoint of the graph will be returned (inputs and outputs flipped, phases reversed). When backend is set, a copy of the graph with the given backend is produced. By default the copy will have the same backend.

Parameters
  • adjoint (bool) – set to True to make the copy be the adjoint of the graph

  • backend (Optional[str]) – the backend of the output graph

Return type

BaseGraph

Returns

A copy of the graph

Note

The copy will have consecutive vertex indices, even if the original graph did not.

depth()

Returns the value of the highest row number given to a vertex. This is -1 when no rows have been set.

Return type

Union[float, int]

edge(s, t)

Returns the edge object with the given source/target.

Return type

TypeVar(ET)

edge_s(edge)

Returns the source of the given edge.

Return type

TypeVar(VT, bound= int)

edge_set()

Returns the edges of the graph as a Python set. Should be overloaded if the backend supplies a cheaper version than this.

Return type

Set[TypeVar(ET)]

edge_st(edge)

Returns a tuple of source/target of the given edge.

Return type

Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int)]

edge_t(edge)

Returns the target of the given edge.

Return type

TypeVar(VT, bound= int)

edge_type(e)

Returns the type of the given edge: EdgeType.SIMPLE if it is regular, EdgeType.HADAMARD if it is a Hadamard edge, 0 if the edge is not in the graph.

Return type

Literal[1, 2]

edges()

Iterator that returns all the edges. Output type depends on implementation in backend.

Return type

Sequence[TypeVar(ET)]

classmethod from_json(js)

Converts the given .qgraph json string into a Graph. Works with the output of to_json.

Return type

BaseGraph

classmethod from_tikz(tikz, warn_overlap=True, fuse_overlap=True, ignore_nonzx=False)

Converts a tikz diagram into a pyzx Graph. The tikz diagram is assumed to be one generated by Tikzit, and hence should have a nodelayer and a edgelayer..

Parameters
  • s – a string containing a well-defined Tikz diagram.

  • warn_overlap (bool) – If True raises a Warning if two vertices have the exact same position.

  • fuse_overlap (bool) – If True fuses two vertices that have the exact same position. Only has effect if fuse_overlap is False.

  • ignore_nonzx (bool) – If True suppresses most errors about unknown vertex/edge types and labels.

Return type

BaseGraph

Warning

Vertices that might look connected in the output of the tikz are not necessarily connected at the level of tikz itself, and won’t be treated as such in pyzx.

grounds()

Returns the set of vertices connected to a ground.

Return type

Set[TypeVar(VT, bound= int)]

incident_edges(vertex)

Returns all neighboring edges of the given vertex.

Return type

Sequence[TypeVar(ET)]

inputs()

Gets the inputs of the graph.

Return type

Tuple[TypeVar(VT, bound= int), ...]

is_ground(vertex)

Returns a boolean indicating if the vertex is connected to a ground.

Return type

bool

is_hybrid()

Returns whether this is a hybrid quantum-classical graph, i.e. a graph with ground generators.

Return type

bool

is_id()

Returns whether the graph is just a set of identity wires, i.e. a graph where all the vertices are either inputs or outputs, and they are connected to each other in a non-permuted manner.

Return type

bool

merge(other)

Merges this graph with the other graph in-place. Returns (list-of-vertices, list-of-edges) corresponding to the id’s of the vertices and edges of the other graph.

Return type

Tuple[List[TypeVar(VT, bound= int)], List[TypeVar(ET)]]

neighbors(vertex)

Returns all neighboring vertices of the given vertex.

Return type

Sequence[TypeVar(VT, bound= int)]

normalize()

Puts every node connecting to an input/output at the correct qubit index and row.

Return type

None

num_edges()

Returns the amount of edges in the graph

Return type

int

num_inputs()

Gets the number of inputs of the graph.

Return type

int

num_outputs()

Gets the number of outputs of the graph.

Return type

int

num_vertices()

Returns the amount of vertices in the graph.

Return type

int

outputs()

Gets the outputs of the graph.

Return type

Tuple[TypeVar(VT, bound= int), ...]

pack_circuit_rows()

Compresses the rows of the graph so that every index is used.

Return type

None

phase(vertex)

Returns the phase value of the given vertex.

Return type

Union[Fraction, int]

phases()

Returns a mapping of vertices to their phase values.

Return type

Mapping[TypeVar(VT, bound= int), Union[Fraction, int]]

qubit(vertex)

Returns the qubit index associated to the vertex. If no index has been set, returns -1.

Return type

Union[float, int]

qubit_count()

Returns the number of inputs of the graph

Return type

int

qubits()

Returns a mapping of vertices to their qubit index.

Return type

Mapping[TypeVar(VT, bound= int), Union[float, int]]

remove_edge(edge)

Removes the given edge from the graph.

Return type

None

remove_edges(edges)

Removes the list of edges from the graph.

Return type

None

remove_isolated_vertices()

Deletes all vertices and vertex pairs that are not connected to any other vertex.

Return type

None

remove_vertex(vertex)

Removes the given vertex from the graph.

Return type

None

remove_vertices(vertices)

Removes the list of vertices from the graph.

Return type

None

replace_subgraph(left_row, right_row, replace)

Deletes the subgraph of all nodes with rank strictly between left_row and right_row and replaces it with the graph replace. The amount of nodes on the left row should match the amount of inputs of the replacement graph and the same for the right row and the outputs. The graphs are glued together based on the qubit index of the vertices.

Return type

None

row(vertex)

Returns the row that the vertex is positioned at. If no row has been set, returns -1.

Return type

Union[float, int]

rows()

Returns a mapping of vertices to their row index.

Return type

Mapping[TypeVar(VT, bound= int), Union[float, int]]

set_edge_type(e, t)

Sets the type of the given edge.

Return type

None

set_ground(vertex, flag=True)

Connect or disconnect the vertex to a ground.

Return type

None

set_inputs(inputs)

Sets the inputs of the graph.

set_outputs(outputs)

Sets the outputs of the graph.

set_phase(vertex, phase)

Sets the phase of the vertex to the given value.

Return type

None

set_phase_master(m)

Points towards an instance of the class Simplifier. Used for phase teleportation.

Return type

None

set_position(vertex, q, r)

Set both the qubit index and row index of the vertex.

set_qubit(vertex, q)

Sets the qubit index associated to the vertex.

Return type

None

set_row(vertex, r)

Sets the row the vertex should be positioned at.

Return type

None

set_type(vertex, t)

Sets the type of the given vertex to t.

Return type

None

set_vdata(vertex, key, val)

Sets the vertex data associated to key to val.

Return type

None

stats()
Return type

str

Returns

Returns a string with some information regarding the degree distribution of the graph.

subgraph_from_vertices(verts)

Returns the subgraph consisting of the specified vertices.

Return type

BaseGraph

tensor(other)

Take the tensor product of two graphs. Places the second graph below the first one. Can also be called using the operator graph1 @ graph2

Return type

BaseGraph

to_graphml()

Returns a GraphML representation of the graph.

Return type

str

to_json(include_scalar=True)

Returns a json representation of the graph that follows the Quantomatic .qgraph format. Convert back into a graph using from_json.

Return type

str

to_matrix(preserve_scalar=True)

Returns a representation of the graph as a matrix using tensorfy

Return type

ndarray

to_tensor(preserve_scalar=True)

Returns a representation of the graph as a tensor using tensorfy

Return type

ndarray

to_tikz(draw_scalar=False)

Returns a Tikz representation of the graph.

Return type

str

type(vertex)

Returns the type of the given vertex: VertexType.BOUNDARY if it is a boundary, VertexType.Z if it is a Z node, VertexType.X if it is a X node, VertexType.H_BOX if it is an H-box.

Return type

Literal[0, 1, 2, 3]

types()

Returns a mapping of vertices to their types.

Return type

Mapping[TypeVar(VT, bound= int), Literal[0, 1, 2, 3]]

update_phase_index(old, new)

When a phase is moved from a vertex to another vertex, we need to tell the phase_teleportation algorithm that this has happened. This function does that. Used in some of the rules in simplify.

Return type

None

vdata(vertex, key, default=0)

Returns the data value of the given vertex associated to the key. If this key has no value associated with it, it returns the default value.

Return type

Any

vdata_keys(vertex)

Returns an iterable of the vertex data key names. Used e.g. in making a copy of the graph in a backend-independent way.

Return type

Sequence[str]

vertex_degree(vertex)

Returns the degree of the given vertex.

Return type

int

vertex_set()

Returns the vertices of the graph as a Python set. Should be overloaded if the backend supplies a cheaper version than this.

Return type

Set[TypeVar(VT, bound= int)]

vertices()

Iterator over all the vertices.

Return type

Sequence[TypeVar(VT, bound= int)]

vindex()

The index given to the next vertex added to the graph. It should always be equal to max(g.vertices()) + 1.

Return type

TypeVar(VT, bound= int)

Circuit API

class Circuit(qubit_amount, name='', bit_amount=None)

Class for representing quantum circuits.

This class is mostly just a wrapper for a list of gates with methods for converting between different representations of a quantum circuit.

The methods in this class that convert a specification of a circuit into an instance of this class, generally do not check whether the specification is well-defined. If a bad input is given, the behaviour is undefined.

add_circuit(circ, mask=None, bit_mask=None)

Adds the gate of another circuit to this one. If mask is not given, then they must have the same amount of qubits and they are mapped one-to-one. If mask is given then it must be a list specifying to which qubits the qubits in the given circuit correspond. Similarly, if bit_mask is not given, then they must have the same amount of bits.

Example:

c1 = Circuit(qubit_amount=4)
c2 = Circuit(qubit_amount=2)
c2.add_gate("CNOT",0,1)
c1.add_circuit(c2, mask=[0,3]) # Now c1 has a CNOT from the first to the last qubit

If the circuits have the same amount of qubits then it can also be called as an operator:

c1 = Circuit(2)
c2 = Circuit(2)
c1 += c2
Return type

None

add_gate(gate, *args, **kwargs)

Adds a gate to the circuit. gate can either be an instance of a Gate, or it can be the name of a gate, in which case additional arguments should be given.

Example:

circuit.add_gate("CNOT", 1, 4) # adds a CNOT gate with control 1 and target 4
circuit.add_gate("ZPhase", 2, phase=Fraction(3,4)) # Adds a ZPhase gate on qubit 2 with phase 3/4
Return type

None

add_gates(gates, qubit)

Adds a series of single qubit gates on the same qubit. gates should be a space-separated string of gatenames.

Example:

circuit.add_gates("S T H T H", 1)
Return type

None

static from_graph(g, split_phases=True)

Produces a Circuit containing the gates of the given ZX-graph. If the ZX-graph is not circuit-like then the behaviour of this function is undefined. split_phases governs whether nodes with phases should be split into Z,S, and T gates or if generic ZPhase/XPhase gates should be used.

Return type

Circuit

static from_qasm(s)

Produces a Circuit based on a QASM input string. It ignores all the non-unitary instructions like measurements in the file. It currently doesn’t support custom gates that have parameters.

Return type

Circuit

static from_qasm_file(fname)

Produces a Circuit based on a QASM description of a circuit. It ignores all the non-unitary instructions like measurements in the file. It currently doesn’t support custom gates that have parameters.

Return type

Circuit

static from_qc_file(fname)

Produces a Circuit based on a .qc description of a circuit. If a Toffoli gate with more than 2 controls is encountered, ancilla qubits are added. Currently up to 5 controls are supported.

Return type

Circuit

static from_qsim_file(fname)

Produces a Circuit based on a .qc description of a circuit. If a Toffoli gate with more than 2 controls is encountered, ancilla qubits are added. Currently up to 5 controls are supported.

Return type

Circuit

static from_quipper(s)

Produces a Circuit based on a Quipper ASCII description of a circuit. Currently measurement instructions are not supported and are discarded.

Return type

Circuit

static from_quipper_file(fname)

Produces a Circuit based on a Quipper ASCII description of a circuit. Currently measurement instructions are not supported and are discarded.

Return type

Circuit

static load(circuitfile)

Tries to detect the circuit description language from the filename and its contents, and then tries to load the file into a circuit.

Return type

Circuit

prepend_gate(gate, *args, **kwargs)

The same as add_gate, but adds the gate to the start of the circuit, not the end.

stats(depth=False)

Returns statistics on the amount of gates in the circuit, separated into different classes (such as amount of T-gates, two-qubit gates, Hadamard gates).

Return type

str

stats_dict(depth=False)

Returns a dictionary containing statistics on the amount of gates in the circuit, separated into different classes (such as amount of T-gates, two-qubit gates, Hadamard gates).

Return type

dict

tcount()

Returns the amount of T-gates necessary to implement this circuit.

Return type

int

tensor(other)

Takes the tensor product of two Circuits. Places the second one below the first. Can also be done as an operator: circuit1 @ circuit2.

Return type

Circuit

to_basic_gates()

Returns a new circuit with every gate expanded in terms of X/Z phases, Hadamards and the 2-qubit gates CNOT, CZ, CX.

Return type

Circuit

to_emoji()

Converts circuit into a representation that can be copy-pasted into the ZX-calculus Discord server.

Return type

str

to_graph(zh=False, compress_rows=True, backend=None)

Turns the circuit into a ZX-Graph. If compress_rows is set, it tries to put single qubit gates on different qubits, on the same row.

Return type

BaseGraph

to_matrix(preserve_scalar=True)

Returns a numpy matrix describing the circuit.

Return type

ndarray

to_qasm()

Produces a QASM description of the circuit.

Return type

str

to_qc()

Produces a .qc description of the circuit.

Return type

str

to_quipper()

Produces a Quipper ASCII description of the circuit.

Return type

str

to_tensor(preserve_scalar=True)

Returns a numpy tensor describing the circuit.

Return type

ndarray

twoqubitcount()

Returns the amount of 2-qubit gates necessary to implement this circuit.

Return type

int

verify_equality(other, up_to_swaps=False)

Composes the other circuit with the adjoint of this circuit, and tries to reduce it to the identity using simplify.full_reduce`. If successful returns True, if not returns None.

Note

A successful reduction to the identity is strong evidence that the two circuits are equal, if this function is not able to reduce the graph to the identity this does not prove anything.

Parameters
  • other (Circuit) – the circuit to compare equality to.

  • up_to_swaps (bool) – if set to True, only checks equality up to a permutation of the qubits.

Return type

bool

Generating Circuits

The following are some methods to generate (random) quantum circuits.

CNOT_HAD_PHASE_circuit(qubits, depth, p_had=0.2, p_t=0.2, clifford=False)

Construct a Circuit consisting of CNOT, HAD and phase gates. The default phase gate is the T gate, but if clifford=True, then this is replaced by the S gate.

Parameters
  • qubits (int) – number of qubits of the circuit

  • depth (int) – number of gates in the circuit

  • p_had (float) – probability that each gate is a Hadamard gate

  • p_t (float) – probability that each gate is a T gate (or if clifford is set, S gate)

  • clifford (bool) – when set to True, the phase gates are S gates instead of T gates.

Return type

Circuit

Returns

A random circuit consisting of Hadamards, CNOT gates and phase gates.

cliffordT(qubits, depth, p_t=None, p_s=None, p_hsh=None, p_cnot=None, backend=None)

Generates a circuit consisting of randomly placed Clifford+T gates. Optionally, take probabilities of adding T, S, HSH, and CNOT. If probabilities for only a subset of gates is given, any remaining probability will be uniformly distributed among the remaining gates.

Parameters
  • qubits (int) – Amount of qubits in circuit.

  • depth (int) – Depth of circuit.

  • p_t (Optional[float]) – Probability that each gate is a T-gate.

  • p_s (Optional[float]) – Probability that each gate is a S-gate.

  • p_hsh (Optional[float]) – Probability that each gate is a HSH-gate.

  • p_cnot (Optional[float]) – Probability that each gate is a CNOT-gate.

  • backend (Optional[str]) – When given, should be one of the possible Backends backends.

Return type

Instance of graph of the given backend.

cliffordTmeas(qubits, depth, p_t=None, p_s=None, p_hsh=None, p_cnot=None, p_meas=None, backend=None)

Generates a circuit consisting of randomly placed Clifford+T gates. Optionally, take probabilities of adding T, S, HSH, CNOT, and measurements. If probabilities for only a subset of gates is given, any remaining probability will be uniformly distributed among the remaining gates.

Parameters
  • qubits (int) – Amount of qubits in circuit.

  • depth (int) – Depth of circuit.

  • p_t (Optional[float]) – Probability that each gate is a T-gate.

  • p_s (Optional[float]) – Probability that each gate is a S-gate.

  • p_hsh (Optional[float]) – Probability that each gate is a HSH-gate.

  • p_cnot (Optional[float]) – Probability that each gate is a CNOT-gate.

  • p_meas (Optional[float]) – Probability that each gate is a measurement.

  • backend (Optional[str]) – When given, should be one of the possible Backends backends.

Return type

Instance of graph of the given backend.

cliffords(qubits, depth, no_hadamard=False, t_gates=False, backend=None)

Generates a circuit consisting of randomly placed Clifford gates. Uses a different approach to generating Clifford circuits then cliffordT.

Parameters
  • qubits (int) – Amount of qubits in circuit.

  • depth (int) – Depth of circuit.

  • no_hadamard (bool) – Whether hadamard edges are allowed to be placed.

  • backend (Optional[str]) – When given, should be one of the possible Backends backends.

Return type

Instance of graph of the given backend.

cnots(qubits, depth, backend=None)

Generates a circuit consisting of randomly placed CNOT gates.

Args: qubits: Amount of qubits in circuit depth: Depth of circuit backend: When given, should be one of the possible Backends backends.

Return type

BaseGraph

Returns

Instance of graph of the given backend

identity(qubits, depth=1, backend=None)

Generates a pyzx.graph.Graph representing an identity circuit.

Parameters
  • qubits (int) – number of qubits (i.e. parallel lines of the Graph)

  • depth (Union[float, int]) – at which row the output vertices should be placed

  • backend (Optional[str]) – the backend to use for the output graph

Return type

BaseGraph

phase_poly(n_qubits, n_phase_layers, cnots_per_layer)

Create a random phase polynomial circuit.

Parameters
  • n_qubits (int) – Number of qubits in the circuit.

  • n_phase_layers (int) – Number of layers of phase gates.

  • cnots_per_layer (int) – Number of CNOTs in each layer.

Return type

Circuit

Returns

A random phase polynomial circuit.

phase_poly_approximate(n_qubits, n_CNOTs, n_phases)

Create a random phase polynomial circuit with an exact number of CNOT gates.

Parameters
  • n_qubits (int) – Number of qubits in the circuit.

  • n_CNOTs (int) – Number of CNOTs in the circuit.

  • n_phases (int) – Target of phase gates in the circuit. The actual number of phase gates may be slightly different.

Return type

Circuit

Returns

A random phase polynomial circuit.

phase_poly_from_gadgets(n_qubits, n_gadgets)

Create a random phase polynomial circuit from a set of phase gadgets.

Parameters
  • n_qubits (int) – Number of qubits in the circuit.

  • n_gadgets (int) – Number of phase gadgets to generate.

Return type

Circuit

Returns

A random phase polynomial circuit.

Circuit extraction and matrices over Z2

There is basically a single function that is needed for the most general extraction of a circuit from a ZX-diagram:

extract_circuit(g, optimize_czs=True, optimize_cnots=2, up_to_perm=False, quiet=True)

Given a graph put into semi-normal form by full_reduce, it extracts its equivalent set of gates into an instance of Circuit. This function implements a more optimized version of the algorithm described in There and back again: A circuit extraction tale

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – The ZX-diagram graph to be extracted into a Circuit.

  • optimize_czs (bool) – Whether to try to optimize the CZ-subcircuits by exploiting overlap between the CZ gates

  • optimize_cnots (int) – (0,1,2,3) Level of CNOT optimization to apply.

  • up_to_perm (bool) – If true, returns a circuit that is equivalent to the given graph up to a permutation of the inputs.

  • quiet (bool) – Whether to print detailed output of the extraction process.

Return type

Circuit

This function uses some reasoning over matrices over the field Z2. This functionality is implemented in the following class.

class Mat2(data)

A matrix over Z2, with methods for multiplication, primitive row and column operations, Gaussian elimination, rank, and epi-mono factorisation.

col_add(c0, c1)

Add r0 to r1

Return type

None

col_swap(c0, c1)

Swap the columns c0 and c1

Return type

None

factor()

Produce a factorisation m = m0 * m1, where

m0.cols() = m1.rows() = m.rank()

Return type

Tuple[Mat2, Mat2]

gauss(full_reduce=False, x=None, y=None, blocksize=6, pivot_cols=[])

Compute the echelon form. Returns the number of non-zero rows in the result, i.e. the rank of the matrix.

The parameter ‘full_reduce’ determines whether to compute the full row-reduced form, useful e.g. for matrix inversion and CNOT circuit synthesis.

The parameter ‘blocksize’ gives the size of the blocks in a block matrix for performing Patel/Markov/Hayes optimization, see:

K. Patel, I. Markov, J. Hayes. Optimal Synthesis of Linear Reversible Circuits. QIC 2008

If blocksize is given as self.cols(), then this is equivalent to just eliminating duplicate rows before doing normal Gaussian elimination.

Contains two convenience parameters for saving the primitive row operations. Suppose the row-reduced form of m is computed as:

g * m = m’

Then, x –> g * x and y –> y * g^-1.

Note x and y need not be matrices. x can be any object that implements the method row_add(), and y any object that implements col_add().

Return type

int

inverse()

Returns the inverse of m is invertible and None otherwise.

Return type

Optional[Mat2]

nullspace(should_copy=True)

Returns a list of non-zero vectors that span the nullspace of the matrix. If the matrix has trivial kernel it returns the empty list.

Return type

List[List[Literal[0, 1]]]

permute_cols(p)

Permute the columns of the matrix according to the permutation p.

Return type

None

permute_rows(p)

Permute the rows of the matrix according to the permutation p.

Return type

None

rank()

Returns the rank of the matrix.

Return type

int

row_add(r0, r1)

Add r0 to r1

Return type

None

row_swap(r0, r1)

Swap the rows r0 and r1

Return type

None

solve(b)

Return a vector x such that M * x = b, or None if there is no solution.

Return type

Optional[Mat2]

to_cnots(optimize=False, use_log_blocksize=False)

Returns a list of CNOTs that implements the matrix as a reversible circuit of qubits.

Return type

List[CNOT]

List of simplifications

Below is listed the content of simplify.py.

This module contains the ZX-diagram simplification strategies of PyZX. Each strategy is based on applying some combination of the rewrite rules in the rules module. The main procedures of interest are clifford_simp for simple reductions, full_reduce for the full rewriting power of PyZX, and teleport_reduce to use the power of full_reduce while not changing the structure of the graph.

simp(g, name, match, rewrite, matchf=None, quiet=False, stats=None)

Helper method for constructing simplification strategies based on the rules present in rules. It uses the match function to find matches, and then rewrites g using rewrite. If matchf is supplied, only the vertices or edges for which matchf() returns True are considered for matches.

Example

simp(g, 'spider_simp', rules.match_spider_parallel, rules.spider)

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – The graph that needs to be simplified.

  • name (str) – The name to display if quiet is set to False.

  • match (Callable[..., List[TypeVar(MatchObject)]]) – One of the match_* functions of rules.

  • rewrite (Callable[[BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)], List[TypeVar(MatchObject)]], Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]]) – One of the rewrite functions of rules.

  • matchf (Union[Callable[[TypeVar(ET)], bool], Callable[[TypeVar(VT, bound= int)], bool], None]) – An optional filtering function on candidate vertices or edges, which is passed as the second argument to the match function.

  • quiet (bool) – Suppress output on numbers of matches found during simplification.

Return type

int

Returns

Number of iterations of rewrite that had to be applied before no more matches were found.

bialg_simp(g, quiet=False, stats=None)
Return type

int

clifford_simp(g, quiet=True, stats=None)

Keeps doing rounds of interior_clifford_simp and pivot_boundary_simp until they can’t be applied anymore.

Return type

int

full_reduce(g, quiet=True, stats=None)

The main simplification routine of PyZX. It uses a combination of clifford_simp and the gadgetization strategies pivot_gadget_simp and gadget_simp.

Return type

None

gadget_simp(g, quiet=False, stats=None)
Return type

int

id_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

lcomp_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

phase_free_simp(g, quiet=False, stats=None)

Performs the following set of simplifications on the graph: spider -> bialg

Return type

int

pivot_boundary_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

pivot_gadget_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

pivot_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

reduce_scalar(g, quiet=True, stats=None)

Modification of full_reduce that is tailered for scalar ZX-diagrams. It skips the boundary pivots, and it additionally does supplementarity_simp.

Return type

int

spider_simp(g, matchf=None, quiet=False, stats=None)
Return type

int

supplementarity_simp(g, quiet=False, stats=None)
Return type

int

tcount(g)

Returns the amount of nodes in g that have a non-Clifford phase.

Return type

int

teleport_reduce(g, quiet=True, stats=None)

This simplification procedure runs full_reduce in a way that does not change the graph structure of the resulting diagram. The only thing that is different in the output graph are the location and value of the phases.

Return type

BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]

to_gh(g, quiet=True)

Turns every red node into a green node by changing regular edges into hadamard edges

Return type

None

to_rg(g, select=None)

Turn green nodes into red nodes by color-changing vertices which satisfy the predicate select. By default, the predicate is set to greedily reducing the number of Hadamard-edges. :type g: BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)] :param g: A ZX-graph. :type select: Optional[Callable[[TypeVar(VT, bound= int)], bool]] :param select: A function taking in vertices and returning True or False.

Return type

None

List of rewrite rules

Below is listed the content of rules.py.

This module contains the implementation of all the rewrite rules on ZX-diagrams in PyZX.

Each rewrite rule consists of two methods: a matcher and a rewriter. The matcher finds as many non-overlapping places where the rewrite rule can be applied. The rewriter takes in a list of matches, and performs the necessary changes on the graph to implement the rewrite.

Each match function takes as input a Graph instance, and an optional “filter function” that tells the matcher to only consider the vertices or edges that the filter function accepts. It outputs a list of “match” objects. What these objects look like differs per rewrite rule.

The rewrite function takes as input a Graph instance and a list of match objects of the appropriate type. It outputs a 4-tuple (edges to add, vertices to remove, edges to remove, isolated vertices check). The first of these should be fed to add_edge_table, while the second and third should be fed to remove_vertices and remove_edges. The last parameter is a Boolean that when true means that the rewrite rule can introduce isolated vertices that should be removed by remove_isolated_vertices.

Dealing with this output is done using either apply_rule or pyzx.simplify.simp.

Warning

There is no guarantee that the matcher does not affect the graph, and currently some matchers do in fact change the graph. Similarly, the rewrite function also changes the graph other than through the output it generates (for instance by adding vertices or changes phases).

apply_copy(g, matches)
Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

apply_gadget_phasepoly(g, matches)

Uses the output of match_gadgets_phasepoly to apply a rewrite based on rule R_13 of the paper A Finite Presentation of CNOT-Dihedral Operators.

Return type

None

apply_rule(g, rewrite, m, check_isolated_vertices=True)
Return type

None

apply_supplementarity(g, matches)

Given the output of :func:match_supplementarity, removes non-Clifford spiders that act on the same set of targets trough supplementarity.

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

bialg(g, matches)

Performs a certain type of bialgebra rewrite given matchings supplied by match_bialg(_parallel).

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

lcomp(g, matches)

Performs a local complementation based rewrite rule on the given graph with the given matches returned from match_lcomp(_parallel). See “Graph Theoretic Simplification of Quantum Circuits using the ZX calculus” (arXiv:1902.03178) for more details on the rewrite

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

match_bialg(g)

Does the same as match_bialg_parallel but with num=1.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), List[TypeVar(VT, bound= int)], List[TypeVar(VT, bound= int)]]]

match_bialg_parallel(g, matchf=None, num=-1)

Finds noninteracting matchings of the bialgebra rule.

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

  • matchf (Optional[Callable[[TypeVar(ET)], bool]]) – An optional filtering function for candidate edge, should return True if a edge should considered as a match. Passing None will consider all edges.

  • num (int) – Maximal amount of matchings to find. If -1 (the default) tries to find as many as possible.

Return type

List of 4-tuples (v1, v2, neighbors_of_v1,neighbors_of_v2)

match_copy(g, vertexf=None)

Finds spiders with a 0 or pi phase that have a single neighbor, and copies them through. Assumes that all the spiders are green and maximally fused.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), Union[Fraction, int], Union[Fraction, int], List[TypeVar(VT, bound= int)]]]

match_gadgets_phasepoly(g)

Finds groups of phase-gadgets that act on the same set of 4 vertices in order to apply a rewrite based on rule R_13 of the paper A Finite Presentation of CNOT-Dihedral Operators.

Return type

List[Tuple[List[TypeVar(VT, bound= int)], Dict[FrozenSet[TypeVar(VT, bound= int)], Union[TypeVar(VT, bound= int), Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int)]]]]]

match_ids(g)

Finds a single identity node. See match_ids_parallel.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), TypeVar(VT, bound= int), Literal[1, 2]]]

match_ids_parallel(g, vertexf=None, num=-1)

Finds non-interacting identity vertices.

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

  • num (int) – Maximal amount of matchings to find. If -1 (the default) tries to find as many as possible.

  • vertexf (Optional[Callable[[TypeVar(VT, bound= int)], bool]]) – An optional filtering function for candidate vertices, should return True if a vertex should be considered as a match. Passing None will consider all vertices.

Return type

List of 4-tuples (identity_vertex, neighbor1, neighbor2, edge_type).

match_lcomp(g)

Same as match_lcomp_parallel, but with num=1

Return type

List[Tuple[TypeVar(VT, bound= int), List[TypeVar(VT, bound= int)]]]

match_lcomp_parallel(g, vertexf=None, num=-1, check_edge_types=True)

Finds noninteracting matchings of the local complementation rule.

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

  • num (int) – Maximal amount of matchings to find. If -1 (the default) tries to find as many as possible.

  • check_edge_types (bool) – Whether the method has to check if all the edges involved are of the correct type (Hadamard edges).

  • vertexf (Optional[Callable[[TypeVar(VT, bound= int)], bool]]) – An optional filtering function for candidate vertices, should return True if a vertex should be considered as a match. Passing None will consider all vertices.

Return type

List of 2-tuples (vertex, neighbors).

match_phase_gadgets(g)

Determines which phase gadgets act on the same vertices, so that they can be fused together.

Parameters

g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

Return type

List of 5-tuples (axel,leaf, total combined phase, other axels with same targets, other leafs).

match_pivot(g)

Does the same as match_pivot_parallel but with num=1.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), List[TypeVar(VT, bound= int)], List[TypeVar(VT, bound= int)]]]

match_pivot_boundary(g, matchf=None, num=-1)

Like match_pivot_parallel, but except for pairings of Pauli vertices, it looks for a pair of an interior Pauli vertex and a boundary non-Pauli vertex in order to gadgetize the non-Pauli vertex.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), List[TypeVar(VT, bound= int)], List[TypeVar(VT, bound= int)]]]

match_pivot_gadget(g, matchf=None, num=-1)

Like match_pivot_parallel, but except for pairings of Pauli vertices, it looks for a pair of an interior Pauli vertex and an interior non-Clifford vertex in order to gadgetize the non-Clifford vertex.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int), List[TypeVar(VT, bound= int)], List[TypeVar(VT, bound= int)]]]

match_pivot_parallel(g, matchf=None, num=-1, check_edge_types=True)

Finds non-interacting matchings of the pivot rule.

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

  • num (int) – Maximal amount of matchings to find. If -1 (the default) tries to find as many as possible.

  • check_edge_types (bool) – Whether the method has to check if all the edges involved are of the correct type (Hadamard edges).

  • matchf (Optional[Callable[[TypeVar(ET)], bool]]) – An optional filtering function for candidate edge, should return True if a edge should considered as a match. Passing None will consider all edges.

Return type

List of 4-tuples. See pivot for the details.

match_spider(g)

Does the same as match_spider_parallel but with num=1.

Return type

List[Tuple[TypeVar(VT, bound= int), TypeVar(VT, bound= int)]]

match_spider_parallel(g, matchf=None, num=-1)

Finds non-interacting matchings of the spider fusion rule.

Parameters
  • g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

  • matchf (Optional[Callable[[TypeVar(ET)], bool]]) – An optional filtering function for candidate edge, should return True if the edge should be considered for matchings. Passing None will consider all edges.

  • num (int) – Maximal amount of matchings to find. If -1 (the default) tries to find as many as possible.

Return type

List of 2-tuples (v1, v2)

match_supplementarity(g)

Finds pairs of non-Clifford spiders that are connected to exactly the same set of vertices.

Parameters

g (BaseGraph[TypeVar(VT, bound= int), TypeVar(ET)]) – An instance of a ZX-graph.

Return type

List of 4-tuples (vertex1, vertex2, type of supplementarity, neighbors).

merge_phase_gadgets(g, matches)

Given the output of :func:match_phase_gadgets, removes phase gadgets that act on the same set of targets.

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

pivot(g, matches)

Perform a pivoting rewrite, given a list of matches as returned by match_pivot(_parallel). A match is itself a list where:

m[0] : first vertex in pivot. m[1] : second vertex in pivot. m[2] : list of zero or one boundaries adjacent to m[0]. m[3] : list of zero or one boundaries adjacent to m[1].

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

remove_ids(g, matches)

Given the output of match_ids(_parallel), returns a list of edges to add, and vertices to remove.

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

spider(g, matches)

Performs spider fusion given a list of matchings from match_spider(_parallel)

Return type

Tuple[Dict[TypeVar(ET), List[int]], List[TypeVar(VT, bound= int)], List[TypeVar(ET)], bool]

unspider(g, m, qubit=-1, row=-1)

Undoes a single spider fusion, given a match m. A match is a list with 3 elements given by:

m[0] : a vertex to unspider
m[1] : the neighbors of the new node, which should be a subset of the
       neighbors of m[0]
m[2] : the phase of the new node. If omitted, the new node gets all of the phase of m[0]

Returns the index of the new node. Optional parameters qubit and row can be used to position the new node. If they are omitted, they are set as the same as the old node.

Return type

TypeVar(VT, bound= int)

List of optimization functions

Below is listed the content of optimize.py.

This module implements several optimization methods on Circuits. The function basic_optimization runs a set of back-and-forth gate commutation and cancellation routines. phase_block_optimize does phase polynomial optimization using the TODD algorithm, and full_optimize combines these two methods.

basic_optimization(circuit, do_swaps=True, quiet=True)

Optimizes the circuit using a strategy that involves delayed placement of gates so that more matches for gate cancellations are found. Specifically tries to minimize the number of Hadamard gates to improve the effectiveness of phase-polynomial optimization techniques.

Parameters
  • circuit (Circuit) – Circuit to be optimized.

  • do_swaps (bool) – When set uses some rules transforming CNOT gates into SWAP gates. Generally leads to better results, but messes up architecture-aware placement of 2-qubit gates.

  • quiet (bool) – Whether to print some progress indicators.

Return type

Circuit

full_optimize(circuit, quiet=True)

Optimizes the circuit using first some basic commutation and cancellation rules, and then a dedicated phase polynomial optimization strategy involving the TODD algorithm.

Parameters
  • circuit (Circuit) – Circuit to be optimized.

  • quiet (bool) – Whether to print some progress indicators.

Return type

Circuit

phase_block_optimize(circuit, pre_optimize=True, quiet=True)

Optimizes the given circuit, by cutting it into phase polynomial pieces, and using the TODD algorithm to optimize each of these phase polynomials. The phase-polynomial circuits are then resynthesized using the parity network algorithm.

Note

Only works with Clifford+T circuits. Will give wrong output when fed smaller rotation gates, or Toffoli-like gates. Depending on the number of qubits and T-gates this function can take a long time to run. It can be sped up somewhat by using the TOpt implementation of TODD. If this is installed, point towards it using zx.settings.topt_command, such as for instance zx.settings.topt_command = ['wsl', '../TOpt'] for running it in the Windows Subsystem for Linux.

Parameters
  • circuit (Circuit) – The circuit to be optimized.

  • pre_optimize (bool) – Whether to call basic_optimization first.

  • quiet (bool) – Whether to print some progress indicators. Helpful when execution time is long.

Return type

Circuit

List of routing functions

Below is listed the content of routing.py.

This module implements Architecture aware routing methods for Circuit s.

create_architecture(name, **kwargs)

Creates an architecture from a name.

Parameters
  • name (Union[str, Architecture]) – The name of the architecture, see pyzx.routing.architectures for the available constants.

  • kwargs – Additional arguments to pass to the architecture constructor.

Return type

Architecture

Returns

The architecture.

class Architecture(name, coupling_graph=None, coupling_matrix=None, backend=None, qubit_map=None, reduce_order=None, **kwargs)

Class that represents the architecture of the qubits to be taken into account when routing.

qubit2vertex(qubit)

Get the internal graph vertex index for a logical architecture qubit.

Return type

int

vertex2qubit(vertex)

Get the logical architecture qubit for an internal graph vertex index.

Return type

int

pre_calc_distances()

Pre-calculates the distances between all pairs of qubits in the architecture.

Return type

Dict[Literal['upper', 'full'], List[Dict[Tuple[int, int], Tuple[int, List[Tuple[int, int]]]]]]

Returns

The computed distances. distances[“upper”|”full”][until][(v1,v2)] contains the distance between v1 and v2, and the shortest path, where upper|full indicates whether to consider bidirectional edges or not (respectively), until indicates the number of qubits to consider, for “full” the distance is calculated only between qubits with index <= until), and for “upper” the distance is calculated only between qubits with index >= until)

pre_calc_non_cutting_vertices()
non_cutting_vertices(subgraph_vertices, pre_calc=False)

Find the non-cutting vertices for this subgraph

Return type

List[int]

get_neighboring_qubits(qubit)
Return type

Set[int]

get_neighboring_vertices(vertex)
Return type

Set[int]

to_quil_device()
visualize(filename=None)
floyd_warshall(subgraph_vertices, upper=True, rec_vertices=[])

Implementation of the Floyd-Warshall algorithm to calculate the all-pair distances in a given graph

Parameters
  • subgraph_vertices (List[int]) – Subset of vertices to consider

  • upper (bool) – Whether use bidirectional edges or only ordered edges (src, tgt) such that src > tgt, default True

  • rec_vertices (List[int]) – A subgraph for which edges are considered undirected, as if the upper flag was set

Return type

Dict[Tuple[int, int], Tuple[int, List[Tuple[int, int]]]]

Returns

A dict with for each pair of qubits in the graph, a tuple with their distance and the corresponding shortest path

shortest_path(start_qubit, end_qubit, qubits_to_use=None)
Return type

Optional[List[int]]

steiner_tree(start_qubit, qubits_to_use, upper=True)

Approximates the steiner tree given the architecture, a root qubit and the other qubits that should be present. This is done using the pre-calculated all-pairs shortest distance and Prim’s algorithm for creating a minimum spanning tree :type start_qubit: int :param start_qubit: The index of the root qubit to be used :type qubits_to_use: List[int] :param qubits_to_use: The indices of the other qubits that should be present in the steiner tree :rtype: Iterator[Optional[Tuple[int, int]]]

Parameters

upper (bool) – Whether to consider only the nodes the steiner tree is used for creating an upper triangular matrix or a full reduction.

Yields

First yields all edges from the tree top-to-bottom, finished with None, then yields all edges from the tree bottom-up, finished with None.

rec_steiner_tree(start_qubit, terminal_qubits, usable_qubits, rec_qubits, upper=True)
transpose()
arities()

Returns a list of tuples (i, arity) where i is the index of each node and arity is the number of neighbors, sorted by decreasing arity.

Return type

List[Tuple[int, int]]

class Parity(par, n_qubits=None)

A set of qubits XORed together.

parity: List[bool]
count()

Returns the number of qubits interacting in the parity.

Return type

int

n_qubits()

Returns the total number of qubits.

Return type

int

to_mat2_row()
Return type

List[Literal[0, 1]]

class CNOT_tracker(n_qubits, **kwargs)

A circuit-like object that keeps track of row and column operations applied during Gauss elimination via CNOT gates.

matrix: Mat2

The qubit parity matrix computed from the CNOT gates.

row_perm: ndarray

The row permutation of the qubit parity matrix.

col_perm: ndarray

The column permutation of the qubit parity matrix.

count_cnots()

Returns the number of CNOT gates in the tracker.

Return type

int

cnot_depth()

Returns the CNOT/CZ depth of the tracked circuit.

Return type

int

row_add(q0, q1)

Track a row addition operation on the matrix

add_gate(gate, *args, **kwargs)

Adds a gate to the circuit. gate can either be an instance of a Gate, or it can be the name of a gate, in which case additional arguments should be given.

Example:

circuit.add_gate("CNOT", 1, 4) # adds a CNOT gate with control 1 and target 4
circuit.add_gate("ZPhase", 2, phase=Fraction(3,4)) # Adds a ZPhase gate on qubit 2 with phase 3/4
col_add(q0, q1)

Track a column addition operation on the matrix

static get_metric_names()

Metric names for the CNOT tracker.

Return type

List[str]

gather_metrics()

Gather metrics for the CNOT tracker.

Return type

Dict[str, int]

prepend_gate(gate, *args, **kwargs)

Adds a gate to the circuit. gate can either be an instance of a Gate, or it can be the name of a gate, in which case additional arguments should be given.

Example:

circuit.add_gate("CNOT", 1, 4) # adds a CNOT gate with control 1 and target 4
circuit.add_gate("ZPhase", 2, phase=Fraction(3,4)) # Adds a ZPhase gate on qubit 2 with phase 3/4
to_qasm()

Produces a QASM description of the circuit.

Return type

str

static from_circuit(circuit)
Return type

CNOT_tracker

update_matrix()

Rebuilds the parity matrix from the gates in the circuit.

static from_qasm_file(fname)

Produces a Circuit based on a QASM description of a circuit. It ignores all the non-unitary instructions like measurements in the file. It currently doesn’t support custom gates that have parameters.

Return type

CNOT_tracker

class ElimMode(value)

Row elimination modes for the cnot mapper procedures

GAUSS_MODE = 'gauss'

Gaussian elimination, ignoring the architecture.

STEINER_MODE = 'steiner'

Steiner tree based Gaussian elimination, optimizing the number of SWAPs operations required to synthesize the CNOTs on the restricted architecture.

GENETIC_GAUSS_MODE = 'genetic_gauss'

Gauss elimination using a genetic algorithm to find the best row permutation.

GENETIC_STEINER_MODE = 'genetic_steiner'

Steiner Gauss elimination using a genetic algorithm to find the best row permutation.

PSO_GAUSS_MODE = 'pso_gauss'

Gauss elimination using Particle Swarm Optimization to find the best row permutation.

PSO_STEINER_MODE = 'pso_steiner'

Steiner Gauss elimination using Particle Swarm Optimization to find the best row permutation.

class CostMetric(value)

Metrics for the cost of the gates needed for a given permutation, used by the cnot mapper fitness functions.

COMBINED = 'combined'

Count both the number of CNOTs and the depth of the circuit

DEPTH = 'depth'

Count the number of CNOTs in the circuit

COUNT = 'count'

Count the depth of the circuit

class FitnessFunction(metric, matrix, mode, architecture, row=True, col=True, full_reduce=True, **kwargs)

A fitness function that calculates the cost of the gates needed for a given permutation.

gauss(mode, matrix, architecture=None, permutation=None, try_transpose=False, **kwargs)

Performs architecture-aware Gaussian Elimination on a matrix.

Parameters
  • mode (Optional[ElimMode]) – Type of Gaussian elimination to be used, see ElimMode.

  • matrix (Mat2) – Target matrix to be reduced.

  • architecture (Optional[Architecture]) – Device architecture to take into account.

  • permutation (Optional[List[int]]) – If given, reduce a permuted version of the matrix.

  • kwargs – Other arguments that can be given to the Mat2.gauss function or parameters for the genetic algorithm.

Return type

int

Returns

The rank of the matrix. matrix is transformed inplace.

permuted_gauss(matrix, mode=None, architecture=None, population_size=30, crossover_prob=0.8, mutate_prob=0.2, n_iterations=5, row=True, col=True, full_reduce=True, fitness_func=None, x=None, y=None, **kwargs)

Applies gaussian elimination to the given matrix, finding an optimal permutation of the matrix to reduce the number of CNOT gates.

Parameters
  • matrix (Mat2) – Mat2 matrix to do gaussian elimination over

  • mode (Optional[ElimMode]) – Elimination mode to use

  • architecture (Optional[Architecture]) – Architecture to take into account

  • population_size (int) – For the genetic algorithm

  • crossover_prob (float) – For the genetic algorithm

  • mutate_prob (float) – For the genetic algorithm

  • n_iterations (int) – For the genetic algorithm

  • row (bool) – If the rows should be permutedA

  • col (bool) – If the columns should be permuted

  • full_reduce (bool) – Whether to do full gaussian reduction

  • fitness_func (Optional[FitnessFunction]) – Optional fitness function to use

  • x – Optional tracker for the row operations

  • y – Optional tracker for the column operations

Return type

Tuple[List[int], Circuit, int]

Returns

Best permutation found, list of CNOTS corresponding to the elimination.

sequential_gauss(matrices, mode=None, architecture=None, fitness_func=None, input_perm=True, output_perm=True, swarm_size=15, n_steps=5, s_crossover=0.4, p_crossover=0.3, pso_mutation=0.2, full_reduce=True, **kwargs)

Applies architecture-aware Gaussian elimination to multiple matrices, sharing the optimization passes when using ParticleSwarmOptimization modes.

Parameters
  • matrix – List of matrices to do gaussian elimination over

  • mode (Optional[ElimMode]) – Elimination mode to use

  • architecture (Optional[Architecture]) – Architecture to take into account

  • fitness_func (Optional[FitnessFunction]) – Optional fitness function to use

  • input_perm (bool) – Allow input permutation

  • output_perm (bool) – Whether the location of the output qubits can be different for the input location. Qubit locations can be optimized with pso.

  • swarm_size (int) – Swarm size for the swarm optimization.

  • n_steps (int) – The number of iterations for the particle swarm optimization.

  • s_crossover (float) – The crossover percentage with the best particle in the swarm for the particle swarm optimizer. Must be between 0.0 and 1.0.

  • p_crossover (float) – The crossover percentage with the personal best of a particle for the particle swarm optimizer. Must be between 0.0 and 1.0.

  • pso_mutation (float) – The mutation percentage of a particle for the particle swarm optimizer. Must be between 0.0 and 1.0.

  • full_reduce (bool) – Fully reduce the matrices

Return type

Tuple[List[CNOT_tracker], List[List[int]], int]

Returns

List of CNOT trackers corresponding to the eliminations, list of final permutations for each matrix, and the cost of the eliminations.

steiner_gauss(matrix, architecture, full_reduce=False, x=None, y=None)

Performs Gaussian elimination that is constrained by the given architecture

Parameters
  • matrix (Mat2) – PyZX Mat2 matrix to be reduced

  • architecture (Architecture) – The Architecture object to conform to

  • full_reduce (bool) – Whether to fully reduce or only create an upper triangular form

  • x (Optional[CNOT_tracker]) – Optional CNOT_tracker object to track row operations

  • y (Optional[CNOT_tracker]) – Optional CNOT_tracker object to track column operations

Returns

Rank of the given matrix

rec_steiner_gauss(matrix, architecture, full_reduce=False, x=None, y=None, permutation=None, **kwargs)

Performs Gaussian elimination that is constrained bij the given architecture according to https://arxiv.org/pdf/1904.00633.pdf Only works on full rank, square matrices.

Parameters
  • matrix (Mat2) – PyZX Mat2 matrix to be reduced

  • architecture (Architecture) – The Architecture object to conform to

  • full_reduce (bool) – Whether to fully reduce or only create an upper triangular form

  • x (Optional[CNOT_tracker]) – Optional CNOT_tracker object to track row operations

  • y (Optional[CNOT_tracker]) – Optional CNOT_tracker object to track column operations

  • permutation (Optional[List[int]]) – Optional permutation of the qubits

class RoutingMethod(value)

Phase polynomial routing method to use in route_phase_poly.

MATROID = 'matroid'

Routing method based on matroid partitioning. Commonly slower than RoutingMethod.GRAY and RoutingMethod.MEIJER.

GRAY = 'GraySynth'

Routing method based on Gray synthesis (see arxiv.org/abs/1712.01859 ).

MEIJER = 'meijer'

Routing method by Meijer and Duncan (see arxiv.org/abs/2004.06052 ).

GRAY_MEIJER = 'GraySynth+Meijer'

Combination of RoutingMethod.GRAY and RoutingMethod.MEIJER, keeps the best result of both.

class RootHeuristic(value)

Heuristics for choosing the root of a Steiner tree during phase polynomial routing.

RANDOM = 'gauss'

Randomly choose a root.

EXHAUSTIVE = 'exhaustive'

Try all possible roots and choose the one with the lowest cost.

ARITY = 'arity'

Choose the root randomly between the nodes with highest arity.

RECURSIVE = 'recursive'

Use an already-chosen root in a recursive call.

to_function()
Return type

Callable[[Architecture, Mat2, List[int], List[int], int, int, Any], List[int]]

class SplitHeuristic(value)

Heuristics for choosing nodes to split a circuit during phase polynomial routing.

RANDOM = 'random'

Randomly pick a candidate.

ARITY = 'arity'

Split the circuit on the nodes with highest arity.

COUNT = 'count'

Split the circuit on all the candidate nodes.

to_function()
Return type

Callable[[Architecture, Mat2, List[int], List[int], Any], List[int]]

route_phase_poly(circuit, architecture, method=RoutingMethod.GRAY_MEIJER, mode=ElimMode.STEINER_MODE, root_heuristic=RootHeuristic.RECURSIVE, split_heuristic=SplitHeuristic.COUNT, **kwargs)

Compile a circuit to an architecture with restricted connectivity.

Parameters
  • circuit (Union[Circuit, PhasePoly]) – The circuit to compile.

  • architecture (Architecture) – The target architecture.

  • method (RoutingMethod) – The routing method to use.

  • mode (ElimMode) – The elimination mode to use during the CNOT mapping step.

  • split_heuristic (SplitHeuristic) – The heuristic to use for splitting the circuit into subcircuits.

  • root_heuristic (RootHeuristic) – The heuristic to use for finding the root of the circuit.

Return type

Circuit

Returns

The compiled circuit.

Functions for dealing with tensors

Below is listed the content of tensor.py.

This module provides methods for converting ZX-graphs into numpy tensors and using these tensors to test semantic equality of ZX-graphs. This module is not meant as an efficient quantum simulator. Due to the way the tensor is calculated it can only handle circuits of small size before running out of memory on a regular machine. Currently, it can reliably transform 9 qubit circuits into tensors. If the ZX-diagram is not circuit-like, but instead has nodes with high degree, it will run out of memory even sooner.

adjoint(t)

Returns the adjoint of the tensor as if it were representing a circuit:

t = tensorfy(circ)
tadj = tensorfy(circ.adjoint())
compare_tensors(adjoint(t),tadj) # This is True
Return type

ndarray

compare_tensors(t1, t2, preserve_scalar=False)

Returns true if t1 and t2 represent equal tensors. When preserve_scalar is False (the default), equality is checked up to nonzero rescaling.

Example: To check whether two ZX-graphs g1 and g2 are semantically the same you would do:

compare_tensors(g1,g2) # True if g1 and g2 represent the same linear map up to nonzero scalar
Return type

bool

compose_tensors(t1, t2)

Returns a tensor that is the result of composing the tensors together as if they were representing circuits:

t1 = tensorfy(circ1)
t2 = tensorfy(circ2)
circ1.compose(circ2)
t3 = tensorfy(circ1)
t4 = compose_tensors(t1,t2)
compare_tensors(t3,t4) # This is True
Return type

ndarray

find_scalar_correction(t1, t2)

Returns the complex number z such that t1 = z*t2. :rtype: complex

Warning

This function assumes that compare_tensors(t1,t2,preserve_scalar=False) is True, i.e. that t1 and t2 indeed are equal up to global scalar. If they aren’t, this function returns garbage.

is_unitary(g)

Returns whether the given ZX-graph is equal to a unitary (up to a number).

Return type

bool

tensor_to_matrix(t, inputs, outputs)

Takes a tensor generated by tensorfy and turns it into a matrix. The inputs and outputs arguments specify the final shape of the matrix: 2^(outputs) x 2^(inputs)

Return type

ndarray

tensorfy(g, preserve_scalar=True)

Takes in a Graph and outputs a multidimensional numpy array representing the linear map the ZX-diagram implements. Beware that quantum circuits take exponential memory to represent.

Return type

ndarray

Drawing

Below is listed the content of drawing.py.

arrange_scalar_diagram(g)
Return type

None

draw(g, labels=False, **kwargs)

Draws the given Circuit or Graph. Depending on the value of pyzx.settings.drawing_backend either uses matplotlib or d3 to draw.

Return type

Any

draw_d3(g, labels=False, scale=None, auto_hbox=None, show_scalar=False, vdata=[])
Return type

Any

draw_matplotlib(g, labels=False, figsize=(8, 2), h_edge_draw='blue', show_scalar=False, rows=None)
Return type

Any

graphs_to_gif(graphs, filename, frame_duration=0.5)

Given a list of graphs, outputs an animated gif showing them in sequence.

Parameters
  • graphs (List[BaseGraph]) – The list of Graph instances that should be made into a gif.

  • filename (str) – the full filename of the output gif.

  • frame_duration (float) – how long (in seconds) each frame should last.

Warning

This function requires imagio to be installed (pip install imageio).

matrix_to_latex(m)

Converts a matrix into latex code. Useful for pretty printing the matrix of a Circuit/Graph.

Return type

str

Example

# Run this in a Jupyter notebook from ipywidgets import Label c = zx.Circuit(3) display(Label(matrix_to_latex(c.to_matrix())))

print_matrix(m)

Returns a Label() Jupyter widget that displays a pretty latex representation of the given matrix. Instead of a matrix, can also give a Circuit or Graph.

Return type

Label

Tikz and Quantomatic functionality

Below is listed the content of tikz.py.

Supplies methods to convert ZX-graphs to tikz files. These tikz files are designed to be easily readable by the program Tikzit.

tikz_to_graph(s, warn_overlap=True, fuse_overlap=True, ignore_nonzx=False, backend=None)

Converts a tikz diagram into a pyzx Graph. The tikz diagram is assumed to be one generated by Tikzit, and hence should have a nodelayer and a edgelayer..

Parameters
  • s (str) – a string containing a well-defined Tikz diagram.

  • warn_overlap (bool) – If True raises a Warning if two vertices have the exact same position.

  • fuse_overlap (bool) – If True fuses two vertices that have the exact same position. Only has effect if fuse_overlap is False.

  • ignore_nonzx (bool) – If True suppresses most errors about unknown vertex/edge types and labels.

  • backend (Optional[str]) – Backend of the graph returned.

Return type

BaseGraph

Warning

Vertices that might look connected in the output of the tikz are not necessarily connected

at the level of tikz itself, and won’t be treated as such in pyzx.

tikzit(g, draw_scalar=False)

Opens Tikzit with the graph g opened as a tikz diagram. For this to work, zx.settings.tikzit_location must be pointed towards the Tikzit executable. Even though this function is intended to be used with Tikzit, zx.tikz.tikzit_location can point towards any executable that takes a tikz file as an input, such as a text processor.

Return type

None

to_tikz(g, draw_scalar=False)

Converts a ZX-graph g to a string representing a tikz diagram.

Return type

str

to_tikz_sequence(graphs, draw_scalar=False, maxwidth=10)

Given a list of ZX-graphs, outputs a single tikz diagram with the graphs presented in a grid. maxwidth is the maximum width of the diagram, before a graph is put on a new row in the tikz diagram.

Return type

str

Below is listed the content of quantomatic.py.

Implements methods for interacting with Quantomatic:

import pyzx as zx
zx.settings.quantomatic_location = "path/to/quantomatic/jar/file.jar"
g = zx.generate.cliffordT(3,10,0.2)
g2 = zx.quantomatic.edit_graph(g) # Opens Quantomatic with the graph g opened. Execution is blocked until Quantomatic is closed again.
# If you have saved the qgraph file in quantomatic, then g2 should now contain your changes.
edit_graph(g)

Opens Quantomatic with the graph g loaded. When you are done editing the graph, you save it in Quantomatic and close the executable. The resulting graph is returned by this function. Note that this function blocks until the Quantomatic executable is closed. For this function to work you must first set zx.settings.quantomatic_location to point towards the Quantomatic .jar file.

Return type

BaseGraph