From 87cd8ffde01f0f9682446a1f4993e96281173cc7 Mon Sep 17 00:00:00 2001 From: mjsutcliffe99 Date: Thu, 8 Aug 2024 21:32:55 +0100 Subject: [PATCH 1/4] Add cat decompositions --- pyzx/simulate.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/pyzx/simulate.py b/pyzx/simulate.py index 6d0281be..6bda1edd 100644 --- a/pyzx/simulate.py +++ b/pyzx/simulate.py @@ -574,3 +574,99 @@ def cut_wishbone(g,v,neighs,ph): gRight.add_to_phase(v_right,1) return (gLeft,gRight) + +def gen_catlike_term(gInit: BaseGraph[VT,ET], verts: List[VT], ph_base, ph_central, ph_appendix, eType_base, eType_appendix, scal_positive, scal_power, scal_phase): + """ + Used for constructing graph terms with local structure of the form of the right-hand side terms of the cat (and magic5) decompositions seen in: https://arxiv.org/pdf/2202.09202. + For example, consider the magic5 decomposition in this above paper. Here, we exchange 5 T-spiders (verts) of our graph (gInit) for three catlike terms. + The third and final such term has: + Phase of pi/2 on each of the 5 outgoing edges, i.e. ph_base=Fraction(1,2); + Phase of 0 on the inner central spider to which the others are connected, i.e. ph_central=0; + Phase of pi/4 on the outstanding one-legged 'appendix' spider, i.e. ph_appendix=Fraction(1,4); + Hadamard edges connecting each of the outgoing spiders to the inner central spider, i.e. eType_base=EdgeType.HADAMARD; + Hadamard edge connecting the appendix spider to the central spider, i.e. eType_appendix=EdgeType.HADAMARD; + Negative sign on the scalar factor, i.e. scal_positive=False; + sqrt(2)^3 factor in its scalar, i.e. scal_power=3; + e^{i*pi/4} factor in its scalar, i.e. scal_phase=Fraction(1,4). + """ + g = gInit.clone() + g.scalar.add_power(scal_power) + if not scal_positive: g.scalar.add_power(1) + g.scalar.add_phase(scal_phase) + + new_v1 = g.add_vertex(qubit=-1,row=-1,ty=1,phase=ph_central) + new_v2 = g.add_vertex(qubit=-2,row=-1,ty=1,phase=ph_appendix) + g.add_edge((new_v1,new_v2),eType_appendix) + for v in verts: + g.add_to_phase(v,ph_base-Fraction(1,4)) + g.add_edge((v,new_v1),eType_base) + + return g + +def check_catn(g: BaseGraph[VT,ET], vert: VT, n): + """Runs assertion checks to ensure the cat_n decomposition is applicable to vertex v of graph g. See: https://arxiv.org/pdf/2202.09202.""" + assert n in [3,4,5,6], "Cat"+str(n)+" decomposition not implemented. Try cat3, cat4, cat5, or cat6 instead." + assert vert in g.vertices(), "Vertex "+str(vert)+" does not exist in graph" + assert g.phase(vert) == 0, "The cat"+str(n)+" decomposition acts on a phaseless spider but specified vertex has phase "+str(g.phase(vert)) # TODO: the cat decomps should be updated to work even if the central phase is pi (i.e. not just zero) + assert len(g.neighbors(vert)) == n, "The cat"+str(n)+" decomposition acts on a "+str(n)+"-degree spider but specified vertex has degree "+str(len(g.neighbors(vert))) + for v in g.neighbors(vert): + assert (g.edge_type((vert,v)) == EdgeType.HADAMARD and g.type(v) == g.type(vert)) or \ + (g.edge_type((vert,v)) == EdgeType.SIMPLE and g.type(v) == toggle_vertex(g.type(vert))), \ + "The cat"+str(n)+" decomposition must act on a spider with "+str(n)+" opposite colour neighbours (or like-coloured with Hadamard edges)" + return True + +def apply_magic5(g: BaseGraph[VT,ET], verts: List[VT]) -> SumGraph: + """Apply the magic5 decomposition to vertices verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" + assert len(verts) == 5, "The magic5 decomposition acts on 5 spiders but you specified "+str(len(verts)) + for v in verts: assert v in g.vertices(), "Vertex "+str(v)+" does not exist in graph" + + g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), Fraction(-1,4), EdgeType.SIMPLE, EdgeType.SIMPLE, True, 2, 0) + g_B = gen_catlike_term(g, verts, 0, 0, Fraction(-1,4), EdgeType.HADAMARD, EdgeType.HADAMARD, True, 3, Fraction(3,4)) + g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, Fraction(1,4), EdgeType.HADAMARD, EdgeType.HADAMARD, False, 3, Fraction(1,4)) + + return [g_A, g_B, g_C] + +# TODO: the cat decomps should be updated to work even if the central phase is pi (i.e. not just zero) +def apply_cat3(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: + """Apply the cat3 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" + check_catn(g,vert,3) + verts = g.neighbors(vert) + g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.HADAMARD, True, -1, Fraction(-1,4)) + g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) + g_A.remove_vertex(vert) + g_B.remove_vertex(vert) + return [g_A, g_B] + +def apply_cat4(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: + """Apply the cat4 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" + check_catn(g,vert,4) + verts = g.neighbors(vert) + g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.SIMPLE, True, -1, Fraction(-1,4)) + g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) + g_A.remove_vertex(vert) + g_B.remove_vertex(vert) + return [g_A, g_B] + +def apply_cat5(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: + """Apply the cat5 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" + check_catn(g,vert,5) + verts = g.neighbors(vert) + g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.HADAMARD, True, -2, 0) + g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, -1, Fraction(3,4)) + g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, 0, EdgeType.HADAMARD, EdgeType.SOLID, False, -1, Fraction(1,4)) + g_A.remove_vertex(vert) + g_B.remove_vertex(vert) + g_C.remove_vertex(vert) + return [g_A, g_B, g_C] + +def apply_cat6(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: + """Apply the cat6 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" + check_catn(g,vert,6) + verts = g.neighbors(vert) + g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.SIMPLE, True, -2, 0) + g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, -1, Fraction(3,4)) + g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, False, -1, Fraction(1,4)) + g_A.remove_vertex(vert) + g_B.remove_vertex(vert) + g_C.remove_vertex(vert) + return [g_A, g_B, g_C] \ No newline at end of file From 26acc1cce00779e273aa053d349962900cbfd163 Mon Sep 17 00:00:00 2001 From: mjsutcliffe99 <105458229+mjsutcliffe99@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:42:39 +0100 Subject: [PATCH 2/4] New decomps return graphs as a SumGraph --- pyzx/simulate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyzx/simulate.py b/pyzx/simulate.py index 6bda1edd..5faa01ba 100644 --- a/pyzx/simulate.py +++ b/pyzx/simulate.py @@ -624,7 +624,7 @@ def apply_magic5(g: BaseGraph[VT,ET], verts: List[VT]) -> SumGraph: g_B = gen_catlike_term(g, verts, 0, 0, Fraction(-1,4), EdgeType.HADAMARD, EdgeType.HADAMARD, True, 3, Fraction(3,4)) g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, Fraction(1,4), EdgeType.HADAMARD, EdgeType.HADAMARD, False, 3, Fraction(1,4)) - return [g_A, g_B, g_C] + return SumGraph([g_A, g_B, g_C]) # TODO: the cat decomps should be updated to work even if the central phase is pi (i.e. not just zero) def apply_cat3(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: @@ -635,7 +635,7 @@ def apply_cat3(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) g_A.remove_vertex(vert) g_B.remove_vertex(vert) - return [g_A, g_B] + return SumGraph([g_A, g_B]) def apply_cat4(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat4 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" @@ -645,7 +645,7 @@ def apply_cat4(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) g_A.remove_vertex(vert) g_B.remove_vertex(vert) - return [g_A, g_B] + return SumGraph([g_A, g_B]) def apply_cat5(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat5 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" @@ -657,7 +657,7 @@ def apply_cat5(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: g_A.remove_vertex(vert) g_B.remove_vertex(vert) g_C.remove_vertex(vert) - return [g_A, g_B, g_C] + return SumGraph([g_A, g_B, g_C]) def apply_cat6(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat6 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" @@ -669,4 +669,4 @@ def apply_cat6(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: g_A.remove_vertex(vert) g_B.remove_vertex(vert) g_C.remove_vertex(vert) - return [g_A, g_B, g_C] \ No newline at end of file + return SumGraph([g_A, g_B, g_C]) From e33bb657f6bfe7aa017e8067f379da698a135d61 Mon Sep 17 00:00:00 2001 From: mjsutcliffe99 <105458229+mjsutcliffe99@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:59:19 +0100 Subject: [PATCH 3/4] Fix type errors --- pyzx/simulate.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyzx/simulate.py b/pyzx/simulate.py index 5faa01ba..380391fe 100644 --- a/pyzx/simulate.py +++ b/pyzx/simulate.py @@ -594,8 +594,8 @@ def gen_catlike_term(gInit: BaseGraph[VT,ET], verts: List[VT], ph_base, ph_centr if not scal_positive: g.scalar.add_power(1) g.scalar.add_phase(scal_phase) - new_v1 = g.add_vertex(qubit=-1,row=-1,ty=1,phase=ph_central) - new_v2 = g.add_vertex(qubit=-2,row=-1,ty=1,phase=ph_appendix) + new_v1 = g.add_vertex(qubit=-1,row=-1,ty=VertexType.Z,phase=ph_central) + new_v2 = g.add_vertex(qubit=-2,row=-1,ty=VertexType.Z,phase=ph_appendix) g.add_edge((new_v1,new_v2),eType_appendix) for v in verts: g.add_to_phase(v,ph_base-Fraction(1,4)) @@ -630,7 +630,7 @@ def apply_magic5(g: BaseGraph[VT,ET], verts: List[VT]) -> SumGraph: def apply_cat3(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat3 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" check_catn(g,vert,3) - verts = g.neighbors(vert) + verts = List(g.neighbors(vert)) g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.HADAMARD, True, -1, Fraction(-1,4)) g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) g_A.remove_vertex(vert) @@ -640,7 +640,7 @@ def apply_cat3(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: def apply_cat4(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat4 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" check_catn(g,vert,4) - verts = g.neighbors(vert) + verts = List(g.neighbors(vert)) g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.SIMPLE, True, -1, Fraction(-1,4)) g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, 0, Fraction(1,2)) g_A.remove_vertex(vert) @@ -650,10 +650,10 @@ def apply_cat4(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: def apply_cat5(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat5 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" check_catn(g,vert,5) - verts = g.neighbors(vert) + verts = List(g.neighbors(vert)) g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.HADAMARD, True, -2, 0) g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, -1, Fraction(3,4)) - g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, 0, EdgeType.HADAMARD, EdgeType.SOLID, False, -1, Fraction(1,4)) + g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, False, -1, Fraction(1,4)) g_A.remove_vertex(vert) g_B.remove_vertex(vert) g_C.remove_vertex(vert) @@ -662,7 +662,7 @@ def apply_cat5(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: def apply_cat6(g: BaseGraph[VT,ET], vert: VT) -> SumGraph: """Apply the cat6 decomposition to vertex verts of graph g. See: https://arxiv.org/pdf/2202.09202.""" check_catn(g,vert,6) - verts = g.neighbors(vert) + verts = List(g.neighbors(vert)) g_A = gen_catlike_term(g, verts, 0, Fraction(-1,2), 0, EdgeType.SIMPLE, EdgeType.SIMPLE, True, -2, 0) g_B = gen_catlike_term(g, verts, 0, 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, True, -1, Fraction(3,4)) g_C = gen_catlike_term(g, verts, Fraction(1,2), 0, 0, EdgeType.HADAMARD, EdgeType.SIMPLE, False, -1, Fraction(1,4)) From f129f47b56ca6f7c9c167b34c292d3c31f0cb744 Mon Sep 17 00:00:00 2001 From: mjsutcliffe99 <105458229+mjsutcliffe99@users.noreply.github.com> Date: Fri, 9 Aug 2024 03:02:09 +0100 Subject: [PATCH 4/4] Fix more type errors --- pyzx/simulate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyzx/simulate.py b/pyzx/simulate.py index 380391fe..1e67cd15 100644 --- a/pyzx/simulate.py +++ b/pyzx/simulate.py @@ -610,8 +610,8 @@ def check_catn(g: BaseGraph[VT,ET], vert: VT, n): assert g.phase(vert) == 0, "The cat"+str(n)+" decomposition acts on a phaseless spider but specified vertex has phase "+str(g.phase(vert)) # TODO: the cat decomps should be updated to work even if the central phase is pi (i.e. not just zero) assert len(g.neighbors(vert)) == n, "The cat"+str(n)+" decomposition acts on a "+str(n)+"-degree spider but specified vertex has degree "+str(len(g.neighbors(vert))) for v in g.neighbors(vert): - assert (g.edge_type((vert,v)) == EdgeType.HADAMARD and g.type(v) == g.type(vert)) or \ - (g.edge_type((vert,v)) == EdgeType.SIMPLE and g.type(v) == toggle_vertex(g.type(vert))), \ + assert (g.edge_type(g.edge(vert,v)) == EdgeType.HADAMARD and g.type(v) == g.type(vert)) or \ + (g.edge_type(g.edge(vert,v)) == EdgeType.SIMPLE and g.type(v) == toggle_vertex(g.type(vert))), \ "The cat"+str(n)+" decomposition must act on a spider with "+str(n)+" opposite colour neighbours (or like-coloured with Hadamard edges)" return True