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))
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.
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
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
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