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

update DAGCircuit class and some tests #25

Merged
merged 1 commit into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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