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

W node support #128

Merged
merged 23 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
69471b7
add vertex and edge types for W node
RazinShaikh Aug 11, 2023
118c401
made jsonparser compatible with W node
RazinShaikh Aug 11, 2023
5d7f8a9
removed trailing whitespace
RazinShaikh Aug 12, 2023
b9d4632
implemented match_w_fusion and w_fusion rule
RazinShaikh Aug 12, 2023
1eec7ec
added fuse_w in editor_actions
RazinShaikh Aug 12, 2023
a93ce27
handling parallel edges for W node
RazinShaikh Aug 12, 2023
546d08b
allow self-loop for W node
RazinShaikh Aug 13, 2023
4719d59
Merge branch 'non-flexsymmetric' into master
RazinShaikh Aug 13, 2023
742aab5
Merge pull request #1 from RazinShaikh/master
RazinShaikh Aug 13, 2023
52501f5
W support for to and from tikz
RazinShaikh Aug 13, 2023
263c654
handled a missing case of self-loop
RazinShaikh Aug 13, 2023
d21bb88
Merge pull request #2 from RazinShaikh/non-flexsymmetric
RazinShaikh Aug 13, 2023
d5f2312
making mypy happy
RazinShaikh Aug 13, 2023
75ce985
matplotlib drawing for w node
RazinShaikh Aug 15, 2023
52d9f4d
W support for generate.spider()
RazinShaikh Aug 15, 2023
7299665
drawing W node with d3 backend
RazinShaikh Aug 15, 2023
62eaedb
w to tensor
RazinShaikh Aug 15, 2023
1938fce
minor bug fix
RazinShaikh Aug 17, 2023
3a6859d
ZXW demo notebook
RazinShaikh Aug 17, 2023
9c11e90
drawing orientation of the W node is left to right
RazinShaikh Aug 17, 2023
8760f9c
added an assert in get_w_partner
RazinShaikh Aug 17, 2023
cf8a2a5
added fuse_w in basicrules.py
RazinShaikh Aug 17, 2023
f3fde52
forgot to check cases in the previous commit
RazinShaikh Aug 18, 2023
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
1,095 changes: 1,095 additions & 0 deletions demos/ZXW_demo.ipynb

Large diffs are not rendered by default.

48 changes: 36 additions & 12 deletions pyzx/basicrules.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@

from typing import Tuple, List
from .graph.base import BaseGraph, VT, ET
from .utils import VertexType, EdgeType, is_pauli
from .rules import apply_rule, w_fusion
from .utils import VertexType, EdgeType, get_w_io, is_pauli, vertex_is_w

def color_change_diagram(g: BaseGraph[VT,ET]):
"""Color-change an entire diagram by applying Hadamards to the inputs and ouputs."""
Expand Down Expand Up @@ -95,8 +96,8 @@ def check_strong_comp(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
return True

def strong_comp(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
if not check_strong_comp(g, v1, v2): return False
if not check_strong_comp(g, v1, v2): return False

nhd: Tuple[List[VT],List[VT]] = ([],[])
v = (v1,v2)

Expand All @@ -121,7 +122,7 @@ def strong_comp(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:

g.remove_vertex(v1)
g.remove_vertex(v2)

return True

def check_copy_X(g: BaseGraph[VT,ET], v: VT) -> bool:
Expand All @@ -136,10 +137,10 @@ def check_copy_X(g: BaseGraph[VT,ET], v: VT) -> bool:
return True

def copy_X(g: BaseGraph[VT,ET], v: VT) -> bool:
if not check_copy_X(g, v): return False
if not check_copy_X(g, v): return False
nv = next(iter(g.neighbors(v)))
strong_comp(g, v, nv)

return True

def check_pi_commute_Z(g: BaseGraph[VT, ET], v: VT) -> bool:
Expand All @@ -163,7 +164,7 @@ def pi_commute_Z(g: BaseGraph[VT, ET], v: VT) -> bool:
g.add_edge(g.edge(v, c))
g.add_edge(g.edge(c, w), edgetype=et)
return True

def check_pi_commute_X(g: BaseGraph[VT,ET], v: VT) -> bool:
color_change_diagram(g)
b = check_pi_commute_Z(g, v)
Expand All @@ -189,24 +190,47 @@ def copy_Z(g: BaseGraph, v: VT) -> bool:
return b

def check_fuse(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
if check_fuse_w(g, v1, v2):
return True
if not (g.connected(v1,v2) and
((g.type(v1) == VertexType.Z and g.type(v2) == VertexType.Z) or
(g.type(v1) == VertexType.X and g.type(v2) == VertexType.X)) and
g.edge_type(g.edge(v1,v2)) == EdgeType.SIMPLE):
return False
else:
return True
return True

def fuse(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
if not check_fuse(g, v1, v2): return False
if vertex_is_w(g.type(v1)):
return fuse_w(g, v1, v2)
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.remove_vertex(v2)
return True

def check_fuse_w(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
if vertex_is_w(g.type(v1)) and vertex_is_w(g.type(v2)):
v1_in, v1_out = get_w_io(g, v1)
v2_in, v2_out = get_w_io(g, v2)
if g.edge_type(g.edge(v1_in, v2_out)) == EdgeType.SIMPLE or \
g.edge_type(g.edge(v2_in, v1_out)) == EdgeType.SIMPLE:
return True
return False

def fuse_w(g: BaseGraph[VT,ET], v1: VT, v2: VT) -> bool:
if not check_fuse_w(g, v1, v2): return False
v1_in, v1_out = get_w_io(g, v1)
v2_in, v2_out = get_w_io(g, v2)
if g.edge_type(g.edge(v1_out, v2_in)) == EdgeType.SIMPLE:
apply_rule(g, w_fusion, [(v1, v2)])
else:
g.set_position(v2_in, g.qubit(v1_in), g.row(v1_in))
g.set_position(v2_out, g.qubit(v1_out), g.row(v1_out))
apply_rule(g, w_fusion, [(v2, v1)])
return True

def check_remove_id(g: BaseGraph[VT,ET], v: VT) -> bool:
if not (g.vertex_degree(v) == 2 and g.phase(v) == 0):
return False
Expand All @@ -216,13 +240,13 @@ def check_remove_id(g: BaseGraph[VT,ET], v: VT) -> bool:
def remove_id(g: BaseGraph[VT,ET], v: VT) -> bool:
if not check_remove_id(g, v):
return False

v1, v2 = tuple(g.neighbors(v))
g.add_edge_smart(g.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)

return True


20 changes: 14 additions & 6 deletions pyzx/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def draw_matplotlib(
vs_on_row: Dict[FloatInt, int] = {} # count the vertices on each row
for v in g.vertices():
vs_on_row[g.row(v)] = vs_on_row.get(g.row(v), 0) + 1

#Dict[VT,Tuple[FloatInt,FloatInt]]
layout = {v:(g.row(v),-g.qubit(v)) for v in g.vertices()}

Expand All @@ -195,18 +195,22 @@ def draw_matplotlib(
else:
vertices = g.vertices()
edges = g.edges()

for e in edges:
sp = layout[g.edge_s(e)]
tp = layout[g.edge_t(e)]
et = g.edge_type(e)
n_row = vs_on_row.get(g.row(g.edge_s(e)), 0)


dx = tp[0] - sp[0]
dy = tp[1] - sp[1]
bend_wire = (dx == 0) and h_edge_draw == 'blue' and n_row > 2
ecol = '#0099ff' if h_edge_draw == 'blue' and et == 2 else 'black'
if et == 2 and h_edge_draw == 'blue':
ecol = '#0099ff'
elif et == 3:
ecol = 'gray'
else:
ecol = 'black'

if bend_wire:
bend = 0.25
Expand All @@ -231,7 +235,7 @@ def draw_matplotlib(
ax.add_patch(patches.Rectangle(centre,w,h,angle=angle/math.pi*180,facecolor='yellow',edgecolor='black'))

#plt.plot([sp[0],tp[0]],[sp[1],tp[1]], 'k', zorder=0, linewidth=0.8)

for v in vertices:
p = layout[v]
t = g.type(v)
Expand All @@ -245,12 +249,16 @@ def draw_matplotlib(
elif t == VertexType.H_BOX:
ax.add_patch(patches.Rectangle((p[0]-0.1, p[1]-0.1), 0.2, 0.2, facecolor='yellow', edgecolor='black'))
a_offset = 0.25
elif t == VertexType.W_INPUT:
ax.add_patch(patches.Circle(p, 0.05, facecolor='black', edgecolor='black', zorder=1))
elif t == VertexType.W_OUTPUT:
ax.add_patch(patches.Polygon([(p[0]-0.15, p[1]), (p[0]+0.15, p[1]+0.2), (p[0]+0.15, p[1]-0.2)], facecolor='black', edgecolor='black'))
else:
ax.add_patch(patches.Circle(p, 0.1, facecolor='black', edgecolor='black', zorder=1))

if labels: plt.text(p[0]+0.25, p[1]+0.25, str(v), ha='center', color='gray', fontsize=5)
if a: plt.text(p[0], p[1]-a_offset, phase_to_s(a, t), ha='center', color='blue', fontsize=8)

if show_scalar:
x = min((g.row(v) for v in g.vertices()), default = 0)
y = -sum((g.qubit(v) for v in g.vertices()))/(g.num_vertices()+1)
Expand Down
5 changes: 5 additions & 0 deletions pyzx/editor_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ def bialgebra(g: BaseGraph[VT,ET],
"matcher": hrules.match_par_hbox,
"rule": hrules.par_hbox,
"type": MATCHES_VERTICES},
"fuse_w": {"text": "fuse W nodes",
"tooltip": "Merges two connected W nodes together",
"matcher": rules.match_w_fusion_parallel,
"rule": rules.w_fusion,
"type": MATCHES_EDGES},
"copy": {"text": "copy 0/pi spider",
"tooltip": "Copies a single-legged spider with a 0/pi phase through its neighbor",
"matcher": hrules.match_copy,
Expand Down
31 changes: 20 additions & 11 deletions pyzx/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from pyzx.routing.parity_maps import CNOT_tracker, Parity
from pyzx.routing.phase_poly import PhasePoly, mat22partition

from .utils import EdgeType, VertexType, FloatInt, FractionLike
from .utils import EdgeType, VertexType, FloatInt, FractionLike, vertex_is_w
from .graph import Graph
from .graph.base import BaseGraph
from .circuit import Circuit
Expand Down Expand Up @@ -70,7 +70,7 @@ def identity(qubits: int, depth: FloatInt=1,backend:Optional[str]=None) -> BaseG
return g

def spider(
typ:Union[Literal["Z"],Literal["X"],Literal["H"],VertexType.Type],
typ:Union[Literal["Z"], Literal["X"], Literal["H"], Literal["W"], VertexType.Type],
inputs: int,
outputs: int,
phase:FractionLike=0
Expand All @@ -80,10 +80,20 @@ def spider(
if typ == "Z": typ = VertexType.Z
elif typ == "X": typ = VertexType.X
elif typ == "H": typ = VertexType.H_BOX
elif typ == "W": typ = VertexType.W_OUTPUT
else:
if not isinstance(typ,int):
if not isinstance(typ, int):
raise TypeError("Wrong type for spider type: " + str(typ))
g = Graph()
if vertex_is_w(typ):
if inputs != 1:
raise ValueError("Wrong number of inputs for W node: " + str(inputs))
v_in = g.add_vertex(VertexType.W_INPUT, (outputs-1)/2, 0.8)
v_out = g.add_vertex(VertexType.W_OUTPUT, (outputs-1)/2, 1)
g.add_edge(g.edge(v_in, v_out), EdgeType.W_IO)
else:
v_in = g.add_vertex(typ, (inputs-1)/2, 1, phase)
v_out = v_in
inp = []
outp = []
for i in range(inputs):
Expand All @@ -92,11 +102,10 @@ def spider(
for i in range(outputs):
v = g.add_vertex(VertexType.BOUNDARY,i,2)
outp.append(v)
v = g.add_vertex(typ,(inputs-1)/2,1,phase)
for w in inp:
g.add_edge(g.edge(v,w))
g.add_edge(g.edge(v_in, w))
for w in outp:
g.add_edge(g.edge(v,w))
g.add_edge(g.edge(v_out, w))

g.set_inputs(tuple(inp))
g.set_outputs(tuple(outp))
Expand All @@ -105,13 +114,13 @@ def spider(


def CNOT_HAD_PHASE_circuit(
qubits: int,
depth: int,
p_had: float = 0.2,
p_t: float = 0.2,
qubits: int,
depth: int,
p_had: float = 0.2,
p_t: float = 0.2,
clifford:bool=False
) -> Circuit:
"""Construct a Circuit consisting of CNOT, HAD and phase gates.
"""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.

Expand Down
Loading