Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring to support multigraph backend #217

Merged
merged 27 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a0256e3
added multigraph flag
akissinger Jul 29, 2023
4691b03
started updated graph methods
akissinger Jul 29, 2023
79f2ff1
cleaning up base graph
akissinger Jul 30, 2023
4930738
...
akissinger Aug 2, 2023
b9dd291
...
akissinger Sep 5, 2023
dd67a01
Merge branch 'master' into multigraph
akissinger Nov 13, 2023
b311e97
updated add/remove logic and added _simple flag
akissinger Nov 13, 2023
518cffc
squashing type errors
akissinger Nov 13, 2023
079ceb5
...
akissinger Nov 13, 2023
59caacd
...
akissinger Nov 14, 2023
5a26ae4
...
akissinger Nov 15, 2023
3ac6e87
Merge branch 'master' into multigraph
akissinger Nov 15, 2023
de19d11
Merge branch 'master' into multigraph
akissinger May 3, 2024
311448a
squashing mypy errors
akissinger May 3, 2024
f7972f2
fixed some missing type annotations
akissinger May 3, 2024
1f3cd43
fixing some broken behaviour in graph_s
akissinger May 3, 2024
299a138
all tests passing again!
akissinger May 3, 2024
5c3dc99
more mypy
akissinger May 3, 2024
a317d0e
added convience method for unordered pairs, many more fixes
akissinger May 3, 2024
47633c0
it typechecks again
akissinger May 3, 2024
0e28c66
more tweaks to satisfy linter
akissinger May 3, 2024
ae6167e
added multigraph back to backends
akissinger May 3, 2024
ec79b98
improved add_edge logic
akissinger May 3, 2024
22cc3e4
Merge branch 'master' into multigraph
akissinger May 3, 2024
d251c57
Merge branch 'master' into multigraph
akissinger May 4, 2024
30810f0
working on bent edges for d3 drawer
akissinger May 5, 2024
5b7ea03
d3 drawing for parallel edges
akissinger May 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions pyzx/altextract.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ def ones_in_pos(m, pos):
break
m1 = m.copy()

for i in range(m.rows()):
m[perm[i],:] = m1[i,:]
if not perm is None:
for i in range(m.rows()):
m[perm[i],:] = m1[i,:]

# produce a parity matrix that extracts all of the extractable
# vertices in convenient places and ignores the rest
Expand Down Expand Up @@ -177,8 +178,8 @@ def alt_extract_circuit(
e = g.edge(v,b)
et = g.edge_type(e)
g.remove_edge(e)
g.add_edge(g.edge(v,w),2)
g.add_edge(g.edge(w,b),toggle_edge(et))
g.add_edge((v,w),2)
g.add_edge((w,b),toggle_edge(et))
d.remove(b)
d.append(w)
neighbor_set.update(d)
Expand Down Expand Up @@ -238,7 +239,7 @@ def alt_extract_circuit(
qubit_map[w] = qubit_map[v]
b = [o for o in g.neighbors(v) if o in outputs][0]
g.remove_vertex(v)
g.add_edge(g.edge(w,b))
g.add_edge((w,b))
frontier.remove(v)
frontier.append(w)
if not quiet: print("Vertices extracted:", len(good_verts))
Expand Down
12 changes: 6 additions & 6 deletions pyzx/basicrules.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ def strong_comp(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
q = 0.4*g.qubit(vn) + 0.6*g.qubit(v[i])
r = 0.4*g.row(vn) + 0.6*g.row(v[i])
newv = g.add_vertex(g.type(v[j]), qubit=q, row=r)
g.add_edge(g.edge(newv,vn), edgetype=g.edge_type(g.edge(v[i],vn)))
g.add_edge((newv,vn), edgetype=g.edge_type(g.edge(v[i],vn)))
g.set_phase(newv, g.phase(v[j]))
nhd[i].append(newv)

for n1 in nhd[0]:
for n2 in nhd[1]:
g.add_edge(g.edge(n1,n2))
g.add_edge((n1,n2))

g.scalar.add_power((len(nhd[0]) - 1) * (len(nhd[1]) - 1))
if g.phase(v1) == 1 and g.phase(v2) == 1:
Expand Down Expand Up @@ -162,8 +162,8 @@ def pi_commute_Z(g: BaseGraph[VT, ET], v: VT) -> bool:
c = g.add_vertex(VertexType.X,
qubit=0.5*(g.qubit(v) + g.qubit(w)),
row=0.5*(g.row(v) + g.row(w)))
g.add_edge(g.edge(v, c))
g.add_edge(g.edge(c, w), edgetype=et)
g.add_edge((v, c))
g.add_edge((c, w), edgetype=et)
return True

def check_pi_commute_X(g: BaseGraph[VT,ET], v: VT) -> bool:
Expand Down Expand Up @@ -214,7 +214,7 @@ def fuse(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
g.add_to_phase(v1, g.phase(v2))
for v3 in g.neighbors(v2):
if v3 != v1:
g.add_edge_smart(g.edge(v1,v3), edgetype=g.edge_type(g.edge(v2,v3)))
g.add_edge((v1,v3), edgetype=g.edge_type(g.edge(v2,v3)))
g.remove_vertex(v2)
return True

Expand Down Expand Up @@ -251,7 +251,7 @@ def remove_id(g: BaseGraph[VT,ET], v: VT) -> bool:
return False

v1, v2 = tuple(g.neighbors(v))
g.add_edge_smart(g.edge(v1,v2), edgetype=EdgeType.SIMPLE
g.add_edge((v1,v2), edgetype=EdgeType.SIMPLE
if g.edge_type(g.edge(v,v1)) == g.edge_type(g.edge(v,v2))
else EdgeType.HADAMARD)
g.remove_vertex(v)
Expand Down
2 changes: 1 addition & 1 deletion pyzx/circuit/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ def graph_add_node(self,
etype: EdgeType.Type=EdgeType.SIMPLE,
ground: bool = False) -> VT:
v = g.add_vertex(t, mapper.to_qubit(l), r, phase, ground)
g.add_edge(g.edge(mapper.prev_vertex(l), v), etype)
g.add_edge((mapper.prev_vertex(l), v), etype)
mapper.set_prev_vertex(l, v)
return v

Expand Down
19 changes: 16 additions & 3 deletions pyzx/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,22 @@ def draw_d3(
for key in vdata if g.vdata(v, key, None) is not None],
}
for v in g.vertices()]
links = [{'source': str(g.edge_s(e)),
'target': str(g.edge_t(e)),
't': g.edge_type(e) } for e in g.edges()]

# keep track of the number of parallel edges seen for a source/target pair
counts: Dict[Tuple[str,str], int] = dict()
links = []
for e in g.edges():
s = str(g.edge_s(e))
t = str(g.edge_t(e))
i = counts.get((s,t), 0)
links.append({'source': s,
'target': t,
't': g.edge_type(e),
'index': i })
counts[(s,t)] = i + 1
for link in links:
s,t = (str(link['source']), str(link['target']))
link['num_parallel'] = counts[(s,t)]
graphj = json.dumps({'nodes': nodes, 'links': links})

with open(os.path.join(settings.javascript_location, 'zx_viewer.inline.js'), 'r') as f:
Expand Down
52 changes: 26 additions & 26 deletions pyzx/editor_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
import json
from fractions import Fraction

from typing import Callable, Optional, List, Tuple
from typing import Callable, Optional, List, Dict, Tuple

from .utils import EdgeType, VertexType, FractionLike
from .utils import toggle_edge, vertex_is_zx, toggle_vertex
from .graph.base import BaseGraph, VT, ET
from .graph.base import BaseGraph, VT, ET, upair
from . import rules
from . import hrules

Expand All @@ -49,7 +49,7 @@ def match_Z_spiders(
return [v for v in candidates if types[v] == VertexType.Z]


def color_change(g: BaseGraph[VT,ET], matches: List[VT]) -> rules.RewriteOutputType[ET,VT]:
def color_change(g: BaseGraph[VT,ET], matches: List[VT]) -> rules.RewriteOutputType[VT,ET]:
for v in matches:
g.set_type(v, toggle_vertex(g.type(v)))
for e in g.incident_edges(v):
Expand Down Expand Up @@ -92,11 +92,11 @@ def pauli_matcher(

def pauli_push(g: BaseGraph[VT,ET],
matches: List[Tuple[VT,VT]]
) -> rules.RewriteOutputType[ET,VT]:
) -> rules.RewriteOutputType[VT,ET]:
"""Pushes a Pauli (i.e. a pi phase) through another spider."""
rem_verts = []
rem_edges = []
etab = {}
rem_verts: List[VT] = []
rem_edges: List[ET] = []
etab: Dict[Tuple[VT,VT], List[int]] = dict()
for w,v in matches: # w is a Pauli and v is the spider we are gonna push it through
if g.vertex_degree(w) == 2:
rem_verts.append(w)
Expand All @@ -105,7 +105,7 @@ def pauli_push(g: BaseGraph[VT,ET],
v2 = l[0]
et1 = g.edge_type(g.edge(v,w))
et2 = g.edge_type(g.edge(v2,w))
etab[g.edge(v,v2)] = [1,0] if et1 == et2 else [0,1]
etab[upair(v,v2)] = [1,0] if et1 == et2 else [0,1]
else:
g.set_phase(w,0)

Expand All @@ -126,17 +126,17 @@ def pauli_push(g: BaseGraph[VT,ET],
et = g.edge_type(e)
rem_edges.append(e)
w2 = g.add_vertex(t,q,r,p)
etab[g.edge(v,w2)] = [1,0]
etab[g.edge(n,w2)] = [1,0] if et == EdgeType.SIMPLE else [0,1]
etab[upair(v,w2)] = [1,0]
etab[upair(n,w2)] = [1,0] if et == EdgeType.SIMPLE else [0,1]
new_verts.append(w2)
if not vertex_is_zx(g.type(v)): # v is H_BOX
if len(new_verts) == 2:
etab[g.edge(new_verts[0],new_verts[1])] = [0,1]
etab[upair(new_verts[0],new_verts[1])] = [0,1]
else:
r = (g.row(v) + sum(g.row(n) for n in new_verts)) / (len(new_verts) + 1)
q = (g.qubit(v) + sum(g.qubit(n) for n in new_verts))/(len(new_verts)+1)
h = g.add_vertex(VertexType.H_BOX,q,r,Fraction(1))
for n in new_verts: etab[g.edge(h,n)] = [1,0]
for n in new_verts: etab[upair(h,n)] = [1,0]
return (etab, rem_verts, rem_edges, False)


Expand All @@ -160,7 +160,7 @@ def match_edge(

def euler_expansion(g: BaseGraph[VT,ET],
matches: List[ET]
) -> rules.RewriteOutputType[ET,VT]:
) -> rules.RewriteOutputType[VT,ET]:
"""Expands the given Hadamard-edges into pi/2 phases using its Euler decomposition."""
types = g.types()
phases = g.phases()
Expand All @@ -174,8 +174,8 @@ def euler_expansion(g: BaseGraph[VT,ET],
q = 0.5*(g.qubit(v1) + g.qubit(v2))
t = toggle_vertex(types[v1])
v = g.add_vertex(t,q,r)
etab[g.edge(v,v1)] = [1,0]
etab[g.edge(v,v2)] = [1,0]
etab[upair(v,v1)] = [1,0]
etab[upair(v,v2)] = [1,0]
if phases[v1] == Fraction(1,2) or phases[v2] == Fraction(1,2):
g.add_to_phase(v1,Fraction(3,2))
g.add_to_phase(v2,Fraction(3,2))
Expand All @@ -190,23 +190,23 @@ def euler_expansion(g: BaseGraph[VT,ET],
r = 0.25*g.row(v1) + 0.75*g.row(v2)
q = 0.25*g.qubit(v1) + 0.75*g.qubit(v2)
w1 = g.add_vertex(VertexType.Z,q,r,Fraction(1,2))
etab[g.edge(v2,w1)] = [1,0]
etab[upair(v2,w1)] = [1,0]
r = 0.5*g.row(v1) + 0.5*g.row(v2)
q = 0.5*g.qubit(v1) + 0.5*g.qubit(v2)
w2 = g.add_vertex(VertexType.X,q,r,Fraction(1,2))
etab[g.edge(w1,w2)] = [1,0]
etab[upair(w1,w2)] = [1,0]
r = 0.75*g.row(v1) + 0.25*g.row(v2)
q = 0.75*g.qubit(v1) + 0.25*g.qubit(v2)
w3 = g.add_vertex(VertexType.Z,q,r,Fraction(1,2))
etab[g.edge(w2,w3)] = [1,0]
etab[g.edge(w3,v1)] = [1,0]
etab[upair(w2,w3)] = [1,0]
etab[upair(w3,v1)] = [1,0]
g.scalar.add_phase(Fraction(7,4))

return (etab, [], rem_edges, False)

def add_Z_identity(g: BaseGraph[VT,ET],
matches: List[ET]
) -> rules.RewriteOutputType[ET,VT]:
) -> rules.RewriteOutputType[VT,ET]:
rem_edges = []
etab = {}
for e in matches:
Expand All @@ -216,8 +216,8 @@ def add_Z_identity(g: BaseGraph[VT,ET],
r = 0.5*(g.row(v1) + g.row(v2))
q = 0.5*(g.qubit(v1) + g.qubit(v2))
w = g.add_vertex(VertexType.Z, q,r, 0)
etab[g.edge(v1,w)] = [1,0] if et == EdgeType.SIMPLE else [0,1]
etab[g.edge(v2,w)] = [1,0]
etab[upair(v1,w)] = [1,0] if et == EdgeType.SIMPLE else [0,1]
etab[upair(v2,w)] = [1,0]
return (etab, [], rem_edges, False)

def match_bialgebra(g: BaseGraph[VT,ET],
Expand Down Expand Up @@ -253,7 +253,7 @@ def match_bialgebra(g: BaseGraph[VT,ET],

def bialgebra(g: BaseGraph[VT,ET],
matches: List[Tuple[VT,VT]]
) -> rules.RewriteOutputType[ET,VT]:
) -> rules.RewriteOutputType[VT,ET]:
rem_verts = []
etab = {}
for v,w in matches:
Expand All @@ -267,7 +267,7 @@ def bialgebra(g: BaseGraph[VT,ET],
r = 0.6*g.row(v) + 0.4*g.row(n)
q = 0.6*g.qubit(v) + 0.4*g.qubit(n)
v2 = g.add_vertex(t,q,r)
etab[g.edge(n,v2)] = [1,0] if g.edge_type(g.edge(n,v)) == EdgeType.SIMPLE else [0,1]
etab[upair(n,v2)] = [1,0] if g.edge_type(g.edge(n,v)) == EdgeType.SIMPLE else [0,1]
new_verts.append(v2)
if g.type(w) == VertexType.Z:
t = VertexType.X
Expand All @@ -280,9 +280,9 @@ def bialgebra(g: BaseGraph[VT,ET],
r = 0.6*g.row(w) + 0.4*g.row(n)
q = 0.6*g.qubit(w) + 0.4*g.qubit(n)
w2 = g.add_vertex(t,q,r)
etab[g.edge(n,w2)] = [1,0] if g.edge_type(g.edge(n,w)) == EdgeType.SIMPLE else [0,1]
etab[upair(n,w2)] = [1,0] if g.edge_type(g.edge(n,w)) == EdgeType.SIMPLE else [0,1]
for v2 in new_verts:
etab[g.edge(w2,v2)] = [1,0]
etab[upair(w2,v2)] = [1,0]
return (etab, rem_verts, [], False)


Expand Down
12 changes: 6 additions & 6 deletions pyzx/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def connectivity_from_biadj(
for i in range(len(right)):
for j in range(len(left)):
if m.data[i][j] and not g.connected(right[i],left[j]):
g.add_edge(g.edge(right[i],left[j]),edgetype)
g.add_edge((right[i],left[j]),edgetype)
elif not m.data[i][j] and g.connected(right[i],left[j]):
g.remove_edge(g.edge(right[i],left[j]))

Expand Down Expand Up @@ -477,7 +477,7 @@ def apply_cnots(g: BaseGraph[VT, ET], c: Circuit, frontier: List[VT], qubit_map:
qubit_map[w] = qubit_map[v]
b = [o for o in g.neighbors(v) if o in outputs][0]
g.remove_vertex(v)
g.add_edge(g.edge(w, b))
g.add_edge((w, b))
frontier.remove(v)
frontier.append(w)

Expand Down Expand Up @@ -563,8 +563,8 @@ def neighbors_of_frontier(g: BaseGraph[VT, ET], frontier: List[VT]) -> Set[VT]:
e = g.edge(v, b)
et = g.edge_type(e)
g.remove_edge(e)
g.add_edge(g.edge(v, w), EdgeType.HADAMARD)
g.add_edge(g.edge(w, b), toggle_edge(et))
g.add_edge((v, w), EdgeType.HADAMARD)
g.add_edge((w, b), toggle_edge(et))
d.remove(b)
d.append(w)
neighbor_set.update(d)
Expand All @@ -580,7 +580,7 @@ def remove_gadget(g: BaseGraph[VT, ET], frontier: List[VT], qubit_map: Dict[VT,
if w not in gadgets: continue
for v in g.neighbors(w):
if v in frontier:
apply_rule(g, pivot, [(w, v, [], [o for o in g.neighbors(v) if o in outputs])]) # type: ignore
apply_rule(g, pivot, [((w, v), ([], [o for o in g.neighbors(v) if o in outputs]))]) # type: ignore
frontier.remove(v)
del gadgets[w]
frontier.append(w)
Expand Down Expand Up @@ -745,7 +745,7 @@ def extract_simple(g: BaseGraph[VT, ET], up_to_perm: bool = True) -> Circuit:
XPhase(q, g.phase(v)))
circ.prepend_gate(gate)

g.add_edge(g.edge(w,o), edgetype=g.edge_type(g.edge(w,v)))
g.add_edge((w,o), edgetype=g.edge_type(g.edge(w,v)))
g.remove_vertex(v)

if progress: continue
Expand Down
2 changes: 1 addition & 1 deletion pyzx/gadget_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def lc_boundary(g: BaseGraph[VT, ET], q: int, c: Circuit):
for i in range(len(nhd)):
g.add_to_phase(nhd[i], Fraction(-1,2))
for j in range(i+1, len(nhd)):
g.add_edge_smart(g.edge(nhd[i],nhd[j]), EdgeType.HADAMARD)
g.add_edge(g.edge(nhd[i],nhd[j]), EdgeType.HADAMARD)
c.prepend_gate(XPhase(Fraction(1,2)))


Expand Down
Loading
Loading