def test_expand_on_state_fn(self): """ Test if expanded StateFn has expected num_qubits. """ num_qubits = 3 add_qubits = 2 # case CircuitStateFn, with primitive QuantumCircuit qc2 = QuantumCircuit(num_qubits) qc2.cx(0, 1) cfn = CircuitStateFn(qc2, is_measurement=True) cfn_exp = cfn._expand_dim(add_qubits) self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits) # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn osfn = OperatorStateFn(cfn) osfn_exp = osfn._expand_dim(add_qubits) self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits) # case DictStateFn dsfn = DictStateFn('1'*num_qubits, is_measurement=True) self.assertEqual(dsfn.num_qubits, num_qubits) dsfn_exp = dsfn._expand_dim(add_qubits) self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits) # case VectorStateFn vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex)) self.assertEqual(vsfn.num_qubits, num_qubits) vsfn_exp = vsfn._expand_dim(add_qubits) self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits)
def construct_circuit(self, parameters, q=None): """ construct circuit """ if not len(parameters) == self.num_parameters: raise ValueError( 'Incorrect number of angles: expecting {}, but {} given.'. format(self.num_parameters, len(parameters))) # initialize circuit, possibly based on given register/initial state if isinstance(self._initial_state, QuantumCircuit): circuit = CircuitStateFn(self._initial_state) elif self._initial_state is not None: circuit = CircuitStateFn( self._initial_state.construct_circuit('circuit')) else: circuit = (H ^ self._num_qubits) for idx in range(self._p): circuit = (self._cost_operator * parameters[idx]).exp_i().compose(circuit) circuit = (self._mixer_operator * parameters[idx + self._p]).exp_i().compose(circuit) evolution = EvolutionFactory.build(self._cost_operator) circuit = evolution.convert(circuit) return circuit.to_circuit()
def test_gradient_u(self, method): """Test the state gradient for U Tr(|psi><psi|Z) = - 0.5 sin(a)cos(c) Tr(|psi><psi|X) = cos^2(a/2) cos(b+c) - sin^2(a/2) cos(b-c) """ ham = 0.5 * X - 1 * Z a = Parameter('a') b = Parameter('b') c = Parameter('c') q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.u(a, b, c, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) params = [a, b, c] state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{ a: np.pi / 4, b: 0, c: 0 }, { a: np.pi / 4, b: np.pi / 4, c: np.pi / 4 }] correct_values = [[0.3536, 0, 0], [0.3232, -0.42678, -0.92678]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1) # Tr(|psi><psi|Z) = - 0.5 sin(a)cos(c) # Tr(|psi><psi|X) = cos^2(a/2) cos(b+c) - sin^2(a/2) cos(b-c) # dTr(|psi><psi|H)/da = 0.5(cos(2a)) + 0.5() q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.u(a, a, a, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) params = [a] state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4}, {a: np.pi / 2}] correct_values = [[-1.03033], [-1]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_jax_chain_rule(self, method: str, autograd: bool): """Test the chain rule functionality using Jax d<H>/d<X> = 2<X> d<H>/d<Z> = - sin(<Z>) <Z> = Tr(|psi><psi|Z) = sin(a)sin(b) <X> = Tr(|psi><psi|X) = cos(a) d<H>/da = d<H>/d<X> d<X>/da + d<H>/d<Z> d<Z>/da = - 2 cos(a)sin(a) - sin(sin(a)sin(b)) * cos(a)sin(b) d<H>/db = d<H>/d<X> d<X>/db + d<H>/d<Z> d<Z>/db = - sin(sin(a)sin(b)) * sin(a)cos(b) """ a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) def combo_fn(x): return jnp.power(x[0], 2) + jnp.cos(x[1]) def grad_combo_fn(x): return np.array([2 * x[0], -np.sin(x[1])]) op = ListOp([ ~StateFn(X) @ CircuitStateFn(primitive=qc, coeff=1.), ~StateFn(Z) @ CircuitStateFn(primitive=qc, coeff=1.) ], combo_fn=combo_fn, grad_combo_fn=None if autograd else grad_combo_fn) state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{ a: np.pi / 4, b: np.pi }, { params[0]: np.pi / 4, params[1]: np.pi / 4 }, { params[0]: np.pi / 2, params[1]: np.pi / 4 }] correct_values = [[-1., 0.], [-1.2397, -0.2397], [0, -0.45936]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_natural_gradient4(self, grad_method, qfi_method, regularization): """Test the natural gradient 4""" # Avoid regularization = lasso intentionally because it does not converge ham = 0.5 * X - 1 * Z a = Parameter('a') params = a q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) nat_grad = NaturalGradient(grad_method=grad_method, qfi_method=qfi_method, regularization=regularization).convert( operator=op, params=params) values_dict = [{a: np.pi / 4}] correct_values = [[0.] ] if regularization == 'ridge' else [[-1.41421342]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( nat_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=0)
def test_operator_coefficient_hessian(self, method): """Test the operator coefficient hessian <Z> = Tr( | psi > < psi | Z) = sin(a)sin(b) <X> = Tr( | psi > < psi | X) = cos(a) d<H>/dc_0 = 2 * c_0 * <X> + c_1 * <Z> d<H>/dc_1 = c_0 * <Z> d^2<H>/dc_0^2 = 2 * <X> d^2<H>/dc_0dc_1 = <Z> d^2<H>/dc_1dc_0 = <Z> d^2<H>/dc_1^2 = 0 """ a = Parameter('a') b = Parameter('b') q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(b, q[0]) coeff_0 = Parameter('c_0') coeff_1 = Parameter('c_1') ham = coeff_0 * coeff_0 * X + coeff_1 * coeff_0 * Z op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) gradient_coeffs = [(coeff_0, coeff_0), (coeff_0, coeff_1), (coeff_1, coeff_1)] coeff_grad = Hessian(hess_method=method).convert(op, gradient_coeffs) values_dict = [{coeff_0: 0.5, coeff_1: -1, a: np.pi / 4, b: np.pi}, {coeff_0: 0.5, coeff_1: -1, a: np.pi / 4, b: np.pi / 4}] correct_values = [[2 / np.sqrt(2), 0, 0], [2 / np.sqrt(2), 1 / 2, 0]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal(coeff_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_operator_coefficient_gradient(self, method): """Test the operator coefficient gradient Tr( | psi > < psi | Z) = sin(a)sin(b) Tr( | psi > < psi | X) = cos(a) """ a = Parameter('a') b = Parameter('b') q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(b, q[0]) coeff_0 = Parameter('c_0') coeff_1 = Parameter('c_1') ham = coeff_0 * X + coeff_1 * Z op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0) gradient_coeffs = [coeff_0, coeff_1] coeff_grad = Gradient(grad_method=method).convert(op, gradient_coeffs) values_dict = [{coeff_0: 0.5, coeff_1: -1, a: np.pi / 4, b: np.pi}, {coeff_0: 0.5, coeff_1: -1, a: np.pi / 4, b: np.pi / 4}] correct_values = [[1 / np.sqrt(2), 0], [1 / np.sqrt(2), 1 / 2]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal(coeff_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_prob_hess(self, method): """Test the probability Hessian using linear combination of unitaries method d^2p0/da^2 = - sin(a)sin(b) / 2 d^2p1/da^2 = sin(a)sin(b) / 2 d^2p0/dadb = cos(a)cos(b) / 2 d^2p1/dadb = - cos(a)cos(b) / 2 """ a = Parameter('a') b = Parameter('b') params = [(a, a), (a, b)] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(b, q[0]) op = CircuitStateFn(primitive=qc, coeff=1.) prob_hess = Hessian(hess_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4, b: 0}, {a: np.pi / 4, b: np.pi / 4}, {a: np.pi / 2, b: np.pi}] correct_values = [[[0, 0], [1 / (2 * np.sqrt(2)), - 1 / (2 * np.sqrt(2))]], [[- 1 / 4, 1 / 4], [1 / 4, - 1 / 4]], [[0, 0], [0, 0]]] for i, value_dict in enumerate(values_dict): for j, prob_hess_result in enumerate(prob_hess.assign_parameters(value_dict).eval()): np.testing.assert_array_almost_equal(prob_hess_result, correct_values[i][j], decimal=1)
def test_gradient_p(self, method): """Test the state gradient for p |psi> = 1/sqrt(2)[[1, exp(ia)]] Tr(|psi><psi|Z) = 0 Tr(|psi><psi|X) = cos(a) d<H>/da = - 0.5 sin(a) """ ham = 0.5 * X - 1 * Z a = Parameter('a') params = a q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.p(a, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4}, {a: 0}, {a: np.pi / 2}] correct_values = [-0.5 / np.sqrt(2), 0, -0.5] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_state_hessian(self, method): """Test the state Hessian Tr(|psi><psi|Z) = sin(a)sin(b) Tr(|psi><psi|X) = cos(a) d^2<H>/da^2 = - 0.5 cos(a) + 1 sin(a)sin(b) d^2<H>/dbda = - 1 cos(a)cos(b) d^2<H>/dbda = - 1 cos(a)cos(b) d^2<H>/db^2 = + 1 sin(a)sin(b) """ ham = 0.5 * X - 1 * Z a = Parameter('a') b = Parameter('b') params = [(a, a), (a, b), (b, b)] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(b, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_hess = Hessian(hess_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4, b: np.pi}, {a: np.pi / 4, b: np.pi / 4}, {a: np.pi / 2, b: np.pi / 4}] correct_values = [[-0.5 / np.sqrt(2), 1 / np.sqrt(2), 0], [-0.5 / np.sqrt(2) + 0.5, -1 / 2., 0.5], [1 / np.sqrt(2), 0, 1 / np.sqrt(2)]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal(state_hess.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_state_gradient5(self, method): """Test the state gradient Tr(|psi><psi|Z) = sin(a0)sin(a1) Tr(|psi><psi|X) = cos(a0) d<H>/da0 = - 0.5 sin(a0) - 1 cos(a0)sin(a1) d<H>/da1 = - 1 sin(a0)cos(a1) """ ham = 0.5 * X - 1 * Z a = ParameterVector('a', 2) params = a q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: [np.pi / 4, np.pi]}, {a: [np.pi / 4, np.pi / 4]}, {a: [np.pi / 2, np.pi / 4]}] correct_values = [[-0.5 / np.sqrt(2), 1 / np.sqrt(2)], [-0.5 / np.sqrt(2) - 0.5, -1 / 2.], [-0.5, -1 / np.sqrt(2)]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal(state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_pauli_expectation_param_qobj(self): """ Test PauliExpectation with param_qobj """ q_instance = QuantumInstance(self.backend, seed_simulator=self.seed, seed_transpiler=self.seed, shots=20000) qubit_op = (1 * I ^ I) + (2 * I ^ Z) + (3 * Z ^ I) + (4 * Z ^ Z) + ( 5 * X ^ X) var_form = RealAmplitudes(qubit_op.num_qubits) ansatz_circuit_op = CircuitStateFn(var_form) observable = PauliExpectation().convert(~StateFn(qubit_op)) expect_op = observable.compose(ansatz_circuit_op).reduce() params1 = {} params2 = {} for param in var_form.parameters: params1[param] = [0] params2[param] = [0, 0] sampler1 = CircuitSampler(backend=q_instance, param_qobj=False) samples1 = sampler1.convert(expect_op, params=params1) val1 = np.real(samples1.eval())[0] samples2 = sampler1.convert(expect_op, params=params2) val2 = np.real(samples2.eval()) sampler2 = CircuitSampler(backend=q_instance, param_qobj=True) samples3 = sampler2.convert(expect_op, params=params1) val3 = np.real(samples3.eval()) samples4 = sampler2.convert(expect_op, params=params2) val4 = np.real(samples4.eval()) np.testing.assert_array_almost_equal([val1] * 2, val2, decimal=2) np.testing.assert_array_almost_equal(val1, val3, decimal=2) np.testing.assert_array_almost_equal([val1] * 2, val4, decimal=2)
def get_exp(H, circ): psi = CircuitStateFn(circ) backend = Aer.get_backend('statevector_simulator') measurable_expression = StateFn(H, is_measurement=True).compose(psi) expectation = AerPauliExpectation().convert(measurable_expression) sampler = CircuitSampler(backend).convert(expectation) return sampler.eval().real
def test_natural_gradient(self, method, regularization): """Test the natural gradient""" ham = 0.5 * X - 1 * Z a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) nat_grad = NaturalGradient(grad_method=method, regularization=regularization).convert( operator=op, params=params) values_dict = [{params[0]: np.pi / 4, params[1]: np.pi / 2}] correct_values = [[-2.36003979, 2.06503481] ] if regularization == 'ridge' else [[-4.2, 0]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( nat_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=0)
def test_prob_grad(self, method): """Test the probability gradient dp0/da = cos(a)sin(b) / 2 dp1/da = - cos(a)sin(b) / 2 dp0/db = sin(a)cos(b) / 2 dp1/db = - sin(a)cos(b) / 2 """ a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = CircuitStateFn(primitive=qc, coeff=1.) prob_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4, b: 0}, {params[0]: np.pi / 4, params[1]: np.pi / 4}, {params[0]: np.pi / 2, params[1]: np.pi}] correct_values = [[[0, 0], [1 / (2 * np.sqrt(2)), - 1 / (2 * np.sqrt(2))]], [[1 / 4, - 1 / 4], [1 / 4, - 1 / 4]], [[0, 0], [- 1 / 2, 1 / 2]]] for i, value_dict in enumerate(values_dict): for j, prob_grad_result in enumerate(prob_grad.assign_parameters(value_dict).eval()): np.testing.assert_array_almost_equal(prob_grad_result, correct_values[i][j], decimal=1)
def test_state_gradient4(self, method): """Test the state gradient 4 Tr(|psi><psi|ZX) = -cos(a) daTr(|psi><psi|ZX) = sin(a) """ ham = X ^ Z a = Parameter('a') params = a q = QuantumRegister(2) qc = QuantumCircuit(q) qc.x(q[0]) qc.h(q[1]) qc.crz(a, q[0], q[1]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4}, {a: 0}, {a: np.pi / 2}] correct_values = [1 / np.sqrt(2), 0, 1] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def gradient_function(current_point): """ Gradient function Args: current_point (np.ndarray): Current values for the variational parameters. Returns: np.ndarray: array of partial derivatives of the loss function w.r.t. the variational parameters. """ free_params = self._free_parameters generated_data, _ = self.get_output(quantum_instance, params=current_point, shots=self._shots) prediction_generated = discriminator.get_label(generated_data, detach=True) op = ~CircuitStateFn(primitive=self.generator_circuit) grad_object = gradient_object.convert(operator=op, params=free_params) value_dict = { free_params[i]: current_point[i] for i in range(len(free_params)) } analytical_gradients = np.array( grad_object.assign_parameters(value_dict).eval()) loss_gradients = self.loss(prediction_generated, analytical_gradients).real return loss_gradients
def test_qfi(self, method): """Test if the quantum fisher information calculation is correct QFI = [[1, 0], [0, 1]] - [[0, 0], [0, cos^2(a)]] """ a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = CircuitStateFn(primitive=qc, coeff=1.) qfi = QFI(qfi_method=method).convert(operator=op, params=params) values_dict = [{ params[0]: np.pi / 4, params[1]: 0.1 }, { params[0]: np.pi, params[1]: 0.1 }, { params[0]: np.pi / 2, params[1]: 0.1 }] correct_values = [[[1, 0], [0, 0.5]], [[1, 0], [0, 0]], [[1, 0], [0, 1]]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( qfi.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_state_gradient3(self, method): """Test the state gradient 3 Tr(|psi><psi|Z) = sin(a)sin(c(a)) = sin(a)sin(cos(a)+1) Tr(|psi><psi|X) = cos(a) d<H>/da = - 0.5 sin(a) - 1 cos(a)sin(cos(a)+1) + 1 sin^2(a)cos(cos(a)+1) """ ham = 0.5 * X - 1 * Z a = Parameter('a') # b = Parameter('b') params = a c = np.cos(a) + 1 q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(c, q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{a: np.pi / 4}, {a: 0}, {a: np.pi / 2}] correct_values = [-1.1220, -0.9093, 0.0403] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def test_circuit_state_fn_from_dict_initialize(self): """ state fn circuit from dict initialize test """ statedict = {'101': .5, '100': .1, '000': .2, '111': .5} sfc = CircuitStateFn.from_dict(statedict) self.assertIsInstance(sfc, CircuitStateFn) samples = sfc.sample() np.testing.assert_array_almost_equal( StateFn(statedict).to_matrix(), np.round(sfc.to_matrix(), decimals=1)) for k, v in samples.items(): self.assertIn(k, statedict) # It's ok if these are far apart because the dict is sampled. self.assertAlmostEqual(v, np.abs(statedict[k])**.5, delta=.5) # Follows same code path as above, but testing to be thorough sfc_vector = CircuitStateFn.from_vector(StateFn(statedict).to_matrix()) np.testing.assert_array_almost_equal( StateFn(statedict).to_matrix(), sfc_vector.to_matrix())
def test_compose(self): """ compose test """ target = (X + Z) @ (Y + Z) expected = 1j * Z - 1j * Y - 1j * X + I self.assertEqual(target, expected) observable = (X ^ X) + (Y ^ Y) + (Z ^ Z) state = CircuitStateFn((CX @ (X ^ H @ X)).to_circuit()) self.assertAlmostEqual((~OperatorStateFn(observable) @ state).eval(), -3)
def test_circuit_sampler2(self, method): """Test the probability gradient with the circuit sampler dp0/da = cos(a)sin(b) / 2 dp1/da = - cos(a)sin(b) / 2 dp0/db = sin(a)cos(b) / 2 dp1/db = - sin(a)cos(b) / 2 """ a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = CircuitStateFn(primitive=qc, coeff=1.) shots = 8000 if method == 'fin_diff': np.random.seed(8) prob_grad = Gradient(grad_method=method, epsilon=shots**(-1 / 6.)).convert( operator=op, params=params) else: prob_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{ a: [np.pi / 4], b: [0] }, { params[0]: [np.pi / 4], params[1]: [np.pi / 4] }, { params[0]: [np.pi / 2], params[1]: [np.pi] }] correct_values = [[[0, 0], [1 / (2 * np.sqrt(2)), -1 / (2 * np.sqrt(2))]], [[1 / 4, -1 / 4], [1 / 4, -1 / 4]], [[0, 0], [-1 / 2, 1 / 2]]] backend = BasicAer.get_backend('qasm_simulator') q_instance = QuantumInstance(backend=backend, shots=shots) for i, value_dict in enumerate(values_dict): sampler = CircuitSampler(backend=q_instance).convert( prob_grad, params=value_dict) result = sampler.eval() np.testing.assert_array_almost_equal(result[0], correct_values[i], decimal=1)
def test_circuit_sampler(self, method): """Test the gradient with circuit sampler Tr(|psi><psi|Z) = sin(a)sin(b) Tr(|psi><psi|X) = cos(a) d<H>/da = - 0.5 sin(a) - 1 cos(a)sin(b) d<H>/db = - 1 sin(a)cos(b) """ ham = 0.5 * X - 1 * Z a = Parameter('a') b = Parameter('b') params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) shots = 8000 if method == 'fin_diff': np.random.seed(8) state_grad = Gradient(grad_method=method, epsilon=shots**(-1 / 6.)).convert( operator=op, params=params) else: state_grad = Gradient(grad_method=method).convert(operator=op, params=params) values_dict = [{ a: np.pi / 4, b: np.pi }, { params[0]: np.pi / 4, params[1]: np.pi / 4 }, { params[0]: np.pi / 2, params[1]: np.pi / 4 }] correct_values = [[-0.5 / np.sqrt(2), 1 / np.sqrt(2)], [-0.5 / np.sqrt(2) - 0.5, -1 / 2.], [-0.5, -1 / np.sqrt(2)]] backend = BasicAer.get_backend('qasm_simulator') q_instance = QuantumInstance(backend=backend, shots=shots) for i, value_dict in enumerate(values_dict): sampler = CircuitSampler(backend=q_instance).convert( state_grad, params={k: [v] for k, v in value_dict.items()}) np.testing.assert_array_almost_equal(sampler.eval()[0], correct_values[i], decimal=1)
def test_sampling(self): """ state fn circuit from dict initialize test """ statedict = {'101': .5, '100': .1, '000': .2, '111': .5} sfc = CircuitStateFn.from_dict(statedict) circ_samples = sfc.sample() dict_samples = StateFn(statedict).sample() vec_samples = StateFn(statedict).to_matrix_op().sample() for k, v in circ_samples.items(): self.assertIn(k, dict_samples) self.assertIn(k, vec_samples) # It's ok if these are far apart because the dict is sampled. self.assertAlmostEqual(v, np.abs(dict_samples[k])**.5, delta=.5) self.assertAlmostEqual(v, np.abs(vec_samples[k])**.5, delta=.5)
def test_circuit_state_fn_from_dict_as_sum(self): """state fn circuit from dict as sum test """ statedict = {'1010101': .5, '1000000': .1, '0000000': .2j, '1111111': 0.5j} sfc_sum = CircuitStateFn.from_dict(statedict) self.assertIsInstance(sfc_sum, SummedOp) for sfc_op in sfc_sum.oplist: self.assertIsInstance(sfc_op, CircuitStateFn) samples = sfc_op.sample() self.assertIn(list(samples.keys())[0], statedict) self.assertEqual(sfc_op.coeff, statedict[list(samples.keys())[0]]) np.testing.assert_array_almost_equal(StateFn(statedict).to_matrix(), sfc_sum.to_matrix())
def _eval_aux_ops(self, threshold=1e-12): # Create new CircuitSampler to avoid breaking existing one's caches. sampler = CircuitSampler(self.quantum_instance) aux_op_meas = self.expectation.convert(StateFn(self.aux_operators, is_measurement=True)) aux_op_expect = aux_op_meas.compose(CircuitStateFn(self.get_optimal_circuit())) values = np.real(sampler.convert(aux_op_expect).eval()) # Discard values below threshold aux_op_results = (values * (np.abs(values) > threshold)) # Deal with the aux_op behavior where there can be Nones or Zero qubit Paulis in the list self._ret['aux_ops'] = [None if is_none else [result] for (is_none, result) in zip(self._aux_op_nones, aux_op_results)] self._ret['aux_ops'] = np.array([self._ret['aux_ops']])
def test_state_hessian_custom_combo_fn(self, method): """Test the state Hessian with on an operator which includes a user-defined combo_fn. Tr(|psi><psi|Z) = sin(a)sin(b) Tr(|psi><psi|X) = cos(a) d^2<H>/da^2 = - 0.5 cos(a) + 1 sin(a)sin(b) d^2<H>/dbda = - 1 cos(a)cos(b) d^2<H>/dbda = - 1 cos(a)cos(b) d^2<H>/db^2 = + 1 sin(a)sin(b) """ ham = 0.5 * X - 1 * Z a = Parameter('a') b = Parameter('b') params = [(a, a), (a, b), (b, b)] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(a, q[0]) qc.rx(b, q[0]) op = ListOp([~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)], combo_fn=lambda x: x[0]**3 + 4 * x[0]) state_hess = Hessian(hess_method=method).convert(operator=op, params=params) values_dict = [{ a: np.pi / 4, b: np.pi }, { a: np.pi / 4, b: np.pi / 4 }, { a: np.pi / 2, b: np.pi / 4 }] correct_values = [[-1.28163104, 2.56326208, 1.06066017], [-0.04495626, -2.40716991, 1.8125], [2.82842712, -1.5, 1.76776695]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal( state_hess.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)
def _eval_aux_ops(self, threshold=1e-12): # Create new CircuitSampler to avoid breaking existing one's caches. sampler = CircuitSampler(self.quantum_instance) aux_op_meas = self.expectation.convert(StateFn(self.aux_operators, is_measurement=True)) aux_op_expect = aux_op_meas.compose(CircuitStateFn(self.get_optimal_circuit())) values = np.real(sampler.convert(aux_op_expect).eval()) # Discard values below threshold aux_op_results = (values * (np.abs(values) > threshold)) # Deal with the aux_op behavior where there can be Nones or Zero qubit Paulis in the list self._ret['aux_ops'] = [None if is_none else [result] for (is_none, result) in zip(self._aux_op_nones, aux_op_results)] # As this has mixed types, since it can included None, it needs to explicitly pass object # data type to avoid numpy 1.19 warning message about implicit conversion being deprecated self._ret['aux_ops'] = np.array([self._ret['aux_ops']], dtype=object)
def construct_expectation( self, parameter: Union[List[float], List[Parameter], np.ndarray] ) -> OperatorBase: r""" Generate the ansatz circuit and expectation value measurement, and return their runnable composition. Args: parameter: Parameters for the ansatz circuit. Returns: The Operator equalling the measurement of the ansatz :class:`StateFn` by the Observable's expectation :class:`StateFn`. Raises: AquaError: If no operator has been provided. """ if self.operator is None: raise AquaError("The operator was never provided.") # ensure operator and varform are compatible self._check_operator_varform() if isinstance(self.var_form, QuantumCircuit): param_dict = dict(zip(self._var_form_params, parameter)) # type: Dict wave_function = self.var_form.assign_parameters(param_dict) else: wave_function = self.var_form.construct_circuit(parameter) # Expectation was never created, try to create one if self._expectation is None: self._try_set_expectation_value_from_factory() # If setting the expectation failed, raise an Error: if self._expectation is None: raise AquaError( 'No expectation set and could not automatically set one, please ' 'try explicitly setting an expectation or specify a backend so it ' 'can be chosen automatically.') observable_meas = self.expectation.convert( StateFn(self.operator, is_measurement=True)) ansatz_circuit_op = CircuitStateFn(wave_function) return observable_meas.compose(ansatz_circuit_op).reduce()
def test_gradient_ryy(self, method): # pylint: disable=wrong-spelling-in-comment """Test the state gradient for YY rotation """ ham = Y ^ Y a = Parameter('a') q = QuantumRegister(2) qc = QuantumCircuit(q) qc.ryy(a, q[0], q[1]) op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.) state_grad = Gradient(grad_method=method).convert(operator=op, params=a) values_dict = [{a: np.pi / 8}, {a: np.pi}] correct_values = [[0], [0]] for i, value_dict in enumerate(values_dict): np.testing.assert_array_almost_equal(state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1)