Skip to content

dag ¤

Tools for converting between directed acyclic graphs (DAGs) and quantum circuits

Functions:

Name Description
draw_dag

Draws a directed acyclic graph (DAG) representation of a quantum circuit and saves it as an image.

qc2dag

Converts a quantum circuit into a directed acyclic graph (DAG).

dag2qc

Converts a directed acyclic graph (DAG) back into a QuantumCircuit.

draw_dag(dag, output='dag_figure.png') ¤

Draws a directed acyclic graph (DAG) representation of a quantum circuit and saves it as an image.

Parameters:

Name Type Description Default
dag DiGraph

The quantum circuit represented as a directed acyclic graph.

required
output str

The filename for saving the generated DAG image. Defaults to 'dag_figure.png'.

'dag_figure.png'
Source code in quark/circuit/dag.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def draw_dag(dag, output='dag_figure.png'):
    """Draws a directed acyclic graph (DAG) representation of a quantum circuit and saves it as an image.

    Args:
        dag (nx.DiGraph): The quantum circuit represented as a directed acyclic graph.
        output (str, optional): The filename for saving the generated DAG image. Defaults to 'dag_figure.png'.
    """
    import matplotlib.pyplot as plt

    A = nx.nx_agraph.to_agraph(dag)

    for node in A.nodes():
        gate = node.split('_')[0]
        if gate == 'measure':
            cbit = dag.nodes[node]['cbits'][0]
            node.attr['label'] = gate + f' [c{cbit}]'
        else:
            node.attr['label'] = gate
    for u, v, data in dag.edges(data=True):
        edge = A.get_edge(u, v)
        line = ''
        for qubit in data['qubit']:
            line += 'q'+str(qubit)
        edge.attr['label'] = line #data['qubit'] 

    A.graph_attr['dpi'] = '300' 
    A.layout(prog='dot')

    A.draw(output)

    img = plt.imread(output)
    plt.imshow(img)
    plt.axis('off')
    plt.show()

qc2dag(qc: QuantumCircuit, show_qubits: bool = True) -> nx.DiGraph ¤

Converts a quantum circuit into a directed acyclic graph (DAG).

Parameters:

Name Type Description Default
qc QuantumCircuit

The quantum circuit to be converted.

required

Returns:

Type Description
DiGraph

nx.DiGraph: A directed acyclic graph representing the quantum circuit,

DiGraph

with nodes as operations and edges as dependencies.

Source code in quark/circuit/dag.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def qc2dag(qc: 'QuantumCircuit',show_qubits:bool=True) -> 'nx.DiGraph':
    """Converts a quantum circuit into a directed acyclic graph (DAG).

    Args:
        qc (QuantumCircuit): The quantum circuit to be converted.

    Returns:
        nx.DiGraph: A directed acyclic graph representing the quantum circuit, 
        with nodes as operations and edges as dependencies.
    """
    node_list,edge_list = convert_gate_info_to_dag_info(qc.nqubits,qc.qubits,qc.gates,show_qubits=show_qubits)
    dag = nx.DiGraph()
    dag.add_nodes_from(node_list)
    dag.add_edges_from(edge_list)
    dag.graph['qubits'] = qc.qubits
    return dag

dag2qc(dag: nx.DiGraph, nqubits: int | None = None, ncbits: int | None = None) -> QuantumCircuit ¤

Converts a directed acyclic graph (DAG) back into a QuantumCircuit.

Parameters:

Name Type Description Default
dag DiGraph

The DAG representation of the quantum circuit.

required
nqubits int

The number of qubits in the circuit.

None
ncbits int | None

The number of classical bits in the circuit. Defaults to the value of nqubits.

None

Returns:

Name Type Description
QuantumCircuit QuantumCircuit

The reconstructed quantum circuit based on the DAG structure.

Source code in quark/circuit/dag.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def dag2qc(dag: 'nx.DiGraph',nqubits: int|None=None, ncbits: int|None = None) -> 'QuantumCircuit':
    """Converts a directed acyclic graph (DAG) back into a QuantumCircuit.

    Args:
        dag (nx.DiGraph):The DAG representation of the quantum circuit.
        nqubits (int): The number of qubits in the circuit.
        ncbits (int | None, optional): The number of classical bits in the circuit. Defaults to the value of `nqubits`.

    Returns:
        QuantumCircuit: The reconstructed quantum circuit based on the DAG structure.
    """
    current_qubits = []    
    new = []
    for node in nx.topological_sort(dag):
        gate = node.split('_')[0]
        qubits = dag.nodes[node]['qubits']
        current_qubits += qubits
        #print(gate,qubits)
        if gate in one_qubit_gates_available.keys():
            new.append((gate,qubits[0]))
        elif gate in two_qubit_gates_available.keys():
            new.append((gate,qubits[0],qubits[1]))
        elif gate in three_qubit_gates_available.keys():
            new.append((gate,qubits[0],qubits[1],qubits[2]))
        elif gate in one_qubit_parameter_gates_available.keys():
            params = dag.nodes[node]['params']
            new.append((gate,*params,qubits[0]))
        elif gate in two_qubit_parameter_gates_available.keys():
            params = dag.nodes[node]['params']
            new.append((gate,*params,qubits[0],qubits[1]))
        elif gate in functional_gates_available.keys():
            if gate == 'measure':
                cbits = dag.nodes[node]['cbits']
                new.append((gate,qubits,cbits))
            elif gate == 'barrier':
                new.append((gate,tuple(qubits)))
            elif gate == 'delay':
                duration = dag.nodes[node]['duration']
                new.append((gate,duration,tuple(qubits)))
            elif gate == 'reset':
                new.append((gate,qubits[0]))
    if nqubits is None:
        nqubits = max(current_qubits)+1
    if ncbits is None:
        ncbits = nqubits                
    qc = QuantumCircuit(nqubits, ncbits)
    qc.gates = new
    qc.qubits = dag.graph['qubits']
    return qc