def test_random_pauli(self): """Test the Random Pauli circuit.""" circuit = PauliTwoDesign(4, seed=12, reps=1) qr = QuantumRegister(4, "q") params = circuit.ordered_parameters # expected circuit for the random seed 12 expected = QuantumCircuit(qr) # initial RYs expected.ry(np.pi / 4, qr) # first random Pauli layer expected.ry(params[0], 0) expected.rx(params[1], 1) expected.rz(params[2], 2) expected.rz(params[3], 3) # entanglement expected.cz(0, 1) expected.cz(2, 3) expected.cz(1, 2) # second random Pauli layer expected.rx(params[4], 0) expected.rx(params[5], 1) expected.rx(params[6], 2) expected.rx(params[7], 3) self.assertEqual(circuit.decompose(), expected)
def test_assign_keeps_one_initial_layer(self): """Test assigning parameters does not add an additional initial layer.""" circuit = PauliTwoDesign(2) values = list(range(circuit.num_parameters)) bound0 = circuit.assign_parameters(values) bound1 = circuit.assign_parameters(values) bound2 = circuit.assign_parameters(values) self.assertEqual(bound0, bound1) self.assertEqual(bound0, bound2)
def test_resize(self): """Test resizing the Random Pauli circuit preserves the gates.""" circuit = PauliTwoDesign(1) top_gates = [op.name for op, _, _ in circuit.data] circuit.num_qubits = 3 with self.subTest('assert existing gates remain'): new_top_gates = [] for op, qargs, _ in circuit: if qargs == [circuit.qubits[0]]: # if top qubit new_top_gates.append(op.name) self.assertEqual(top_gates, new_top_gates)
def test_pauli_two_design(self): """Test standard gradient descent on the Pauli two-design example.""" circuit = PauliTwoDesign(3, reps=3, seed=2) parameters = list(circuit.parameters) obs = Z ^ Z ^ I expr = ~StateFn(obs) @ StateFn(circuit) initial_point = np.array([ 0.1822308, -0.27254251, 0.83684425, 0.86153976, -0.7111668, 0.82766631, 0.97867993, 0.46136964, 2.27079901, 0.13382699, 0.29589915, 0.64883193, ]) def objective(x): return expr.bind_parameters(dict(zip(parameters, x))).eval().real optimizer = GradientDescent(maxiter=100, learning_rate=0.1, perturbation=0.1) result = optimizer.optimize(circuit.num_parameters, objective, initial_point=initial_point) self.assertLess(result[1], -0.95) # final loss self.assertEqual(result[2], 100) # function evaluations
def test_resize(self): """Test resizing the Random Pauli circuit preserves the gates.""" circuit = PauliTwoDesign(1) top_gates = [ instruction.operation.name for instruction in circuit.decompose().data ] circuit.num_qubits = 3 decomposed = circuit.decompose() with self.subTest("assert existing gates remain"): new_top_gates = [] for instruction in decomposed: if instruction.qubits == ( decomposed.qubits[0], ): # if top qubit new_top_gates.append(instruction.operation.name) self.assertEqual(top_gates, new_top_gates)
def test_random_pauli(self): """Test the Random Pauli circuit.""" circuit = PauliTwoDesign(4, seed=12, reps=1) qr = QuantumRegister(4, "q") params = circuit.ordered_parameters # expected circuit for the random seed 12 # # ┌─────────┐┌──────────┐ ┌──────────┐ # q_0: ┤ Ry(π/4) ├┤ Ry(θ[0]) ├─■─┤ Rx(θ[4]) ├──────────── # ├─────────┤├──────────┤ │ └──────────┘┌──────────┐ # q_1: ┤ Ry(π/4) ├┤ Rx(θ[1]) ├─■──────■──────┤ Rx(θ[5]) ├ # ├─────────┤├──────────┤ │ ├──────────┤ # q_2: ┤ Ry(π/4) ├┤ Rz(θ[2]) ├─■──────■──────┤ Rx(θ[6]) ├ # ├─────────┤├──────────┤ │ ┌──────────┐└──────────┘ # q_3: ┤ Ry(π/4) ├┤ Rz(θ[3]) ├─■─┤ Rx(θ[7]) ├──────────── # └─────────┘└──────────┘ └──────────┘ expected = QuantumCircuit(qr) # initial RYs expected.ry(np.pi / 4, qr) # first random Pauli layer expected.ry(params[0], 0) expected.rx(params[1], 1) expected.rz(params[2], 2) expected.rz(params[3], 3) # entanglement expected.cz(0, 1) expected.cz(2, 3) expected.cz(1, 2) # second random Pauli layer expected.rx(params[4], 0) expected.rx(params[5], 1) expected.rx(params[6], 2) expected.rx(params[7], 3) self.assertEqual(circuit.decompose(), expected)
def test_pauli_two_design(self, method): """Test SPSA on the Pauli two-design example.""" circuit = PauliTwoDesign(3, reps=1, seed=1) parameters = list(circuit.parameters) obs = Z ^ Z ^ I expr = ~StateFn(obs) @ StateFn(circuit) initial_point = np.array([ 0.82311034, 0.02611798, 0.21077064, 0.61842177, 0.09828447, 0.62013131 ]) def objective(x): return expr.bind_parameters(dict(zip(parameters, x))).eval().real settings = {"maxiter": 100, "blocking": True, "allowed_increase": 0} if method == "2spsa": settings["second_order"] = True settings["regularization"] = 0.01 expected_nfev = settings["maxiter"] * 5 + 1 elif method == "qnspsa": settings["fidelity"] = QNSPSA.get_fidelity(circuit) settings["regularization"] = 0.001 settings["learning_rate"] = 0.05 settings["perturbation"] = 0.05 expected_nfev = settings["maxiter"] * 7 + 1 else: expected_nfev = settings["maxiter"] * 3 + 1 if method == "qnspsa": spsa = QNSPSA(**settings) else: spsa = SPSA(**settings) with self.assertWarns(DeprecationWarning): result = spsa.optimize(circuit.num_parameters, objective, initial_point=initial_point) with self.subTest("check final accuracy"): self.assertLess(result[1], -0.95) # final loss with self.subTest("check number of function calls"): self.assertEqual(result[2], expected_nfev) # function evaluations