def test_gradient_rzz(self, method): # pylint: disable=wrong-spelling-in-comment """Test the state gradient for ZZ rotation """ ham = Z ^ X a = Parameter('a') q = QuantumRegister(2) qc = QuantumCircuit(q) qc.h(q[0]) qc.rzz(a, q[0], q[1]) 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 = [[-0.707], [-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_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 evaluate_operators( self, state: Union[str, dict, Result, list, np.ndarray, Statevector, QuantumCircuit, Instruction, OperatorBase], operators: Union[WeightedPauliOperator, OperatorBase, list, dict] ) -> Union[float, List[float], Dict[str, List[float]]]: """Evaluates additional operators at the given state. Args: state: any kind of input that can be used to specify a state. See also ``StateFn`` for more details. operators: either a single, list or dictionary of ``WeightedPauliOperator``s or any kind of operator implementing the ``OperatorBase``. Returns: The expectation value of the given operator(s). The return type will be identical to the format of the provided operators. """ # try to get a QuantumInstance from the solver quantum_instance = getattr(self._solver, 'quantum_instance', None) if not isinstance(state, StateFn): state = StateFn(state) # handle all possible formats of operators # i.e. if a user gives us a dict of operators, we return the results equivalently, etc. if isinstance(operators, list): results = [] for op in operators: results.append(self._eval_op(state, op, quantum_instance)) elif isinstance(operators, dict): results = {} # type: ignore for name, op in operators.items(): results[name] = self._eval_op(state, op, quantum_instance) else: results = self._eval_op(state, operators, quantum_instance) return results
def construct_circuit( 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)) wave_function = self.var_form.assign_parameters(param_dict) else: wave_function = self.var_form.construct_circuit(parameter) # If ExpectationValue was never created, create one now. if not self.expectation: self._try_set_expectation_value_from_factory() 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_grad_combo_fn_chain_rule_nat_grad(self): """ Test the chain rule for a custom gradient combo function """ np.random.seed(2) def combo_fn(x): amplitudes = x[0].primitive.data pdf = np.multiply(amplitudes, np.conj(amplitudes)) return np.sum(np.log(pdf)) / (-len(amplitudes)) def grad_combo_fn(x): amplitudes = x[0].primitive.data pdf = np.multiply(amplitudes, np.conj(amplitudes)) grad = [] for prob in pdf: grad += [-1 / prob] return grad qc = RealAmplitudes(2, reps=1) grad_op = ListOp([StateFn(qc)], combo_fn=combo_fn, grad_combo_fn=grad_combo_fn) grad = NaturalGradient(grad_method='lin_comb', regularization='ridge').convert( grad_op, qc.ordered_parameters) value_dict = dict( zip(qc.ordered_parameters, np.random.rand(len(qc.ordered_parameters)))) correct_values = [[0.20777236], [-18.92560338], [-15.89005475], [-10.44002031]] np.testing.assert_array_almost_equal( grad.assign_parameters(value_dict).eval(), correct_values, decimal=3)
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_pauli_expect_op_vector(self): """ pauli expect op vector test """ paulis_op = ListOp([X, Y, Z, I]) converted_meas = self.expect.convert(~StateFn(paulis_op)) plus_mean = (converted_meas @ Plus) sampled_plus = self.sampler.convert(plus_mean) np.testing.assert_array_almost_equal(sampled_plus.eval(), [1, 0, 0, 1], decimal=1) minus_mean = (converted_meas @ Minus) sampled_minus = self.sampler.convert(minus_mean) np.testing.assert_array_almost_equal(sampled_minus.eval(), [-1, 0, 0, 1], decimal=1) zero_mean = (converted_meas @ Zero) sampled_zero = self.sampler.convert(zero_mean) np.testing.assert_array_almost_equal(sampled_zero.eval(), [0, 0, 1, 1], decimal=1) sum_zero = (Plus + Minus) * (.5 ** .5) sum_zero_mean = (converted_meas @ sum_zero) sampled_zero_mean = self.sampler.convert(sum_zero_mean) # !!NOTE!!: Depolarizing channel (Sampling) means interference # does not happen between circuits in sum, so expectation does # not equal expectation for Zero!! np.testing.assert_array_almost_equal(sampled_zero_mean.eval(), [0, 0, 0, 2], decimal=1)
# qc.cx(c[0], c[1]) #Acting the gates on circuit for i in range (g): gates() # Prepare the Ising Hamiltonian #n = 3 #number of qubits a = 1.0 k = 2 t = range(1, n+1) mdl = Model()# build model with docplex x = [mdl.binary_var() for i in range(n)] objective = a*(k - mdl.sum(t[i]*x[i] for i in range(n)))**2 mdl.minimize(objective) qp = QuadraticProgram()# convert to Qiskit's quadratic program qp.from_docplex(mdl) qp2ising = QuadraticProgramToIsing()# convert to Ising Hamiltonian H, offset = qp2ising.encode(qp) H_matrix = np.real(H.to_matrix()) psi = StateFn(qc) expectation_value = (~psi @ H @ psi).eval() print(psi) print(expectation_value)
def _parameter_shift( self, operator: OperatorBase, params: Union[ParameterExpression, ParameterVector, List]) -> OperatorBase: r""" Args: operator: The operator containing circuits we are taking the derivative of. params: The parameters (ω) we are taking the derivative with respect to. If a ParameterVector is provided, each parameter will be shifted. Returns: param_shifted_op: An operator object which evaluates to the respective gradients. Raises: ValueError: If the given parameters do not occur in the provided operator TypeError: If the operator has more than one circuit representing the quantum state """ if isinstance(params, (ParameterVector, list)): param_grads = [ self._parameter_shift(operator, param) for param in params ] absent_params = [ params[i] for i, grad_ops in enumerate(param_grads) if grad_ops is None ] if len(absent_params) > 0: raise ValueError( "The following parameters do not appear in the provided operator: ", absent_params) return ListOp(absent_params) # By this point, it's only one parameter param = params if not isinstance(param, ParameterExpression): raise ValueError if isinstance(operator, ListOp) and not isinstance(operator, ComposedOp): return_op = operator.traverse( partial(self._parameter_shift, params=param)) # Remove any branch of the tree where the relevant parameter does not occur trimmed_oplist = [op for op in return_op.oplist if op is not None] # If all branches are None, remove the parent too if len(trimmed_oplist) == 0: return None # Rebuild the operator with the trimmed down oplist properties = { 'coeff': return_op._coeff, 'abelian': return_op._abelian } if return_op.__class__ == ListOp: properties['combo_fn'] = return_op.combo_fn return return_op.__class__(oplist=trimmed_oplist, **properties) else: circs = self.get_unique_circuits(operator) if len(circs) > 1: raise TypeError( 'Please define an operator with a single circuit representing ' 'the quantum state.') if len(circs) == 0: return operator circ = circs[0] if self.analytic: # Unroll the circuit into a gate set for which the gradient may be computed # using pi/2 shifts. circ = ParamShift._unroll_to_supported_operations(circ) operator = ParamShift._replace_operator_circuit(operator, circ) if param not in circ._parameter_table: return ~Zero @ One shifted_ops = [] summed_shifted_op = None for m, param_occurence in enumerate(circ._parameter_table[param]): param_index = param_occurence[1] pshift_op = deepcopy(operator) mshift_op = deepcopy(operator) # We need the circuit objects of the newly instantiated operators pshift_circ = self.get_unique_circuits(pshift_op)[0] mshift_circ = self.get_unique_circuits(mshift_op)[0] pshift_gate = pshift_circ._parameter_table[param][m][0] mshift_gate = mshift_circ._parameter_table[param][m][0] p_param = pshift_gate.params[param_index] m_param = mshift_gate.params[param_index] # For analytic gradients the circuit parameters are shifted once by +pi/2 and # once by -pi/2. if self.analytic: shift_constant = 0.5 pshift_gate.params[param_index] = (p_param + (np.pi / (4 * shift_constant))) mshift_gate.params[param_index] = (m_param - (np.pi / (4 * shift_constant))) # For finite difference gradients the circuit parameters are shifted once by # +epsilon and once by -epsilon. else: shift_constant = 1. / (2 * self._epsilon) pshift_gate.params[param_index] = (p_param + self._epsilon) mshift_gate.params[param_index] = (m_param - self._epsilon) # The results of the shifted operators are now evaluated according the parameter # shift / finite difference formula. if isinstance(operator, ComposedOp): shifted_op = shift_constant * (pshift_op - mshift_op) # If the operator represents a quantum state then we apply a special combo # function to evaluate probability gradients. elif isinstance(operator, StateFn): shifted_op = ListOp([pshift_op, mshift_op], combo_fn=partial( self._prob_combo_fn, shift_constant=shift_constant)) else: raise TypeError( 'Probability gradients are not supported for the given ' 'operator type') if isinstance(p_param, ParameterExpression) and not isinstance( p_param, Parameter): expr_grad = DerivativeBase.parameter_expression_grad( p_param, param) shifted_op *= expr_grad if not summed_shifted_op: summed_shifted_op = shifted_op else: summed_shifted_op += shifted_op shifted_ops.append(summed_shifted_op) if not SummedOp(shifted_ops).reduce(): return ~StateFn(Zero) @ One else: return SummedOp(shifted_ops).reduce()
def _run(self) -> 'VQEResult': """Run the algorithm to compute the minimum eigenvalue. Returns: The result of the VQE algorithm as ``VQEResult``. Raises: AquaError: Wrong setting of operator and backend. """ if self.operator is None: raise AquaError("The operator was never provided.") self._check_operator_varform() self._quantum_instance.circuit_summary = True self._eval_count = 0 # Convert the gradient operator into a callable function that is compatible with the # optimization routine. if self._gradient: if isinstance(self._gradient, GradientBase): self._gradient = self._gradient.gradient_wrapper( ~StateFn(self._operator) @ StateFn(self._var_form), bind_params=self._var_form_params, backend=self._quantum_instance) vqresult = self.find_minimum(initial_point=self.initial_point, var_form=self.var_form, cost_fn=self._energy_evaluation, gradient_fn=self._gradient, optimizer=self.optimizer) # TODO remove all former dictionary logic self._ret = {} self._ret['num_optimizer_evals'] = vqresult.optimizer_evals self._ret['min_val'] = vqresult.optimal_value self._ret['opt_params'] = vqresult.optimal_point self._ret['eval_time'] = vqresult.optimizer_time self._ret['opt_params_dict'] = vqresult.optimal_parameters if self._ret['num_optimizer_evals'] is not None and \ self._eval_count >= self._ret['num_optimizer_evals']: self._eval_count = self._ret['num_optimizer_evals'] self._eval_time = self._ret['eval_time'] logger.info('Optimization complete in %s seconds.\nFound opt_params %s in %s evals', self._eval_time, self._ret['opt_params'], self._eval_count) self._ret['eval_count'] = self._eval_count result = VQEResult() result.combine(vqresult) result.eigenvalue = vqresult.optimal_value + 0j result.eigenstate = self.get_optimal_vector() self._ret['energy'] = self.get_optimal_cost() self._ret['eigvals'] = np.asarray([self._ret['energy']]) self._ret['eigvecs'] = np.asarray([result.eigenstate]) if len(self.aux_operators) > 0: self._eval_aux_ops() # TODO remove when ._ret is deprecated result.aux_operator_eigenvalues = self._ret['aux_ops'][0] result.cost_function_evals = self._eval_count return result
def _run(self): """ Run the algorithm to compute up to the requested k number of eigenvalues. Returns: dict: Dictionary of results Raises: AquaError: if no operator has been provided """ if self._operator is None: raise AquaError("Operator was never provided") k_orig = self._k if self._filter_criterion: # need to consider all elements if a filter is set self._k = 2**(self._operator.num_qubits) self._ret = {} self._solve() # compute energies before filtering, as this also evaluates the aux operators self._get_energies() # if a filter is set, loop over the given values and only keep if self._filter_criterion: eigvecs = [] eigvals = [] energies = [] aux_ops = [] cnt = 0 for i in range(len(self._ret['eigvals'])): eigvec = self._ret['eigvecs'][i] eigval = self._ret['eigvals'][i] energy = self._ret['energies'][i] if 'aux_ops' in self._ret: aux_op = self._ret['aux_ops'][i] else: aux_op = None if self._filter_criterion(eigvec, eigval, aux_op): cnt += 1 eigvecs += [eigvec] eigvals += [eigval] energies += [energy] if 'aux_ops' in self._ret: aux_ops += [aux_op] if cnt == k_orig: break self._ret['eigvecs'] = np.array(eigvecs) self._ret['eigvals'] = np.array(eigvals) self._ret['energies'] = np.array(energies) self._k = k_orig # evaluate ground state after filtering (in case a filter is set) self._get_ground_state_energy() logger.debug('NumPyEigensolver _run result:\n%s', pprint.pformat(self._ret, indent=4)) result = EigensolverResult() if 'eigvals' in self._ret: result.eigenvalues = self._ret['eigvals'] if 'eigvecs' in self._ret: result.eigenstates = ListOp([StateFn(vec) for vec in self._ret['eigvecs']]) if 'aux_ops' in self._ret: result.aux_operator_eigenvalues = self._ret['aux_ops'] logger.debug('EigensolverResult dict:\n%s', pprint.pformat(result.data, indent=4)) return result
def test_parameterized_qobj(self): """ grouped pauli expectation test """ two_qubit_h2 = (-1.052373245772859 * I ^ I) + \ (0.39793742484318045 * I ^ Z) + \ (-0.39793742484318045 * Z ^ I) + \ (-0.01128010425623538 * Z ^ Z) + \ (0.18093119978423156 * X ^ X) aer_sampler = CircuitSampler(self.sampler.quantum_instance, param_qobj=True, attach_results=True) var_form = RealAmplitudes() var_form.num_qubits = 2 observable_meas = self.expect.convert( StateFn(two_qubit_h2, is_measurement=True)) ansatz_circuit_op = CircuitStateFn(var_form) expect_op = observable_meas.compose(ansatz_circuit_op).reduce() def generate_parameters(num): param_bindings = {} for param in var_form.parameters: values = [] for _ in range(num): values.append(np.random.rand()) param_bindings[param] = values return param_bindings def validate_sampler(ideal, sut, param_bindings): expect_sampled = ideal.convert(expect_op, params=param_bindings).eval() actual_sampled = sut.convert(expect_op, params=param_bindings).eval() self.assertAlmostEqual(actual_sampled, expect_sampled, delta=.1) def get_circuit_templates(sampler): return sampler._transpiled_circ_templates def validate_aer_binding_used(templates): self.assertIsNotNone(templates) def validate_aer_templates_reused(prev_templates, cur_templates): self.assertIs(prev_templates, cur_templates) validate_sampler(self.sampler, aer_sampler, generate_parameters(1)) cur_templates = get_circuit_templates(aer_sampler) validate_aer_binding_used(cur_templates) prev_templates = cur_templates validate_sampler(self.sampler, aer_sampler, generate_parameters(2)) cur_templates = get_circuit_templates(aer_sampler) validate_aer_templates_reused(prev_templates, cur_templates) prev_templates = cur_templates validate_sampler(self.sampler, aer_sampler, generate_parameters(2)) # same num of params cur_templates = get_circuit_templates(aer_sampler) validate_aer_templates_reused(prev_templates, cur_templates)
qc.y(0) operations_i.append('qc_new.y(0)') elif param == 5: qc.z(0) operations_i.append('qc_new.z(0)') print(A) qc.x(2) qc.z(1) qc.y(3) qc.s(0) qc.cx(0, 1) # qc.swap(1, 3) qc.cx(2, 3) cliff_sf_target = StateFn(qc) print(qc) # %% randomly select a single qubit gate and randomly change it to another # calculate overlap integral def overlap_modules_square(psi_2): psi_1 = cliff_sf_target # return (psi_1.adjoint().compose(psi_2).eval().real) * (psi_2.adjoint().compose(psi_1).eval().real) return np.real((~psi_1 @ psi_2).eval() * (~psi_2 @ psi_1).eval()) # radom apply GATE_FUNCTIONS applied_gates = []
qp = QuadraticProgram() # convert to Qiskit's quadratic program qp.from_docplex(mdl) qp2ising = QuadraticProgramToIsing() # convert to Ising Hamiltonian H, offset = qp2ising.encode(qp) op = H.to_pauli_op() help(H) print(H) # Prepare the state qc = QuantumCircuit(3) qc.h(0) qc.cx(0, 1) qc.cy(1, 2) psi = StateFn(qc) # wrap it into a statefunction print(psi) # Calculate the expectation value for Ising Hamiltonian print('expectation_value:', psi.adjoint().compose(op).compose(psi).eval().real) # %% another way of calculating expectation # define your backend or quantum instance (where you can add settings) backend = Aer.get_backend('qasm_simulator') q_instance = QuantumInstance(backend, shots=1024) # define the state to sample measurable_expression = StateFn(op, is_measurement=True).compose(psi)