"""Functions to extract fusion network from a given graph state."""from__future__importannotationsimportcopyimportdataclassesimportoperatorfromenumimportEnumimportnetworkxasnximportnumpyasnpfromgraphix.graphsimimportGraphState
[docs]classResourceType(Enum):"""Resource type."""GHZ="GHZ"LINEAR="LINEAR"NONE=Nonedef__str__(self)->str:"""Return the name of the resource type."""returnself.name
[docs]@dataclasses.dataclassclassResourceGraph:"""Resource graph state object. Parameters ---------- cltype : :class:`ResourceType` object Type of the cluster. graph : :class:`~graphix.graphsim.GraphState` object Graph state of the cluster. """cltype:ResourceTypegraph:GraphStatedef__eq__(self,other:object)->bool:"""Return `True` if two resource graphs are equal, `False` otherwise."""ifnotisinstance(other,ResourceGraph):raiseTypeError("cannot compare ResourceGraph with other object")returnself.cltype==other.cltypeandnx.utils.graphs_equal(self.graph,other.graph)
[docs]defget_fusion_network_from_graph(graph:GraphState,max_ghz:float=np.inf,max_lin:float=np.inf,)->list[ResourceGraph]:"""Extract GHZ and linear cluster graph state decomposition of desired resource state :class:`~graphix.graphsim.GraphState`. Extraction algorithm is based on [1]. [1] Zilk et al., A compiler for universal photonic quantum computers, 2022 `arXiv:2210.09251 <https://arxiv.org/abs/2210.09251>`_ Parameters ---------- graph : :class:`~graphix.graphsim.GraphState` object Graph state. phasedict : dict Dictionary of phases for each node. max_ghz: Maximum size of ghz clusters max_lin: Maximum size of linear clusters Returns ------- list List of :class:`ResourceGraph` objects. """adjdict={k:dict(copy.deepcopy(v))fork,vingraph.adjacency()}number_of_edges=graph.number_of_edges()resource_list=[]neighbors_list=[]# Prepare a list sorted by number of neighbors to get the largest GHZ clusters first.forv,vainadjdict.items():iflen(va)>2:neighbors_list.append((v,len(va)))# If there is an isolated node, add it to the list.iflen(va)==0:resource_list.append(create_resource_graph([v],root=v))# Find GHZ graphs in the graph and remove their edges from the graph.# All nodes that have more than 2 edges become the roots of the GHZ clusters.forv,_insorted(neighbors_list,key=operator.itemgetter(1),reverse=True):iflen(adjdict[v])>2:nodes=[v]whilelen(adjdict[v])>0andlen(nodes)<max_ghz:n,_=adjdict[v].popitem()nodes.append(n)deladjdict[n][v]number_of_edges-=1resource_list.append(create_resource_graph(nodes,root=v))# Find Linear clusters in the remaining graph and remove their edges from the graph.whilenumber_of_edges!=0:forv,vainadjdict.items():iflen(va)==1:n=vnodes=[n]whilelen(adjdict[n])>0andlen(nodes)<max_lin:n2,_=adjdict[n].popitem()nodes.append(n2)deladjdict[n2][n]number_of_edges-=1n=n2# We define any cluster whose size is smaller than 4, a GHZ clusteriflen(nodes)==3:resource_list.append(create_resource_graph([nodes[1],nodes[0],nodes[2]],root=nodes[1]))eliflen(nodes)==2:resource_list.append(create_resource_graph(nodes,root=nodes[0]))else:resource_list.append(create_resource_graph(nodes))# If a cycle exists in the graph, extract one 3-qubit ghz cluster from the cycle.forv,vainadjdict.items():iflen(va)==2:neighbors=list(va.keys())nodes=[v,*neighbors]deladjdict[neighbors[0]][v]deladjdict[neighbors[1]][v]delva[neighbors[0]]delva[neighbors[1]]number_of_edges-=2resource_list.append(create_resource_graph(nodes,root=v))breakreturnresource_list
[docs]defcreate_resource_graph(node_ids:list[int],root:int|None=None)->ResourceGraph:"""Create a resource graph state (GHZ or linear) from node ids. Parameters ---------- node_ids : list List of node ids. root : int Root of the ghz cluster. If None, it's a linear cluster. Returns ------- :class:`ResourceGraph` object `ResourceGraph` object. """cluster_type=Noneedges=[]ifrootisnotNone:edges=[(root,i)foriinnode_idsifi!=root]cluster_type=ResourceType.GHZelse:edges=[(node_ids[i],node_ids[i+1])foriinrange(len(node_ids))ifi+1<len(node_ids)]cluster_type=ResourceType.LINEARtmp_graph=GraphState()tmp_graph.add_nodes_from(node_ids)tmp_graph.add_edges_from(edges)returnResourceGraph(cltype=cluster_type,graph=tmp_graph)
[docs]defget_fusion_nodes(c1:ResourceGraph,c2:ResourceGraph)->list[int]:"""Get the nodes that are fused between two resource states. Currently, we consider only type-I fusion. See [2] for the definition of fusion operation. [2] Daniel E. Browne and Terry Rudolph. Resource-efficient linear optical quantum computation. Physical Review Letters, 95(1):010501, 2005. Parameters ---------- c1 : :class:`ResourceGraph` object First resource state to be fused. c2 : :class:`ResourceGraph` object Second resource state to be fused. Returns ------- list List of nodes that are fused between the two clusters. """ifnotisinstance(c1,ResourceGraph)ornotisinstance(c2,ResourceGraph):raiseTypeError("c1 and c2 must be Cluster objects")ifc1==c2:return[]return[nforninc1.graph.nodesifninc2.graph.nodes]