class TestParameterCtrlState(QiskitTestCase): """Test gate equality with ctrl_state parameter.""" @data((RXGate(0.5), CRXGate(0.5)), (RYGate(0.5), CRYGate(0.5)), (RZGate(0.5), CRZGate(0.5)), (XGate(), CXGate()), (YGate(), CYGate()), (ZGate(), CZGate()), (U1Gate(0.5), CU1Gate(0.5)), (SwapGate(), CSwapGate()), (HGate(), CHGate()), (U3Gate(0.1, 0.2, 0.3), CU3Gate(0.1, 0.2, 0.3))) @unpack def test_ctrl_state_one(self, gate, controlled_gate): """Test controlled gates with ctrl_state See https://github.com/Qiskit/qiskit-terra/pull/4025 """ self.assertEqual(gate.control(1, ctrl_state='1'), controlled_gate)
class TestNLocal(QiskitTestCase): """Test the n-local circuit class.""" def test_if_reps_is_zero(self): """Test to check if error is raised for 0 or negative value of reps""" with self.assertRaises(ValueError): _ = NLocal(reps=-1) def test_reps_setter_when_negative(self): """Test to check if setter raises error for reps <=0""" nlocal = NLocal(reps=1) with self.assertRaises(ValueError): nlocal.reps = -1 def assertCircuitEqual(self, qc1, qc2, visual=False, transpiled=True): """An equality test specialized to circuits.""" if transpiled: basis_gates = ['id', 'u1', 'u3', 'cx'] qc1_transpiled = transpile(qc1, basis_gates=basis_gates, optimization_level=0) qc2_transpiled = transpile(qc2, basis_gates=basis_gates, optimization_level=0) qc1, qc2 = qc1_transpiled, qc2_transpiled if visual: self.assertEqual(qc1.draw(), qc2.draw()) else: self.assertEqual(qc1, qc2) def test_empty_nlocal(self): """Test the creation of an empty NLocal.""" nlocal = NLocal() self.assertEqual(nlocal.num_qubits, 0) self.assertEqual(nlocal.num_parameters_settable, 0) self.assertEqual(nlocal.reps, 1) self.assertEqual(nlocal, QuantumCircuit()) for attribute in [nlocal.rotation_blocks, nlocal.entanglement_blocks]: self.assertEqual(len(attribute), 0) @data((XGate(), [[0], [2], [1]]), (XGate(), [[0]]), (CRXGate(-0.2), [[2, 0], [1, 3]]), ) @unpack def test_add_layer_to_empty_nlocal(self, block, entangler_map): """Test appending gates to an empty nlocal.""" nlocal = NLocal() nlocal.add_layer(block, entangler_map) max_num_qubits = max(max(indices) for indices in entangler_map) reference = QuantumCircuit(max_num_qubits + 1) for indices in entangler_map: reference.append(block, indices) self.assertCircuitEqual(nlocal, reference) @data([5, 3], [1, 5], [1, 1], [1, 2, 3, 10]) def test_append_circuit(self, num_qubits): """Test appending circuits to an nlocal works normally.""" # fixed depth of 3 gates per circuit depth = 3 # keep track of a reference circuit reference = QuantumCircuit(max(num_qubits)) # construct the NLocal from the first circuit first_circuit = random_circuit(num_qubits[0], depth, seed=4200) # TODO Terra bug: if this is to_gate it fails, since the QC adds an instruction not gate nlocal = NLocal(max(num_qubits), entanglement_blocks=first_circuit.to_instruction(), reps=1) reference.append(first_circuit, list(range(num_qubits[0]))) # append the rest for num in num_qubits[1:]: circuit = random_circuit(num, depth, seed=4200) nlocal.append(circuit, list(range(num))) reference.append(circuit, list(range(num))) self.assertCircuitEqual(nlocal, reference) @data([5, 3], [1, 5], [1, 1], [1, 2, 3, 10]) def test_add_nlocal(self, num_qubits): """Test adding an nlocal to an nlocal (using add_layer).""" # fixed depth of 3 gates per circuit depth = 3 # keep track of a reference circuit reference = QuantumCircuit(max(num_qubits)) # construct the NLocal from the first circuit first_circuit = random_circuit(num_qubits[0], depth, seed=4220) # TODO Terra bug: if this is to_gate it fails, since the QC adds an instruction not gate nlocal = NLocal(max(num_qubits), entanglement_blocks=first_circuit.to_instruction(), reps=1) reference.append(first_circuit, list(range(num_qubits[0]))) # append the rest for num in num_qubits[1:]: circuit = random_circuit(num, depth, seed=4220) nlocal.add_layer(NLocal(num, entanglement_blocks=circuit, reps=1)) reference.append(circuit, list(range(num))) self.assertCircuitEqual(nlocal, reference) @unittest.skip('Feature missing') def test_iadd_overload(self): """Test the overloaded + operator.""" num_qubits, depth = 2, 2 # construct two circuits for adding first_circuit = random_circuit(num_qubits, depth, seed=4242) circuit = random_circuit(num_qubits, depth, seed=4242) # get a reference reference = first_circuit + circuit # convert the object to be appended to different types others = [circuit, circuit.to_instruction(), circuit.to_gate(), NLocal(circuit)] # try adding each type for other in others: nlocal = NLocal(num_qubits, entanglement_blocks=first_circuit, reps=1) nlocal += other with self.subTest(msg='type: {}'.format(type(other))): self.assertCircuitEqual(nlocal, reference) def test_parameter_getter_from_automatic_repetition(self): """Test getting and setting of the nlocal parameters.""" circuit = QuantumCircuit(2) circuit.ry(Parameter('a'), 0) circuit.crx(Parameter('b'), 0, 1) # repeat circuit and check that parameters are duplicated reps = 3 nlocal = NLocal(2, entanglement_blocks=circuit, reps=reps) self.assertTrue(nlocal.num_parameters, 6) self.assertTrue(len(nlocal.parameters), 6) @data(list(range(6)), ParameterVector('θ', length=6), [0, 1, Parameter('theta'), 3, 4, 5]) def test_parameter_setter_from_automatic_repetition(self, params): """Test getting and setting of the nlocal parameters.""" circuit = QuantumCircuit(2) circuit.ry(Parameter('a'), 0) circuit.crx(Parameter('b'), 0, 1) # repeat circuit and check that parameters are duplicated reps = 3 nlocal = NLocal(2, entanglement_blocks=circuit, reps=reps) nlocal.assign_parameters(params, inplace=True) param_set = set(p for p in params if isinstance(p, ParameterExpression)) with self.subTest(msg='Test the parameters of the non-transpiled circuit'): # check the parameters of the final circuit self.assertEqual(nlocal.parameters, param_set) with self.subTest(msg='Test the parameters of the transpiled circuit'): basis_gates = ['id', 'u1', 'u2', 'u3', 'cx'] transpiled_circuit = transpile(nlocal, basis_gates=basis_gates) self.assertEqual(transpiled_circuit.parameters, param_set) @data(list(range(6)), ParameterVector('θ', length=6), [0, 1, Parameter('theta'), 3, 4, 5]) def test_parameters_setter(self, params): """Test setting the parameters via list.""" # construct circuit with some parameters initial_params = ParameterVector('p', length=6) circuit = QuantumCircuit(1) for i, initial_param in enumerate(initial_params): circuit.ry(i * initial_param, 0) # create an NLocal from the circuit and set the new parameters nlocal = NLocal(1, entanglement_blocks=circuit, reps=1) nlocal.assign_parameters(params, inplace=True) param_set = set(p for p in params if isinstance(p, ParameterExpression)) with self.subTest(msg='Test the parameters of the non-transpiled circuit'): # check the parameters of the final circuit self.assertEqual(nlocal.parameters, param_set) with self.subTest(msg='Test the parameters of the transpiled circuit'): basis_gates = ['id', 'u1', 'u2', 'u3', 'cx'] transpiled_circuit = transpile(nlocal, basis_gates=basis_gates) self.assertEqual(transpiled_circuit.parameters, param_set) def test_repetetive_parameter_setting(self): """Test alternate setting of parameters and circuit construction.""" x = Parameter('x') circuit = QuantumCircuit(1) circuit.rx(x, 0) nlocal = NLocal(1, entanglement_blocks=circuit, reps=3, insert_barriers=True) with self.subTest(msg='immediately after initialization'): self.assertEqual(len(nlocal.parameters), 3) with self.subTest(msg='after circuit construction'): self.assertEqual(len(nlocal.parameters), 3) q = Parameter('q') nlocal.assign_parameters([x, q, q], inplace=True) with self.subTest(msg='setting parameter to Parameter objects'): self.assertEqual(nlocal.parameters, set({x, q})) nlocal.assign_parameters([0, -1], inplace=True) with self.subTest(msg='setting parameter to numbers'): self.assertEqual(nlocal.parameters, set()) def test_skip_unentangled_qubits(self): """Test skipping the unentangled qubits.""" num_qubits = 6 entanglement_1 = [[0, 1, 3], [1, 3, 5], [0, 1, 5]] skipped_1 = [2, 4] entanglement_2 = [ entanglement_1, [[0, 1, 2], [2, 3, 5]] ] skipped_2 = [4] for entanglement, skipped in zip([entanglement_1, entanglement_2], [skipped_1, skipped_2]): with self.subTest(entanglement=entanglement, skipped=skipped): nlocal = NLocal(num_qubits, rotation_blocks=XGate(), entanglement_blocks=CCXGate(), entanglement=entanglement, reps=3, skip_unentangled_qubits=True) skipped_set = set(nlocal.qubits[i] for i in skipped) dag = circuit_to_dag(nlocal) idle = set(dag.idle_wires()) self.assertEqual(skipped_set, idle) @data('linear', 'full', 'circular', 'sca', ['linear', 'full'], ['circular', 'linear', 'sca']) def test_entanglement_by_str(self, entanglement): """Test setting the entanglement of the layers by str.""" reps = 3 nlocal = NLocal(5, rotation_blocks=XGate(), entanglement_blocks=CCXGate(), entanglement=entanglement, reps=reps) def get_expected_entangler_map(rep_num, mode): if mode == 'linear': return [(0, 1, 2), (1, 2, 3), (2, 3, 4)] elif mode == 'full': return [(0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)] else: circular = [(3, 4, 0), (0, 1, 2), (1, 2, 3), (2, 3, 4)] if mode == 'circular': return circular sca = circular[-rep_num:] + circular[:-rep_num] if rep_num % 2 == 1: sca = [tuple(reversed(indices)) for indices in sca] return sca for rep_num in range(reps): entangler_map = nlocal.get_entangler_map(rep_num, 0, 3) if isinstance(entanglement, list): mode = entanglement[rep_num % len(entanglement)] else: mode = entanglement expected = get_expected_entangler_map(rep_num, mode) with self.subTest(rep_num=rep_num): # using a set here since the order does not matter self.assertEqual(set(entangler_map), set(expected)) def test_pairwise_entanglement(self): """Test pairwise entanglement.""" nlocal = NLocal(5, rotation_blocks=XGate(), entanglement_blocks=CXGate(), entanglement='pairwise', reps=1) entangler_map = nlocal.get_entangler_map(0, 0, 2) pairwise = [(0, 1), (2, 3), (1, 2), (3, 4)] self.assertEqual(pairwise, entangler_map) def test_pairwise_entanglement_raises(self): """Test choosing pairwise entanglement raises an error for too large blocks.""" nlocal = NLocal(3, XGate(), CCXGate(), entanglement='pairwise', reps=1) # pairwise entanglement is only defined if the entangling gate has 2 qubits with self.assertRaises(ValueError): print(nlocal.draw()) def test_entanglement_by_list(self): """Test setting the entanglement by list. This is the circuit we test (times 2, with final X layer) ┌───┐ ┌───┐┌───┐ ┌───┐ q_0: |0>┤ X ├──■────■───X────┤ X ├┤ X ├──■───X─────── .. ┤ X ├ ├───┤ │ │ │ ├───┤└─┬─┘ │ │ ├───┤ q_1: |0>┤ X ├──■────┼───┼──X─┤ X ├──■────┼───X──X──── .. ┤ X ├ ├───┤┌─┴─┐ │ │ │ ├───┤ │ │ │ x2 ├───┤ q_2: |0>┤ X ├┤ X ├──■───┼──X─┤ X ├──■────■──────X──X─ .. ┤ X ├ ├───┤└───┘┌─┴─┐ │ ├───┤ ┌─┴─┐ │ ├───┤ q_3: |0>┤ X ├─────┤ X ├─X────┤ X ├─────┤ X ├───────X─ .. ┤ X ├ └───┘ └───┘ └───┘ └───┘ └───┘ """ circuit = QuantumCircuit(4) for _ in range(2): circuit.x([0, 1, 2, 3]) circuit.barrier() circuit.ccx(0, 1, 2) circuit.ccx(0, 2, 3) circuit.swap(0, 3) circuit.swap(1, 2) circuit.barrier() circuit.x([0, 1, 2, 3]) circuit.barrier() circuit.ccx(2, 1, 0) circuit.ccx(0, 2, 3) circuit.swap(0, 1) circuit.swap(1, 2) circuit.swap(2, 3) circuit.barrier() circuit.x([0, 1, 2, 3]) layer_1_ccx = [(0, 1, 2), (0, 2, 3)] layer_1_swap = [(0, 3), (1, 2)] layer_1 = [layer_1_ccx, layer_1_swap] layer_2_ccx = [(2, 1, 0), (0, 2, 3)] layer_2_swap = [(0, 1), (1, 2), (2, 3)] layer_2 = [layer_2_ccx, layer_2_swap] entanglement = [layer_1, layer_2] nlocal = NLocal(4, rotation_blocks=XGate(), entanglement_blocks=[CCXGate(), SwapGate()], reps=4, entanglement=entanglement, insert_barriers=True) self.assertCircuitEqual(nlocal, circuit)
def test_controlled_rx(self): """Test the creation of a controlled RX gate.""" theta = 0.5 self.assertEqual(RXGate(theta).control(), CRXGate(theta))