def test_topological_nodes(self): """The topological_nodes() method""" self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2], []) self.dag.apply_operation_back(HGate(), [self.qubit2], []) named_nodes = self.dag.topological_nodes() expected = [('qr[0]', []), ('qr[1]', []), ('cx', [self.qubit0, self.qubit1]), ('h', [self.qubit0]), ('qr[2]', []), ('cx', [self.qubit2, self.qubit1]), ('cx', [self.qubit0, self.qubit2]), ('h', [self.qubit2]), ('qr[0]', []), ('qr[1]', []), ('qr[2]', []), ('cr[0]', []), ('cr[0]', []), ('cr[1]', []), ('cr[1]', [])] self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes])
def _define(self): """ gate rccx a,b,c { u2(0,pi) c; u1(pi/4) c; cx b, c; u1(-pi/4) c; cx a, c; u1(pi/4) c; cx b, c; u1(-pi/4) c; u2(0,pi) c; } """ definition = [] q = QuantumRegister(3, 'q') rule = [ (U2Gate(0, pi), [q[2]], []), # H gate (U1Gate(pi / 4), [q[2]], []), # T gate (CXGate(), [q[1], q[2]], []), (U1Gate(-pi / 4), [q[2]], []), # inverse T gate (CXGate(), [q[0], q[2]], []), (U1Gate(pi / 4), [q[2]], []), (CXGate(), [q[1], q[2]], []), (U1Gate(-pi / 4), [q[2]], []), # inverse T gate (U2Gate(0, pi), [q[2]], []), # H gate ] for inst in rule: definition.append(inst) self.definition = definition
def _define(self): """ gate cu3(theta,phi,lambda) c, t { u1((lambda+phi)/2) c; u1((lambda-phi)/2) t; cx c,t; u3(-theta/2,0,-(phi+lambda)/2) t; cx c,t; u3(theta/2,phi,0) t; } """ from qiskit.extensions.standard.u1 import U1Gate from qiskit.extensions.standard.x import CXGate definition = [] q = QuantumRegister(2, 'q') rule = [ (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) ] for inst in rule: definition.append(inst) self.definition = definition
def test_dag_collect_runs(self): """Test the collect_runs method with 3 different gates.""" self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1]) self.dag.apply_operation_back(CXGate(), [self.qubit1, self.qubit2]) self.dag.apply_operation_back(HGate(), [self.qubit2]) collected_runs = self.dag.collect_runs(['u1', 'cx', 'h']) self.assertEqual(len(collected_runs), 3) for run in collected_runs: if run[0].name == 'cx': self.assertEqual(len(run), 2) self.assertEqual(['cx'] * 2, [x.name for x in run]) self.assertEqual( [[self.qubit2, self.qubit1], [self.qubit1, self.qubit2]], [x.qargs for x in run]) elif run[0].name == 'h': self.assertEqual(len(run), 1) self.assertEqual(['h'], [x.name for x in run]) self.assertEqual([[self.qubit2]], [x.qargs for x in run]) elif run[0].name == 'u1': self.assertEqual(len(run), 3) self.assertEqual(['u1'] * 3, [x.name for x in run]) self.assertEqual([[self.qubit0], [self.qubit0], [self.qubit0]], [x.qargs for x in run]) else: self.fail('Unknown run encountered')
def _define(self): """ gate dcx a, b { cx a, b; cx a, b; } """ from qiskit.extensions.standard.x import CXGate q = QuantumRegister(2, 'q') self.definition = [(CXGate(), [q[0], q[1]], []), (CXGate(), [q[1], q[0]], [])]
def _multiplex(self, target_gate, list_of_angles): """ Return a recursive implementation of a multiplexor circuit, where each instruction itself has a decomposition based on smaller multiplexors. The LSB is the multiplexor "data" and the other bits are multiplexor "select". Args: target_gate (Gate): Ry or Rz gate to apply to target qubit, multiplexed over all other "select" qubits list_of_angles (list[float]): list of rotation angles to apply Ry and Rz Returns: DAGCircuit: the circuit implementing the multiplexor's action """ list_len = len(list_of_angles) local_num_qubits = int(math.log2(list_len)) + 1 q = QuantumRegister(local_num_qubits) circuit = QuantumCircuit(q, name="multiplex" + local_num_qubits.__str__()) lsb = q[0] msb = q[local_num_qubits - 1] # case of no multiplexing: base case for recursion if local_num_qubits == 1: circuit.append(target_gate(list_of_angles[0]), [q[0]]) return circuit # calc angle weights, assuming recursion (that is the lower-level # requested angles have been correctly implemented by recursion angle_weight = np.kron([[0.5, 0.5], [0.5, -0.5]], np.identity(2 ** (local_num_qubits - 2))) # calc the combo angles list_of_angles = angle_weight.dot(np.array(list_of_angles)).tolist() # recursive step on half the angles fulfilling the above assumption multiplex_1 = self._multiplex(target_gate, list_of_angles[0:(list_len // 2)]) circuit.append(multiplex_1.to_instruction(), q[0:-1]) # attach CNOT as follows, thereby flipping the LSB qubit circuit.append(CXGate(), [msb, lsb]) # implement extra efficiency from the paper of cancelling adjacent # CNOTs (by leaving out last CNOT and reversing (NOT inverting) the # second lower-level multiplex) multiplex_2 = self._multiplex(target_gate, list_of_angles[(list_len // 2):]) if list_len > 1: circuit.append(multiplex_2.to_instruction().mirror(), q[0:-1]) else: circuit.append(multiplex_2.to_instruction(), q[0:-1]) # attach a final CNOT circuit.append(CXGate(), [msb, lsb]) return circuit
def _define(self): """ gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} """ from qiskit.extensions.standard.u1 import U1Gate from qiskit.extensions.standard.h import HGate from qiskit.extensions.standard.x import CXGate q = QuantumRegister(2, 'q') self.definition = [(HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U1Gate(self.params[0]), [q[1]], []), (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], [])]
def _define(self): """ gate aswap a,b { cx b,a; cx a,b; } """ from qiskit.extensions.standard.x import CXGate definition = [] q = QuantumRegister(2, "q") rule = [(CXGate(), [q[1], q[0]], []), (CXGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def _define(self): """ gate rzz(theta) a, b { cx a, b; rz(theta) b; cx a, b; } """ from qiskit.extensions.standard.rz import RZGate from qiskit.extensions.standard.x import CXGate definition = [] q = QuantumRegister(2, 'q') rule = [(CXGate(), [q[0], q[1]], []), (RZGate(self.params[0]), [q[1]], []), (CXGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_remove_op_node_longer(self): """Test remove_op_node method in a "longer" dag""" self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1]) self.dag.apply_operation_back(HGate(), [self.qubit0]) self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1]) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2]) self.dag.apply_operation_back(HGate(), [self.qubit2]) op_nodes = list(self.dag.topological_op_nodes()) self.dag.remove_op_node(op_nodes[0]) expected = [('h', [self.qubit0]), ('cx', [self.qubit2, self.qubit1]), ('cx', [self.qubit0, self.qubit2]), ('h', [self.qubit2])] self.assertEqual(expected, [(i.name, i.qargs) for i in self.dag.topological_op_nodes()])
def _process_cnot(self, node): """Process a CNOT gate node.""" id0 = self._process_bit_id(node.children[0]) id1 = self._process_bit_id(node.children[1]) if not (len(id0) == len(id1) or len(id0) == 1 or len(id1) == 1): raise QiskitError("internal error: qreg size mismatch", "line=%s" % node.line, "file=%s" % node.file) maxidx = max([len(id0), len(id1)]) for idx in range(maxidx): if len(id0) > 1 and len(id1) > 1: self.dag.apply_operation_back(CXGate(), [id0[idx], id1[idx]], [], self.condition) elif len(id0) > 1: self.dag.apply_operation_back(CXGate(), [id0[idx], id1[0]], [], self.condition) else: self.dag.apply_operation_back(CXGate(), [id0[0], id1[idx]], [], self.condition)
def test_layers_basic(self): """The layers() method returns a list of layers, each of them with a list of nodes.""" qreg = QuantumRegister(2, 'qr') creg = ClassicalRegister(2, 'cr') qubit0 = qreg[0] qubit1 = qreg[1] clbit0 = creg[0] clbit1 = creg[1] condition = (creg, 3) dag = DAGCircuit() dag.add_qreg(qreg) dag.add_creg(creg) dag.apply_operation_back(HGate(), [qubit0], []) dag.apply_operation_back(CXGate(), [qubit0, qubit1], [], condition=None) dag.apply_operation_back(Measure(), [qubit1, clbit1], [], condition=None) dag.apply_operation_back(XGate(), [qubit1], [], condition=condition) dag.apply_operation_back(Measure(), [qubit0, clbit0], [], condition=None) dag.apply_operation_back(Measure(), [qubit1, clbit1], [], condition=None) layers = list(dag.layers()) self.assertEqual(5, len(layers)) name_layers = [[ node.op.name for node in layer["graph"].nodes() if node.type == "op" ] for layer in layers] self.assertEqual( [['h'], ['cx'], ['measure'], ['x'], ['measure', 'measure']], name_layers)
def test_substituting_node_preserves_args_condition(self, inplace): """Verify args and condition are preserved by a substitution.""" dag = DAGCircuit() qr = QuantumRegister(2) cr = ClassicalRegister(1) dag.add_qreg(qr) dag.add_creg(cr) dag.apply_operation_back(HGate(), [qr[1]]) node_to_be_replaced = dag.apply_operation_back(CXGate(), [qr[1], qr[0]], condition=(cr, 1)) dag.apply_operation_back(HGate(), [qr[1]]) replacement_node = dag.substitute_node(node_to_be_replaced, CZGate(), inplace=inplace) raise_if_dagcircuit_invalid(dag) self.assertEqual(replacement_node.name, 'cz') self.assertEqual(replacement_node.qargs, [qr[1], qr[0]]) self.assertEqual(replacement_node.cargs, []) self.assertEqual(replacement_node.condition, (cr, 1)) self.assertEqual(replacement_node is node_to_be_replaced, inplace)
def _define(self): """ gate ch a,b { s b; h b; t b; cx a, b; tdg b; h b; sdg b; } """ from qiskit.extensions.standard.x import CXGate definition = [] q = QuantumRegister(2, 'q') rule = [ (SGate(), [q[1]], []), (HGate(), [q[1]], []), (TGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), (TdgGate(), [q[1]], []), (HGate(), [q[1]], []), (SdgGate(), [q[1]], []) ] for inst in rule: definition.append(inst) self.definition = definition
def test_quantum_successors(self): """The method dag.quantum_successors() returns successors connected by quantum edges""" # q_0: |0>─────■───|0>─ # ┌─┐┌─┴─┐ # q_1: |0>┤M├┤ X ├───── # └╥┘└───┘ # c_0: 0 ═╬═══════════ # ║ # c_1: 0 ═╩═══════════ self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) successor_measure = self.dag.quantum_successors( self.dag.named_nodes('measure').pop()) cnot_node = next(successor_measure) with self.assertRaises(StopIteration): next(successor_measure) self.assertIsInstance(cnot_node.op, CXGate) successor_cnot = self.dag.quantum_successors(cnot_node) # Ordering between Reset and out[q1] is indeterminant. successor1 = next(successor_cnot) successor2 = next(successor_cnot) with self.assertRaises(StopIteration): next(successor_cnot) self.assertTrue( (successor1.type == 'out' and isinstance(successor2.op, Reset)) or (successor2.type == 'out' and isinstance(successor1.op, Reset)))
def test_instructions_equal(self): """Test equality of two instructions.""" hop1 = Instruction('h', 1, 0, []) hop2 = Instruction('s', 1, 0, []) hop3 = Instruction('h', 1, 0, []) self.assertFalse(hop1 == hop2) self.assertTrue(hop1 == hop3) uop1 = Instruction('u', 1, 0, [0.4, 0.5, 0.5]) uop2 = Instruction('u', 1, 0, [0.4, 0.6, 0.5]) uop3 = Instruction('v', 1, 0, [0.4, 0.5, 0.5]) uop4 = Instruction('u', 1, 0, [0.4, 0.5, 0.5]) self.assertFalse(uop1 == uop2) self.assertTrue(uop1 == uop4) self.assertFalse(uop1 == uop3) self.assertTrue(HGate() == HGate()) self.assertFalse(HGate() == CXGate()) self.assertFalse(hop1 == HGate()) eop1 = Instruction('kraus', 1, 0, [np.array([[1, 0], [0, 1]])]) eop2 = Instruction('kraus', 1, 0, [np.array([[0, 1], [1, 0]])]) eop3 = Instruction('kraus', 1, 0, [np.array([[1, 0], [0, 1]])]) eop4 = Instruction('kraus', 1, 0, [np.eye(4)]) self.assertTrue(eop1 == eop3) self.assertFalse(eop1 == eop2) self.assertFalse(eop1 == eop4)
def _gray_code_chain(q, num_ctrl_qubits, gate): """Apply the gate to the the last qubit in the register ``q``, controlled on all preceding qubits. This function uses the gray code to propagate down to the last qubit. Ported and adapted from Aqua (github.com/Qiskit/qiskit-aqua), commit 769ca8d, file qiskit/aqua/circuits/gates/multi_control_u1_gate.py. """ from qiskit.extensions.standard.x import CXGate rule = [] q_controls, q_target = q[:num_ctrl_qubits], q[num_ctrl_qubits] gray_code = _generate_gray_code(num_ctrl_qubits) last_pattern = None for pattern in gray_code: if '1' not in pattern: continue if last_pattern is None: last_pattern = pattern # find left most set bit lm_pos = list(pattern).index('1') # find changed bit comp = [i != j for i, j in zip(pattern, last_pattern)] if True in comp: pos = comp.index(True) else: pos = None if pos is not None: if pos != lm_pos: rule.append((CXGate(), [q_controls[pos], q_controls[lm_pos]], [])) else: indices = [i for i, x in enumerate(pattern) if x == '1'] for idx in indices[1:]: rule.append( (CXGate(), [q_controls[idx], q_controls[lm_pos]], [])) # check parity if pattern.count('1') % 2 == 0: # inverse rule.append((gate.inverse(), [q_controls[lm_pos], q_target], [])) else: rule.append((gate, [q_controls[lm_pos], q_target], [])) last_pattern = pattern return rule
def _define(self): """ gate cswap a,b,c { cx c,b; ccx a,b,c; cx c,b; } """ from qiskit.extensions.standard.x import CXGate from qiskit.extensions.standard.x import CCXGate definition = [] q = QuantumRegister(3, 'q') rule = [(CXGate(), [q[2], q[1]], []), (CCXGate(), [q[0], q[1], q[2]], []), (CXGate(), [q[2], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_substituting_node_with_wrong_width_node_raises(self): """Verify replacing a node with one of a different shape raises.""" dag = DAGCircuit() qr = QuantumRegister(2) dag.add_qreg(qr) node_to_be_replaced = dag.apply_operation_back(CXGate(), [qr[0], qr[1]]) with self.assertRaises(DAGCircuitError) as _: dag.substitute_node(node_to_be_replaced, Measure())
def _define(self): """ gate crz(lambda) a,b { u1(lambda/2) b; cx a,b; u1(-lambda/2) b; cx a,b; } """ from qiskit.extensions.standard.u1 import U1Gate from qiskit.extensions.standard.x import CXGate definition = [] q = QuantumRegister(2, 'q') rule = [(U1Gate(self.params[0] / 2), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U1Gate(-self.params[0] / 2), [q[1]], []), (CXGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_get_named_nodes(self): """The get_named_nodes(AName) method returns all the nodes with name AName""" self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2], []) self.dag.apply_operation_back(HGate(), [self.qubit2], []) # The ordering is not assured, so we only compare the output (unordered) sets. # We use tuples because lists aren't hashable. named_nodes = self.dag.named_nodes('cx') node_qargs = {tuple(node.qargs) for node in named_nodes} expected_qargs = {(self.qubit0, self.qubit1), (self.qubit2, self.qubit1), (self.qubit0, self.qubit2)} self.assertEqual(expected_qargs, node_qargs)
def _define(self): """ gate iswap a,b { s q[0]; s q[1]; h q[0]; cx q[0],q[1]; cx q[1],q[0]; h q[1]; } """ from qiskit.extensions.standard.h import HGate from qiskit.extensions.standard.s import SGate from qiskit.extensions.standard.x import CXGate q = QuantumRegister(2, 'q') self.definition = [(SGate(), [q[0]], []), (SGate(), [q[1]], []), (HGate(), [q[0]], []), (CXGate(), [q[0], q[1]], []), (CXGate(), [q[1], q[0]], []), (HGate(), [q[1]], [])]
def test_apply_operation_back(self): """The apply_operation_back() method.""" self.dag.apply_operation_back(HGate(), [self.qubit0], [], condition=None) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [], condition=None) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None) self.dag.apply_operation_back(XGate(), [self.qubit1], [], condition=self.condition) self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], [], condition=None) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None) self.assertEqual(len(list(self.dag.nodes())), 16) self.assertEqual(len(list(self.dag.edges())), 17)
def _define(self): """Calculate a subcircuit that implements this unitary.""" from qiskit.extensions.standard.x import CXGate from qiskit.extensions.standard.u1 import U1Gate from qiskit.extensions.standard.h import HGate definition = [] q = QuantumRegister(2, 'q') theta = self.params[0] rule = [ (HGate(), [q[0]], []), (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U1Gate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], []), (HGate(), [q[0]], []), ] for inst in rule: definition.append(inst) self.definition = definition
def test_get_op_nodes_all(self): """The method dag.op_nodes() returns all op nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.op_nodes() self.assertEqual(len(op_nodes), 3) for node in op_nodes: self.assertIsInstance(node.op, Instruction)
def test_dag_nodes_on_wire_multiple_successors(self): """ Test that if a DAGNode has multiple successors in the DAG along one wire, they are all retrieved in order. This could be the case for a circuit such as q0_0: |0>──■─────────■── ┌─┴─┐┌───┐┌─┴─┐ q0_1: |0>┤ X ├┤ H ├┤ X ├ └───┘└───┘└───┘ Both the 2nd CX gate and the H gate follow the first CX gate in the DAG, so they both must be returned but in the correct order. """ self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit1], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) nodes = self.dag.nodes_on_wire(self.dag.qubits()[1], only_ops=True) node_names = [nd.name for nd in nodes] self.assertEqual(node_names, ['cx', 'h', 'cx'])
def test_edges(self): """Test that DAGCircuit.edges() behaves as expected with ops.""" self.dag.apply_operation_back(HGate(), [self.qubit0], [], condition=None) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [], condition=None) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None) self.dag.apply_operation_back(XGate(), [self.qubit1], [], condition=self.condition) self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], [], condition=None) self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None) out_edges = self.dag.edges(self.dag.output_map.values()) self.assertEqual(list(out_edges), []) in_edges = self.dag.edges(self.dag.input_map.values()) # number of edges for input nodes should be the same as number of wires self.assertEqual(len(list(in_edges)), 5)
def test_two_q_gates(self): """The method dag.two_qubit_ops() returns all 2Q gate operation nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Barrier(2), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.two_qubit_ops() self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() self.assertIsInstance(op_node.op, Gate) self.assertEqual(len(op_node.qargs), 2)
def test_get_gates_nodes(self): """The method dag.gate_nodes() returns all gate nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.gate_nodes() self.assertEqual(len(op_nodes), 2) op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() self.assertIsInstance(op_node_1.op, Gate) self.assertIsInstance(op_node_2.op, Gate)
def test_substitute_circuit_one_middle(self): """The method substitute_node_with_dag() replaces a in-the-middle node with a DAG.""" cx_node = self.dag.op_nodes(op=CXGate).pop() flipped_cx_circuit = DAGCircuit() v = QuantumRegister(2, "v") flipped_cx_circuit.add_qreg(v) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[1]], []) flipped_cx_circuit.apply_operation_back(CXGate(), [v[1], v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[1]], []) self.dag.substitute_node_with_dag(cx_node, flipped_cx_circuit, wires=[v[0], v[1]]) self.assertEqual(self.dag.count_ops()['h'], 5)