Skip to content

Commit

Permalink
Merge pull request #25 from YuChenSSR/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
YuChenSSR authored Jun 29, 2023
2 parents 9599f02 + 7c8a43a commit 4cdf2c5
Show file tree
Hide file tree
Showing 5 changed files with 3,455 additions and 26 deletions.
161 changes: 138 additions & 23 deletions src/quafu/dagcircuits/circuit_dag.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import copy

from quafu.dagcircuits.instruction_node import InstructionNode # instruction_node.py in the same folder as circuit_dag.py now
from dag_circuit import DAGCircuit # dag_circuit.py in the same folder as circuit_dag.py now

# import pygraphviz as pgv
from networkx.drawing.nx_pydot import write_dot
Expand Down Expand Up @@ -52,17 +53,17 @@ def gate_to_node(input_gate,specific_label: str):
hashable_gate = InstructionNode(gate.name, gate.pos, gate.paras,gate.duration, gate.unit,gate.channel,gate.time_func, label=specific_label)
return hashable_gate


# Building a DAG Graph using NetworkX from a QuantumCircuit
def circuit_to_dag(circuit):
# Building a DAG Graph using DAGCircuit from a QuantumCircuit
def circuit_to_dag(circuit, measure_flag = True):
'''
Building a DAG Graph using NetworkX from a QuantumCircuit
Building a DAG Graph using DAGCircui from a QuantumCircuit
Args:
circuit: a QuantumCircuit object
measure_flag: whether to add measure_gate node to the dag graph
Returns:
g: a networkx MultiDiGraph object
g: a DAGCircuit object
example:
.. jupyter-execute::
Expand All @@ -85,8 +86,9 @@ def circuit_to_dag(circuit):
# A dictionary to store the last use of any qubit
qubit_last_use = {}

g = nx.MultiDiGraph() # two nodes can have multiple edges
# g = nx.MultiDiGraph() # two nodes can have multiple edges
# g = nx.DiGraph() # two nodes can only have one edge
g = DAGCircuit() # two nodes can only have one edge

# Add the start node
# g.add_node(-1,{"color": "green"})
Expand All @@ -111,22 +113,24 @@ def circuit_to_dag(circuit):
g.add_edge(-1, hashable_gate,label=f'q{qubit}',color="green")

qubit_last_use[qubit] = hashable_gate

# Add measure_gate node
qm = Any
qm.name = "measure"
qm.paras, qm.duration, qm.unit,qm.channel,qm.time_func = [None,None,None,None,None]
qm.pos = copy.deepcopy(circuit.measures) # circuit.measures is a dict
measure_gate = InstructionNode(qm.name, qm.pos, qm.paras, qm.duration, qm.unit,qm.channel,qm.time_func, label="m")
g.add_node(measure_gate,color="blue")
# Add edges from qubit_last_use[qubit] to measure_gate
for qubit in measure_gate.pos.keys():
if qubit in qubit_last_use:
g.add_edge(qubit_last_use[qubit], measure_gate,label=f'q{qubit}')
else:
g.add_edge(-1, measure_gate,label=f'q{qubit}',color="green")

qubit_last_use[qubit] = measure_gate

if measure_flag:
# Add measure_gate node
qm = Any
qm.name = "measure"
qm.paras, qm.duration, qm.unit = [None,None,None]
qm.channel, qm.time_func = [None,None]
qm.pos = copy.deepcopy(circuit.measures) # circuit.measures is a dict
measure_gate = InstructionNode(qm.name, qm.pos, qm.paras, qm.duration, qm.unit, qm.channel, qm.time_func, label="m")
g.add_node(measure_gate,color="blue")
# Add edges from qubit_last_use[qubit] to measure_gate
for qubit in measure_gate.pos:
if qubit in qubit_last_use:
g.add_edge(qubit_last_use[qubit], measure_gate,label=f'q{qubit}')
else:
g.add_edge(-1, measure_gate,label=f'q{qubit}',color="green")

qubit_last_use[qubit] = measure_gate

# Add the end node
# g.add_node(float('inf'),{"color": "red"})
Expand All @@ -135,6 +139,11 @@ def circuit_to_dag(circuit):
for qubit in qubit_last_use:
g.add_edge(qubit_last_use[qubit], float('inf'),label=f'q{qubit}',color="red")

# update qubits_used, cbits_used, num_instruction_nodes
g.update_qubits_used()
g.update_cbits_used()
g.update_num_instruction_nodes()

return g


Expand Down Expand Up @@ -190,7 +199,7 @@ def node_to_gate(gate_in_dag):
Args:
gate_in_dag: a node in dag graph , gate_in_dag is a GateWrapper object.
in GateWrapper, gate_in_dag.name is uppercase, gate_in_dag.pos is a list or a dict
in instruction_node, gate_in_dag.name is uppercase, gate_in_dag.pos is a list or a dict
gate_transform support gate with one qubit or more qubits, not measures!
and you should exculde nodes [-1 ,float('inf') , measure_gate] in dag graph
Expand Down Expand Up @@ -356,3 +365,109 @@ def draw_dag(dep_g, output_format="png"):
else:
raise ValueError("Unsupported output format: choose either 'png' or 'svg'")


def nodelist_to_dag(op_nodes: List[Any]) -> DAGCircuit:
# Starting Label Index
i = 0

# A dictionary to store the last use of any qubit
qubit_last_use = {}

# g = nx.MultiDiGraph() # two nodes can have multiple edges
# g = nx.DiGraph() # two nodes can only have one edge
g = DAGCircuit()

# Add the start node
# g.add_node(-1,{"color": "green"})
g.add_nodes_from([(-1, {"color": "green"})])

# deepcopy the circuit to avoid modifying the original circuit
# gates = copy.deepcopy(circuit.gates) # need to import copy
# change to: gate = copy.deepcopy(input_gate) in gate_to_node()

for op_node in op_nodes:
# transform gate to node
hashable_gate = copy.deepcopy(op_node)
g.add_node(hashable_gate,color="blue")

# Add edges based on qubit_last_use; update last use
for qubit in hashable_gate.pos:
if qubit in qubit_last_use:
g.add_edge(qubit_last_use[qubit], hashable_gate,label=f'q{qubit}')
else:
g.add_edge(-1, hashable_gate,label=f'q{qubit}',color="green")

qubit_last_use[qubit] = hashable_gate


# Add the end node
# g.add_node(float('inf'),{"color": "red"})
g.add_nodes_from([(float('inf'), {"color": "red"})])

for qubit in qubit_last_use:
g.add_edge(qubit_last_use[qubit], float('inf'),label=f'q{qubit}',color="red")

# update the qubits_used, cbits_used, num_instruction_nodes
g.qubits_used = g.update_qubits_used()
g.cbits_used = g.update_cbits_used()
g.num_instruction_nodes = g.update_num_instruction_nodes()

return g

# nodes_qubit_mapping_dict
def nodelist_qubit_mapping_dict(nodes_list):
'''
Args:
nodes_list: a list of nodes
Returns:
nodes_qubit_mapping_dict: a dict about keys are the qubits used by the nodes and values are the new qubits
'''
nodes_list_qubits_used = set()
for node in nodes_list:
if hasattr(node, 'pos') and node.pos is not None:
nodes_list_qubits_used = nodes_list_qubits_used | set(node.pos)

mapping_pos = list(range(len(nodes_list_qubits_used)))
# mapping, get a dict
nodes_qubit_mapping_dict = dict(zip(sorted(list(nodes_list_qubits_used)), mapping_pos))
nodes_qubit_mapping_dict

return nodes_qubit_mapping_dict

def nodelist_qubit_mapping_dict_reverse(nodes_list):
'''
Args:
nodes_list: a list of nodes
Returns:
nodes_qubit_mapping_dict_reverse: a dict about keys are the new qubits and values are the qubits used by the nodes
'''
nodes_qubit_mapping_dict = nodelist_qubit_mapping_dict(nodes_list)
# reverse mapping, get a dict
nodes_qubit_mapping_dict_reverse = {value: key for key, value in nodes_qubit_mapping_dict.items()}

return nodes_qubit_mapping_dict_reverse

# a function to map nodes_list
def nodes_list_mapping(nodes_list, nodes_qubit_mapping_dict):
'''
Args:
nodes_list: the nodes list of instruction nodes
nodes_qubit_mapping_dict: the dict of the mapping qubits
return:
nodes_list_mapping: the nodes_list after mapping qubits
'''
nodes_qubit_mapping_dict
nodes_list_mapping = []
for node in nodes_list:
node_new = copy.deepcopy(node)
if hasattr(node, 'pos') and node.pos is not None:
if isinstance(node.pos, list):
node_new.pos = [nodes_qubit_mapping_dict[qubit] for qubit in node.pos]
elif isinstance(node.pos, dict):
node_new.pos = {}
# the values of the dict are void, so we need to copy the values from the original dict
for qubit in node.pos:
node_new.pos[nodes_qubit_mapping_dict[qubit]] = copy.deepcopy(node.pos[qubit])
nodes_list_mapping.append(node_new)
return nodes_list_mapping
53 changes: 53 additions & 0 deletions src/quafu/dagcircuits/dag.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
digraph {
"-1" [color=green];
"0{CX(0,1)}" [color=blue];
"1{X(2)}" [color=blue];
"2{CX(1,0)}" [color=blue];
"3{CX(2,1)}" [color=blue];
"4{CP(1,0)}(1.571)" [color=blue];
"5{barrier(0,1,2)}" [color=blue];
"6{RXX(0,1)}(1.571)" [color=blue];
"7{delay(0)}" [color=blue];
"8{CSWAP(0,1,2)}" [color=blue];
"9{MCX(0,1,2)}" [color=blue];
"10{MCY(0,1,2)}" [color=blue];
"11{MCZ(0,1,2)}" [color=blue];
"12{CT(2,1)}" [color=blue];
"m{measure(0,1,2=>0,1,2)}" [color=blue];
inf [color=red];
"-1" -> "0{CX(0,1)}" [color=green, key=0, label=q0];
"-1" -> "0{CX(0,1)}" [color=green, key=1, label=q1];
"-1" -> "1{X(2)}" [color=green, key=0, label=q2];
"0{CX(0,1)}" -> "2{CX(1,0)}" [key=0, label=q1];
"0{CX(0,1)}" -> "2{CX(1,0)}" [key=1, label=q0];
"1{X(2)}" -> "3{CX(2,1)}" [key=0, label=q2];
"2{CX(1,0)}" -> "3{CX(2,1)}" [key=0, label=q1];
"2{CX(1,0)}" -> "4{CP(1,0)}(1.571)" [key=0, label=q0];
"3{CX(2,1)}" -> "4{CP(1,0)}(1.571)" [key=0, label=q1];
"3{CX(2,1)}" -> "5{barrier(0,1,2)}" [key=0, label=q2];
"4{CP(1,0)}(1.571)" -> "5{barrier(0,1,2)}" [key=0, label=q0];
"4{CP(1,0)}(1.571)" -> "5{barrier(0,1,2)}" [key=1, label=q1];
"5{barrier(0,1,2)}" -> "6{RXX(0,1)}(1.571)" [key=0, label=q0];
"5{barrier(0,1,2)}" -> "6{RXX(0,1)}(1.571)" [key=1, label=q1];
"5{barrier(0,1,2)}" -> "8{CSWAP(0,1,2)}" [key=0, label=q2];
"6{RXX(0,1)}(1.571)" -> "7{delay(0)}" [key=0, label=q0];
"6{RXX(0,1)}(1.571)" -> "8{CSWAP(0,1,2)}" [key=0, label=q1];
"7{delay(0)}" -> "8{CSWAP(0,1,2)}" [key=0, label=q0];
"8{CSWAP(0,1,2)}" -> "9{MCX(0,1,2)}" [key=0, label=q0];
"8{CSWAP(0,1,2)}" -> "9{MCX(0,1,2)}" [key=1, label=q1];
"8{CSWAP(0,1,2)}" -> "9{MCX(0,1,2)}" [key=2, label=q2];
"9{MCX(0,1,2)}" -> "10{MCY(0,1,2)}" [key=0, label=q0];
"9{MCX(0,1,2)}" -> "10{MCY(0,1,2)}" [key=1, label=q1];
"9{MCX(0,1,2)}" -> "10{MCY(0,1,2)}" [key=2, label=q2];
"10{MCY(0,1,2)}" -> "11{MCZ(0,1,2)}" [key=0, label=q0];
"10{MCY(0,1,2)}" -> "11{MCZ(0,1,2)}" [key=1, label=q1];
"10{MCY(0,1,2)}" -> "11{MCZ(0,1,2)}" [key=2, label=q2];
"11{MCZ(0,1,2)}" -> "12{CT(2,1)}" [key=0, label=q2];
"11{MCZ(0,1,2)}" -> "12{CT(2,1)}" [key=1, label=q1];
"11{MCZ(0,1,2)}" -> "m{measure(0,1,2=>0,1,2)}" [key=0, label=q0];
"12{CT(2,1)}" -> "m{measure(0,1,2=>0,1,2)}" [key=0, label=q1];
"12{CT(2,1)}" -> "m{measure(0,1,2=>0,1,2)}" [key=1, label=q2];
"m{measure(0,1,2=>0,1,2)}" -> inf [color=red, key=0, label=q0];
"m{measure(0,1,2=>0,1,2)}" -> inf [color=red, key=1, label=q1];
"m{measure(0,1,2=>0,1,2)}" -> inf [color=red, key=2, label=q2];
}
Loading

0 comments on commit 4cdf2c5

Please sign in to comment.