qiskit_trebugger.model.circuit_comparator

Implements the circuit diff functionality for quantum circuits.

  1"""Implements the circuit diff functionality for quantum circuits.
  2"""
  3from qiskit.converters import dag_to_circuit, circuit_to_dag
  4from numpy import zeros, uint16
  5
  6# make the global DP array
  7LCS_DP = zeros((2000, 2000), dtype=uint16)
  8
  9
 10class CircuitComparator:
 11    """Compares two quantum circuits and generates the
 12    circuit level diffs using longest common subsequences.
 13    """
 14
 15    @staticmethod
 16    def get_moments(dag):
 17        """Returns the layers of the dag circuit as list
 18
 19        Args:
 20            dag (DAGCircuit): DAGCircuit representing a quantum circuit
 21
 22        Returns:
 23            List: list of depth-1 circuits as graphs
 24        """
 25        moments = [l["graph"] for l in list(dag.layers())]
 26        return moments
 27
 28    @staticmethod
 29    def make_lcs(moments1, moments2):
 30        """Populates the LCS table by comparing the
 31        first circuit's layers with the second
 32
 33        Args:
 34            moments1 (List): list of depth-1 layers
 35            moments2 (List): list of depth-1 layers
 36        """
 37
 38        # clear for the base cases of dp
 39        for i in range(2000):
 40            LCS_DP[i][0], LCS_DP[0][i] = 0, 0
 41
 42        size_1, size_2 = len(moments1), len(moments2)
 43
 44        for i in range(1, size_1 + 1):
 45            for j in range(1, size_2 + 1):
 46                # if the layers are isomorphic then okay
 47                if moments1[i - 1] == moments2[j - 1]:
 48                    LCS_DP[i][j] = 1 + LCS_DP[i - 1][j - 1]
 49                else:
 50                    LCS_DP[i][j] = max(LCS_DP[i - 1][j], LCS_DP[i][j - 1])
 51
 52    @staticmethod
 53    def compare(prev_circ, curr_circ):
 54        """Compares two circuits and returns the circuit diff as a
 55        quantum circuit with changed colors of diff
 56
 57        Args:
 58            prev_circ (QuantumCircuit): first circuit
 59            curr_circ (QuantumCircuit): second circuit
 60
 61        Returns:
 62            QuantumCircuit: the quantum circuit representing the
 63                            circuit diff
 64        """
 65        if prev_circ is None:
 66            return (False, curr_circ)
 67
 68        # update by reference as there is no qasm now
 69        prev_dag = circuit_to_dag(prev_circ.copy())
 70        curr_dag = circuit_to_dag(curr_circ.copy())
 71
 72        moments1 = CircuitComparator.get_moments(prev_dag)
 73        moments2 = CircuitComparator.get_moments(curr_dag)
 74
 75        CircuitComparator.make_lcs(moments1, moments2)
 76
 77        (size_1, size_2) = (len(moments1), len(moments2))
 78
 79        id_set = set()
 80        i = size_1
 81        j = size_2
 82
 83        while i > 0 and j > 0:
 84            if moments1[i - 1] == moments2[j - 1]:
 85                # just want diff for second one
 86                id_set.add(j - 1)
 87                i -= 1
 88                j -= 1
 89
 90            else:
 91                if LCS_DP[i - 1][j] > LCS_DP[i][j - 1]:
 92                    # means the graph came from the
 93                    # first circuit , go up
 94                    i -= 1
 95                else:
 96                    # if equal or small, go left
 97                    j -= 1
 98
 99        # if the whole circuit has not changed
100        fully_changed = len(id_set) == 0
101
102        if not fully_changed:
103            for id2, layer in enumerate(list(curr_dag.layers())):
104                if id2 not in id_set:
105                    # this is not an LCS node -> highlight it
106                    for node in layer["graph"].front_layer():
107                        node.name = node.name + " "
108
109        return (fully_changed, dag_to_circuit(curr_dag))
LCS_DP = array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=uint16)
class CircuitComparator:
 11class CircuitComparator:
 12    """Compares two quantum circuits and generates the
 13    circuit level diffs using longest common subsequences.
 14    """
 15
 16    @staticmethod
 17    def get_moments(dag):
 18        """Returns the layers of the dag circuit as list
 19
 20        Args:
 21            dag (DAGCircuit): DAGCircuit representing a quantum circuit
 22
 23        Returns:
 24            List: list of depth-1 circuits as graphs
 25        """
 26        moments = [l["graph"] for l in list(dag.layers())]
 27        return moments
 28
 29    @staticmethod
 30    def make_lcs(moments1, moments2):
 31        """Populates the LCS table by comparing the
 32        first circuit's layers with the second
 33
 34        Args:
 35            moments1 (List): list of depth-1 layers
 36            moments2 (List): list of depth-1 layers
 37        """
 38
 39        # clear for the base cases of dp
 40        for i in range(2000):
 41            LCS_DP[i][0], LCS_DP[0][i] = 0, 0
 42
 43        size_1, size_2 = len(moments1), len(moments2)
 44
 45        for i in range(1, size_1 + 1):
 46            for j in range(1, size_2 + 1):
 47                # if the layers are isomorphic then okay
 48                if moments1[i - 1] == moments2[j - 1]:
 49                    LCS_DP[i][j] = 1 + LCS_DP[i - 1][j - 1]
 50                else:
 51                    LCS_DP[i][j] = max(LCS_DP[i - 1][j], LCS_DP[i][j - 1])
 52
 53    @staticmethod
 54    def compare(prev_circ, curr_circ):
 55        """Compares two circuits and returns the circuit diff as a
 56        quantum circuit with changed colors of diff
 57
 58        Args:
 59            prev_circ (QuantumCircuit): first circuit
 60            curr_circ (QuantumCircuit): second circuit
 61
 62        Returns:
 63            QuantumCircuit: the quantum circuit representing the
 64                            circuit diff
 65        """
 66        if prev_circ is None:
 67            return (False, curr_circ)
 68
 69        # update by reference as there is no qasm now
 70        prev_dag = circuit_to_dag(prev_circ.copy())
 71        curr_dag = circuit_to_dag(curr_circ.copy())
 72
 73        moments1 = CircuitComparator.get_moments(prev_dag)
 74        moments2 = CircuitComparator.get_moments(curr_dag)
 75
 76        CircuitComparator.make_lcs(moments1, moments2)
 77
 78        (size_1, size_2) = (len(moments1), len(moments2))
 79
 80        id_set = set()
 81        i = size_1
 82        j = size_2
 83
 84        while i > 0 and j > 0:
 85            if moments1[i - 1] == moments2[j - 1]:
 86                # just want diff for second one
 87                id_set.add(j - 1)
 88                i -= 1
 89                j -= 1
 90
 91            else:
 92                if LCS_DP[i - 1][j] > LCS_DP[i][j - 1]:
 93                    # means the graph came from the
 94                    # first circuit , go up
 95                    i -= 1
 96                else:
 97                    # if equal or small, go left
 98                    j -= 1
 99
100        # if the whole circuit has not changed
101        fully_changed = len(id_set) == 0
102
103        if not fully_changed:
104            for id2, layer in enumerate(list(curr_dag.layers())):
105                if id2 not in id_set:
106                    # this is not an LCS node -> highlight it
107                    for node in layer["graph"].front_layer():
108                        node.name = node.name + " "
109
110        return (fully_changed, dag_to_circuit(curr_dag))

Compares two quantum circuits and generates the circuit level diffs using longest common subsequences.

@staticmethod
def get_moments(dag):
16    @staticmethod
17    def get_moments(dag):
18        """Returns the layers of the dag circuit as list
19
20        Args:
21            dag (DAGCircuit): DAGCircuit representing a quantum circuit
22
23        Returns:
24            List: list of depth-1 circuits as graphs
25        """
26        moments = [l["graph"] for l in list(dag.layers())]
27        return moments

Returns the layers of the dag circuit as list

Args: dag (DAGCircuit): DAGCircuit representing a quantum circuit

Returns: List: list of depth-1 circuits as graphs

@staticmethod
def make_lcs(moments1, moments2):
29    @staticmethod
30    def make_lcs(moments1, moments2):
31        """Populates the LCS table by comparing the
32        first circuit's layers with the second
33
34        Args:
35            moments1 (List): list of depth-1 layers
36            moments2 (List): list of depth-1 layers
37        """
38
39        # clear for the base cases of dp
40        for i in range(2000):
41            LCS_DP[i][0], LCS_DP[0][i] = 0, 0
42
43        size_1, size_2 = len(moments1), len(moments2)
44
45        for i in range(1, size_1 + 1):
46            for j in range(1, size_2 + 1):
47                # if the layers are isomorphic then okay
48                if moments1[i - 1] == moments2[j - 1]:
49                    LCS_DP[i][j] = 1 + LCS_DP[i - 1][j - 1]
50                else:
51                    LCS_DP[i][j] = max(LCS_DP[i - 1][j], LCS_DP[i][j - 1])

Populates the LCS table by comparing the first circuit's layers with the second

Args: moments1 (List): list of depth-1 layers moments2 (List): list of depth-1 layers

@staticmethod
def compare(prev_circ, curr_circ):
 53    @staticmethod
 54    def compare(prev_circ, curr_circ):
 55        """Compares two circuits and returns the circuit diff as a
 56        quantum circuit with changed colors of diff
 57
 58        Args:
 59            prev_circ (QuantumCircuit): first circuit
 60            curr_circ (QuantumCircuit): second circuit
 61
 62        Returns:
 63            QuantumCircuit: the quantum circuit representing the
 64                            circuit diff
 65        """
 66        if prev_circ is None:
 67            return (False, curr_circ)
 68
 69        # update by reference as there is no qasm now
 70        prev_dag = circuit_to_dag(prev_circ.copy())
 71        curr_dag = circuit_to_dag(curr_circ.copy())
 72
 73        moments1 = CircuitComparator.get_moments(prev_dag)
 74        moments2 = CircuitComparator.get_moments(curr_dag)
 75
 76        CircuitComparator.make_lcs(moments1, moments2)
 77
 78        (size_1, size_2) = (len(moments1), len(moments2))
 79
 80        id_set = set()
 81        i = size_1
 82        j = size_2
 83
 84        while i > 0 and j > 0:
 85            if moments1[i - 1] == moments2[j - 1]:
 86                # just want diff for second one
 87                id_set.add(j - 1)
 88                i -= 1
 89                j -= 1
 90
 91            else:
 92                if LCS_DP[i - 1][j] > LCS_DP[i][j - 1]:
 93                    # means the graph came from the
 94                    # first circuit , go up
 95                    i -= 1
 96                else:
 97                    # if equal or small, go left
 98                    j -= 1
 99
100        # if the whole circuit has not changed
101        fully_changed = len(id_set) == 0
102
103        if not fully_changed:
104            for id2, layer in enumerate(list(curr_dag.layers())):
105                if id2 not in id_set:
106                    # this is not an LCS node -> highlight it
107                    for node in layer["graph"].front_layer():
108                        node.name = node.name + " "
109
110        return (fully_changed, dag_to_circuit(curr_dag))

Compares two circuits and returns the circuit diff as a quantum circuit with changed colors of diff

Args: prev_circ (QuantumCircuit): first circuit curr_circ (QuantumCircuit): second circuit

Returns: QuantumCircuit: the quantum circuit representing the circuit diff