Skip to content

Commit

Permalink
Merge pull request #261 from RazinShaikh/opposite-bialgebra
Browse files Browse the repository at this point in the history
Bialgebra in the opposite direction
  • Loading branch information
jvdwetering authored Aug 1, 2024
2 parents e8a0de5 + df8c9a2 commit a9a5a65
Showing 1 changed file with 90 additions and 4 deletions.
94 changes: 90 additions & 4 deletions pyzx/editor_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


import json
from collections import defaultdict
from fractions import Fraction

from typing import Callable, Optional, List, Dict, Tuple
Expand Down Expand Up @@ -251,7 +252,7 @@ def match_bialgebra(g: BaseGraph[VT,ET],
candidates.difference_update(g.incident_edges(n))
return m

def bialgebra(g: BaseGraph[VT,ET],
def bialgebra(g: BaseGraph[VT,ET],
matches: List[Tuple[VT,VT]]
) -> rules.RewriteOutputType[VT,ET]:
rem_verts = []
Expand Down Expand Up @@ -299,6 +300,86 @@ def bialgebra(g: BaseGraph[VT,ET],
g.scalar.add_power((g.vertex_degree(v1)-2)*(g.vertex_degree(v2)-2))
return (etab, rem_verts, [], False)

def match_bialgebra_op(g: BaseGraph[VT,ET],
vertexf: Optional[Callable[[VT], bool]] = None,
vertex_type: Optional[Tuple[VertexType, VertexType]] = None,
edge_type: Optional[EdgeType] = None
) -> Optional[Tuple[List[VT], List[VT]]]:
if vertexf is not None: candidates = set([v for v in g.vertices() if vertexf(v)])
else: candidates = g.vertex_set()
if vertex_type is not None:
vtype1, vtype2 = vertex_type
else:
vtype1, vtype2 = VertexType.Z, VertexType.X
if edge_type is None:
edge_type = EdgeType.SIMPLE
type1_vertices = [v for v in candidates if g.type(v) == vtype1]
type2_vertices = [v for v in candidates if g.type(v) == vtype2]
if len(type1_vertices) <= 1 or len(type2_vertices) <= 1:
return None
# the vertices must have one external edge
for v1 in type1_vertices:
if g.vertex_degree(v1) != len(type2_vertices) + 1:
return None
for v2 in type2_vertices:
if g.vertex_degree(v2) != len(type1_vertices) + 1:
return None
# if all type1 vertices are connected to all type2 vertices with a simple edge, then they are a match
for v1 in type1_vertices:
for v2 in type2_vertices:
edges = list(g.edges(v1, v2))
if not (len(edges) == 1 and g.edge_type(edges[0]) == edge_type):
return None
return type1_vertices, type2_vertices

def bialgebra_op(g: BaseGraph[VT,ET],
matches: Tuple[List[VT], List[VT]],
edge_type: Optional[EdgeType] = EdgeType.SIMPLE
) -> rules.RewriteOutputType[VT,ET]:
def get_neighbors_and_loops(type1_vertices: List[VT], type2_vertices: List[VT]) -> Tuple[List[Tuple[VT, EdgeType]], List[EdgeType]]:
neighbors: List[Tuple[VT, EdgeType]] = []
loops: List[EdgeType] = []
for v1 in type1_vertices:
for edge in g.incident_edges(v1):
edge_st = g.edge_st(edge)
neighbor = edge_st[0] if edge_st[0] != v1 else edge_st[1]
if neighbor in type2_vertices:
continue
elif neighbor in type1_vertices:
if v1 > neighbor:
loops.append(g.edge_type(edge))
else:
neighbors.append((neighbor, g.edge_type(edge)))
return neighbors, loops

def add_vertex_with_averages(vertices, g, vtype):
average_row = sum(g.row(v) for v in vertices) / len(vertices)
average_qubit = sum(g.qubit(v) for v in vertices) / len(vertices)
return g.add_vertex(vtype, average_qubit, average_row)

def update_etab(etab, new_vertex, neighbors, loops):
for n, et in neighbors + [(new_vertex, et) for et in loops]:
etab[upair(new_vertex, n)][0 if et == EdgeType.SIMPLE else 1] += 1

type1_vertices, type2_vertices = matches
neighbors1, loops1 = get_neighbors_and_loops(type1_vertices, type2_vertices)
neighbors2, loops2 = get_neighbors_and_loops(type2_vertices, type1_vertices)

new_vertex1 = add_vertex_with_averages(type1_vertices, g, g.type(type2_vertices[0]))
new_vertex2 = add_vertex_with_averages(type2_vertices, g, g.type(type1_vertices[0]))

etab: dict = defaultdict(lambda: [0, 0])
if edge_type == EdgeType.SIMPLE:
etab[upair(new_vertex1, new_vertex2)] = [1, 0]
else:
etab[upair(new_vertex1, new_vertex2)] = [0, 1]
update_etab(etab, new_vertex1, neighbors1, loops1)
update_etab(etab, new_vertex2, neighbors2, loops2)

g.scalar.add_power(-(len(neighbors1)-1)*(len(neighbors2)-1))

return (etab, type1_vertices + type2_vertices, [], False)


MATCHES_VERTICES = 1
MATCHES_EDGES = 2
Expand Down Expand Up @@ -364,11 +445,16 @@ def bialgebra(g: BaseGraph[VT,ET],
"matcher": pauli_matcher,
"rule": pauli_push,
"type": MATCHES_VERTICES},
"bialgebra": {"text": "bialgebra",
"bialgebra": {"text": "bialgebra",
"tooltip": "Applies the bialgebra rule to a connected pair of Z and X spiders",
"matcher": match_bialgebra,
"rule": bialgebra,
"matcher": match_bialgebra,
"rule": bialgebra,
"type": MATCHES_EDGES},
"bialgebra_op": {"text": "bialgebra (inverse)",
"tooltip": "Applies the bialgebra rule to a connected pair of Z and X spiders in the opposite direction",
"matcher": match_bialgebra_op,
"rule": bialgebra_op,
"type": MATCHES_VERTICES},
"euler": {"text": "decompose Hadamard",
"tooltip": "Expands a Hadamard-edge into its component spiders using its Euler decomposition",
"matcher": match_hadamard_edge,
Expand Down

0 comments on commit a9a5a65

Please sign in to comment.