def __init__( self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, var_form: Optional[Union[QuantumCircuit, VariationalForm]] = None, optimizer: Optional[Optimizer] = None, initial_point: Optional[np.ndarray] = None, expectation: Optional[ExpectationBase] = None, include_custom: bool = False, max_evals_grouped: int = 1, aux_operators: Optional[List[Optional[Union[ OperatorBase, LegacyBaseOperator]]]] = None, callback: Optional[Callable[[int, np.ndarray, float, float], None]] = None, quantum_instance: Optional[Union[QuantumInstance, BaseBackend]] = None, orbital_rotation: Optional['OrbitalRotation'] = None, core: Optional[LegacyBaseOperator] = None, qmolecule: Optional[QMolecule] = None, bounds: Optional[np.ndarray] = None, iterative_oo: bool = False, iterative_oo_iterations: int = 3, ) -> None: """ Args: operator: Qubit operator of the Hamiltonian. var_form: A parameterized variational form (ansatz). optimizer: A classical optimizer. initial_point: An optional initial point (i.e. initial parameter values) for the optimizer. If ``None`` then VQE will look to the variational form for a preferred point and if not will simply compute a random one. expectation: The Expectation converter for taking the average value of the Observable over the var_form state function. When ``None`` (the default) an :class:`~qiskit.aqua.operators.expectations.ExpectationFactory` is used to select an appropriate expectation based on the operator and backend. When using Aer qasm_simulator backend, with paulis, it is however much faster to leverage custom Aer function for the computation but, although VQE performs much faster with it, the outcome is ideal, with no shot noise, like using a state vector simulator. If you are just looking for the quickest performance when choosing Aer qasm_simulator and the lack of shot noise is not an issue then set `include_custom` parameter here to ``True`` (defaults to ``False``). include_custom: When `expectation` parameter here is None setting this to ``True`` will allow the factory to include the custom Aer pauli expectation. max_evals_grouped: Max number of evaluations performed simultaneously. Signals the given optimizer that more than one set of parameters can be supplied so that potentially the expectation values can be computed in parallel. Typically this is possible when a finite difference gradient is used by the optimizer such that multiple points to compute the gradient can be passed and if computed in parallel improve overall execution time. aux_operators: Optional list of auxiliary operators to be evaluated with the eigenstate of the minimum eigenvalue main result and their expectation values returned. For instance in chemistry these can be dipole operators, total particle count operators so we can get values for these at the ground state. callback: a callback that can access the intermediate data during the optimization. Four parameter values are passed to the callback as follows during each evaluation by the optimizer for its current set of parameters as it works towards the minimum. These are: the evaluation count, the optimizer parameters for the variational form, the evaluated mean and the evaluated standard deviation. quantum_instance: :class:`~qiskit.aqua.QuantumInstance` that the algorithm is executed on. orbital_rotation: instance of :class:`~qiskit.chemistry.algorithms.minimum_eigen_solvers.OrbitalRotation` class that creates the matrices that rotate the orbitals needed to produce the rotated MO coefficients C as C = C0 * exp(-kappa). core: instance of the :class:`~qiskit.chemistry.core.Hamiltonian` class to make new qubit operator after the orbital rotation using the data stored in qmolecule. qmolecule: instance of the :class:`~qiskit.chemistry.QMolecule` class which has methods needed to recompute one-/two-electron/dipole integrals after orbital rotation (C = C0 * exp(-kappa)). bounds: bounds for variational form and orbital rotation parameters given to a classical optimizer. iterative_oo: when ``True`` optimize first the variational form and then the orbitals, iteratively. Otherwise, the wavefunction ansatz and orbitals are optimized simultaneously. iterative_oo_iterations: number of iterations in the iterative procedure, set larger to be sure to converge to the global minimum. Raises: AquaError: if the number of orbital optimization iterations is less or equal to zero. """ super().__init__( operator=operator, var_form=var_form, optimizer=optimizer, initial_point=initial_point, expectation=expectation, include_custom=include_custom, max_evals_grouped=max_evals_grouped, aux_operators=aux_operators, callback=callback, quantum_instance=quantum_instance, ) self._qmolecule_rotated = None self._fixed_wavefunction_params = None if aux_operators is None: self._aux_operators = [] else: self._aux_operators = [aux_operators] if not isinstance(aux_operators, list) else \ aux_operators logger.info(self.print_settings()) self._core = core self._qmolecule = qmolecule if orbital_rotation is None: self._orbital_rotation = OrbitalRotation( num_qubits=self.var_form.num_qubits, core=self._core, qmolecule=self._qmolecule) self._num_parameters_oovqe = None if initial_point is None: self._set_initial_point() self._bounds = bounds if self._bounds is None: self._set_bounds(self._orbital_rotation.parameter_bound_value) self._iterative_oo = iterative_oo self._iterative_oo_iterations = iterative_oo_iterations if self._iterative_oo_iterations < 1: raise AquaError( 'Please set iterative_oo_iterations parameter to a positive number,' ' got {} instead'.format(self._iterative_oo_iterations)) # copies to overcome incompatibilities with error checks in VQAlgorithm class self.var_form_num_parameters = self.var_form.num_parameters self.var_form_bounds = copy.copy(self.var_form._bounds)
def construct_circuit(self, circuit=None, variable_register=None, output_register=None, output_idx=None, ancillary_register=None, mct_mode='basic'): # pylint: disable=arguments-differ """ Construct circuit. Args: circuit (QuantumCircuit): The optional circuit to extend from variable_register (QuantumRegister): The optional quantum register to use for problem variables output_register (QuantumRegister): The optional quantum register to use for holding the output output_idx (int): The index of the output register to write to ancillary_register (QuantumRegister): The optional quantum register to use as ancilla mct_mode (str): The mode to use for building Multiple-Control Toffoli Returns: QuantumCircuit: quantum circuit. Raises: AquaError: invalid input """ circuit = self._set_up_circuit(circuit=circuit, variable_register=variable_register, clause_register='skip', output_register=output_register, output_idx=output_idx, ancillary_register=ancillary_register, mct_mode=mct_mode) def build_clause(clause_expr): if clause_expr[0] == 'and': lits = [l[1] for l in clause_expr[1:]] elif clause_expr[0] == 'lit': lits = [clause_expr[1]] else: raise AquaError( 'Unexpected clause expression {}.'.format(clause_expr)) flags = BooleanLogicNormalForm._lits_to_flags(lits) and_circuit = AND(num_variable_qubits=len(self._variable_register), flags=flags, mcx_mode=mct_mode) qubits = self._variable_register[:] + [ self._output_register[self._output_idx] ] if self._ancillary_register: qubits += self._ancillary_register[:and_circuit. num_ancilla_qubits] circuit.compose(and_circuit, qubits, inplace=True) # compute all clauses if self._depth == 0: self._construct_circuit_for_tiny_expr(circuit, output_idx=output_idx) elif self._depth == 1: if self._ast[0] == 'xor': for cur_clause_expr in self._ast[1:]: build_clause(cur_clause_expr) else: build_clause(self._ast) elif self._depth == 2: if not self._ast[0] == 'xor': raise AquaError('Unexpected root logical ' 'operation {} for ESOP.'.format(self._ast[0])) for cur_clause_expr in self._ast[1:]: build_clause(cur_clause_expr) else: raise AquaError('Unexpected ESOP expression {}.'.format(self._ast)) return circuit
def get_optimal_cost(self): if 'opt_params' not in self._ret: raise AquaError("Cannot return optimal cost before running the " "algorithm to find optimal params.") return self._ret['min_val']
def __init__( self, data: np.ndarray, bounds: Optional[np.ndarray] = None, num_qubits: Optional[np.ndarray] = None, batch_size: int = 500, num_epochs: int = 3000, seed: int = 7, discriminator: Optional[DiscriminativeNetwork] = None, generator: Optional[GenerativeNetwork] = None, tol_rel_ent: Optional[float] = None, snapshot_dir: Optional[str] = None, quantum_instance: Optional[Union[QuantumInstance, BaseBackend]] = None ) -> None: """ Args: data: Training data of dimension k bounds: k min/max data values [[min_0,max_0],...,[min_k-1,max_k-1]] if univariate data: [min_0,max_0] num_qubits: k numbers of qubits to determine representation resolution, i.e. n qubits enable the representation of 2**n values [num_qubits_0,..., num_qubits_k-1] batch_size: Batch size, has a min. value of 1. num_epochs: Number of training epochs seed: Random number seed discriminator: Discriminates between real and fake data samples generator: Generates 'fake' data samples tol_rel_ent: Set tolerance level for relative entropy. If the training achieves relative entropy equal or lower than tolerance it finishes. snapshot_dir: Directory in to which to store cvs file with parameters, if None (default) then no cvs file is created. quantum_instance: Quantum Instance or Backend Raises: AquaError: invalid input """ validate_min('batch_size', batch_size, 1) super().__init__(quantum_instance) if data is None: raise AquaError('Training data not given.') self._data = np.array(data) if bounds is None: bounds_min = np.percentile(self._data, 5, axis=0) bounds_max = np.percentile(self._data, 95, axis=0) bounds = [] for i, _ in enumerate(bounds_min): bounds.append([bounds_min[i], bounds_max[i]]) if np.ndim(data) > 1: if len(bounds) != (len(num_qubits) or len(data[0])): raise AquaError( 'Dimensions of the data, the length of the data bounds ' 'and the numbers of qubits per ' 'dimension are incompatible.') else: if (np.ndim(bounds) or len(num_qubits)) != 1: raise AquaError( 'Dimensions of the data, the length of the data bounds ' 'and the numbers of qubits per ' 'dimension are incompatible.') self._bounds = np.array(bounds) self._num_qubits = num_qubits # pylint: disable=unsubscriptable-object if np.ndim(data) > 1: if self._num_qubits is None: self._num_qubits = np.ones[len(data[0])] * 3 else: if self._num_qubits is None: self._num_qubits = np.array([3]) self._data, self._data_grid, self._grid_elements, self._prob_data = \ discretize_and_truncate(self._data, self._bounds, self._num_qubits, return_data_grid_elements=True, return_prob=True, prob_non_zero=True) self._batch_size = batch_size self._num_epochs = num_epochs self._snapshot_dir = snapshot_dir self._g_loss = [] self._d_loss = [] self._rel_entr = [] self._tol_rel_ent = tol_rel_ent self._random_seed = seed if generator is None: self.set_generator() else: self._generator = generator if discriminator is None: self.set_discriminator() else: self._discriminator = discriminator self.seed = self._random_seed self._ret = {}
def optimal_params(self): if 'opt_params' not in self._ret: raise AquaError( "Cannot find optimal params before running the algorithm.") return self._ret['opt_params']
def __init__(self, circuit) -> None: if circuit is None: raise AquaError("No quantum circuit was passed.") else: self.circuit = circuit
def __init__( self, optimizer: Optimizer, feature_map: Union[QuantumCircuit, FeatureMap], var_form: Union[QuantumCircuit, VariationalForm], training_dataset: Dict[str, np.ndarray], test_dataset: Optional[Dict[str, np.ndarray]] = None, datapoints: Optional[np.ndarray] = None, max_evals_grouped: int = 1, minibatch_size: int = -1, callback: Optional[Callable[[int, np.ndarray, float, int], None]] = None, use_sigmoid_cross_entropy: bool = False, quantum_instance: Optional[Union[QuantumInstance, BaseBackend, Backend]] = None ) -> None: """ Args: optimizer: The classical optimizer to use. feature_map: The FeatureMap instance to use. var_form: The variational form instance. training_dataset: The training dataset, in the format {'A': np.ndarray, 'B': np.ndarray, ...}. test_dataset: The test dataset, in same format as `training_dataset`. datapoints: NxD array, N is the number of data and D is data dimension. max_evals_grouped: The maximum number of evaluations to perform simultaneously. minibatch_size: The size of a mini-batch. callback: a callback that can access the intermediate data during the optimization. Four parameter values are passed to the callback as follows during each evaluation. These are: the evaluation count, parameters of the variational form, the evaluated value, the index of data batch. use_sigmoid_cross_entropy: whether to use sigmoid cross entropy or not. quantum_instance: Quantum Instance or Backend Note: We use `label` to denote numeric results and `class` the class names (str). Raises: AquaError: Missing feature map or missing training dataset. """ warn_package('aqua.algorithms.classifiers', 'qiskit_machine_learning.algorithms.classifiers', 'qiskit-machine-learning') # VariationalForm is not deprecated on level of the VQAlgorithm yet as UCCSD still # derives from there, therefore we're adding a warning here if isinstance(var_form, VariationalForm): warnings.warn(""" The {} object as input for the VQC is deprecated as of 0.7.0 and will be removed no earlier than 3 months after the release. You should pass a QuantumCircuit object instead. See also qiskit.circuit.library.n_local for a collection of suitable circuits.""".format(type(feature_map)), DeprecationWarning, stacklevel=2) super().__init__(var_form=var_form, optimizer=optimizer, cost_fn=self._loss, quantum_instance=quantum_instance) self._batches = None self._label_batches = None self._batch_index = None self._eval_time = None self.batch_num = None self._optimizer.set_max_evals_grouped(max_evals_grouped) self._callback = callback if use_sigmoid_cross_entropy: self.cost_function = cost_estimate_sigmoid else: self.cost_function = cost_estimate if feature_map is None: raise AquaError('Missing feature map.') if training_dataset is None: raise AquaError('Missing training dataset.') self._training_dataset, self._class_to_label = split_dataset_to_data_and_labels( training_dataset) self._label_to_class = { label: class_name for class_name, label in self._class_to_label.items() } self._num_classes = len(list(self._class_to_label.keys())) if test_dataset is not None: self._test_dataset = split_dataset_to_data_and_labels( test_dataset, self._class_to_label) else: self._test_dataset = test_dataset if datapoints is not None and not isinstance(datapoints, np.ndarray): datapoints = np.asarray(datapoints) if len(datapoints) == 0: # pylint: disable=len-as-condition datapoints = None self._datapoints = datapoints self._minibatch_size = minibatch_size self._eval_count = 0 self._ret = {} # type: Dict[str, Any] self._parameterized_circuits = None self.feature_map = feature_map
def get_optimal_cost(self) -> float: """Get the minimal cost or energy found by the VQE.""" if 'opt_params' not in self._ret: raise AquaError("Cannot return optimal cost before running the " "algorithm to find optimal params.") return self._ret['min_val']
def optimal_params(self) -> List[float]: """The optimal parameters for the variational form.""" if 'opt_params' not in self._ret: raise AquaError("Cannot find optimal params before running the algorithm.") return self._ret['opt_params']
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 _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 to_weighted_pauli_operator(operator): """ Converting a given operator to `WeightedPauliOperator` Args: operator (WeightedPauliOperator | TPBGroupedWeightedPauliOperator | MatrixOperator): one of supported operator type Returns: WeightedPauliOperator: the converted weighted pauli operator Raises: AquaError: Unsupported type to convert Warnings: Converting time from a MatrixOperator to a Pauli-type Operator grows exponentially. If you are converting a system with large number of qubits, it will take time. You can turn on DEBUG logging to check the progress. """ if operator.__class__ == WeightedPauliOperator: return operator elif operator.__class__ == TPBGroupedWeightedPauliOperator: # destroy the grouping but keep z2 symmetries info return WeightedPauliOperator(paulis=operator.paulis, z2_symmetries=operator.z2_symmetries, name=operator.name) elif operator.__class__ == MatrixOperator: if operator.is_empty(): return WeightedPauliOperator(paulis=[]) if operator.num_qubits > 10: logger.warning( "Converting time from a MatrixOperator to a Pauli-type Operator grows " "exponentially. If you are converting a system with large number of " "qubits, it will take time. And now you are converting a %s-qubit " "Hamiltonian. You can turn on DEBUG logging to check the progress." "", operator.num_qubits) num_qubits = operator.num_qubits coeff = 2**(-num_qubits) paulis = [] possible_basis = 'IXYZ' if operator.dia_matrix is not None: possible_basis = 'IZ' if logger.isEnabledFor(logging.DEBUG): logger.debug( "Converting a MatrixOperator to a Pauli-type Operator:") TextProgressBar(sys.stderr) results = parallel_map(_conversion, list( itertools.product(possible_basis, repeat=num_qubits)), task_kwargs={"matrix": operator._matrix}, num_processes=aqua_globals.num_processes) for trace_value, pauli in results: weight = trace_value * coeff if weight != 0.0 and np.abs(weight) > operator.atol: paulis.append([weight, pauli]) return WeightedPauliOperator(paulis, z2_symmetries=operator.z2_symmetries, name=operator.name) else: raise AquaError( "Unsupported type to convert to WeightedPauliOperator: " "{}".format(operator.__class__))
def _mct_v_chain(qc, control_qubits, target_qubit, ancillary_qubits, dirty_ancilla=False): """ Create new MCT circuit by chaining Toffoli gates into a V shape. The dirty_ancilla mode is from https://arxiv.org/abs/quant-ph/9503016 Lemma 7.2 All intermediate Toffoli gates are implemented up to a relative phase, see https://arxiv.org/abs/1508.03273 An additional saving of 4 CNOTs is achieved by using the Toffoli implementation from Section IV.B of https://arxiv.org/abs/1508.03273 """ if len(ancillary_qubits) < len(control_qubits) - 2: raise AquaError('Insufficient number of ancillary qubits.') if dirty_ancilla: anci_idx = len(control_qubits) - 3 qc.u2(0, pi, target_qubit) qc.cx(target_qubit, ancillary_qubits[anci_idx]) qc.u1(-pi / 4, ancillary_qubits[anci_idx]) qc.cx(control_qubits[len(control_qubits) - 1], ancillary_qubits[anci_idx]) qc.u1(pi / 4, ancillary_qubits[anci_idx]) qc.cx(target_qubit, ancillary_qubits[anci_idx]) qc.u1(-pi / 4, ancillary_qubits[anci_idx]) qc.cx(control_qubits[len(control_qubits) - 1], ancillary_qubits[anci_idx]) qc.u1(pi / 4, ancillary_qubits[anci_idx]) for idx in reversed(range(2, len(control_qubits) - 1)): qc.rccx(control_qubits[idx], ancillary_qubits[anci_idx - 1], ancillary_qubits[anci_idx]) anci_idx -= 1 anci_idx = 0 qc.rccx(control_qubits[0], control_qubits[1], ancillary_qubits[anci_idx]) for idx in range(2, len(control_qubits) - 1): qc.rccx(control_qubits[idx], ancillary_qubits[anci_idx], ancillary_qubits[anci_idx + 1]) anci_idx += 1 if dirty_ancilla: qc.u1(-pi / 4, ancillary_qubits[anci_idx]) qc.cx(control_qubits[len(control_qubits) - 1], ancillary_qubits[anci_idx]) qc.u1(pi / 4, ancillary_qubits[anci_idx]) qc.cx(target_qubit, ancillary_qubits[anci_idx]) qc.u1(-pi / 4, ancillary_qubits[anci_idx]) qc.cx(control_qubits[len(control_qubits) - 1], ancillary_qubits[anci_idx]) qc.u1(pi / 4, ancillary_qubits[anci_idx]) qc.cx(target_qubit, ancillary_qubits[anci_idx]) qc.u2(0, pi, target_qubit) else: qc.ccx(control_qubits[len(control_qubits) - 1], ancillary_qubits[anci_idx], target_qubit) for idx in reversed(range(2, len(control_qubits) - 1)): qc.rccx(control_qubits[idx], ancillary_qubits[anci_idx - 1], ancillary_qubits[anci_idx]) anci_idx -= 1 qc.rccx(control_qubits[0], control_qubits[1], ancillary_qubits[anci_idx]) if dirty_ancilla: anci_idx = 0 for idx in range(2, len(control_qubits) - 1): qc.rccx(control_qubits[idx], ancillary_qubits[anci_idx], ancillary_qubits[anci_idx + 1]) anci_idx += 1
def mct(self, q_controls, q_target, q_ancilla, mode='basic'): """ Apply Multiple-Control Toffoli operation Args: self (QuantumCircuit): The QuantumCircuit object to apply the mct gate on. q_controls (Union(QuantumRegister, list[Qubit])): The list of control qubits q_target (Qubit): The target qubit q_ancilla (Union(QuantumRegister, list[Qubit])): The list of ancillary qubits mode (str): The implementation mode to use Raises: AquaError: invalid input """ if len(q_controls) == 1: # cx self.cx(q_controls[0], q_target) elif len(q_controls) == 2: # ccx self.ccx(q_controls[0], q_controls[1], q_target) else: # check controls if isinstance(q_controls, QuantumRegister): control_qubits = [qb for qb in q_controls] elif isinstance(q_controls, list): control_qubits = q_controls else: raise AquaError( 'MCT needs a list of qubits or a quantum register for controls.' ) # check target if isinstance(q_target, Qubit): target_qubit = q_target else: raise AquaError('MCT needs a single qubit as target.') # check ancilla if q_ancilla is None: ancillary_qubits = [] elif isinstance(q_ancilla, QuantumRegister): ancillary_qubits = [qb for qb in q_ancilla] elif isinstance(q_ancilla, list): ancillary_qubits = q_ancilla else: raise AquaError( 'MCT needs None or a list of qubits or a quantum register for ancilla.' ) all_qubits = control_qubits + [target_qubit] + ancillary_qubits self._check_qargs(all_qubits) self._check_dups(all_qubits) if mode == 'basic': _mct_v_chain(self, control_qubits, target_qubit, ancillary_qubits, dirty_ancilla=False) elif mode == 'basic-dirty-ancilla': _mct_v_chain(self, control_qubits, target_qubit, ancillary_qubits, dirty_ancilla=True) elif mode == 'advanced': _multicx(self, [*control_qubits, target_qubit], ancillary_qubits[0] if ancillary_qubits else None) elif mode == 'noancilla': _multicx_noancilla(self, [*control_qubits, target_qubit]) else: raise AquaError( 'Unrecognized mode for building MCT circuit: {}.'.format(mode))
def get_gradient( self, operator: OperatorBase, params: Union[ParameterExpression, ParameterVector, List[ParameterExpression]] ) -> OperatorBase: """Get the gradient for the given operator w.r.t. the given parameters Args: operator: Operator w.r.t. which we take the gradient. params: Parameters w.r.t. which we compute the gradient. Returns: Operator which represents the gradient w.r.t. the given params. Raises: ValueError: If ``params`` contains a parameter not present in ``operator``. AquaError: If the coefficient of the operator could not be reduced to 1. AquaError: If the differentiation of a combo_fn requires JAX but the package is not installed. TypeError: If the operator does not include a StateFn given by a quantum circuit Exception: Unintended code is reached """ def is_coeff_c(coeff, c): if isinstance(coeff, ParameterExpression): expr = coeff._symbol_expr return expr == c return coeff == c if isinstance(params, (ParameterVector, list)): param_grads = [ self.get_gradient(operator, param) for param in params ] # If get_gradient returns None, then the corresponding parameter was probably not # present in the operator. This needs to be looked at more carefully as other things can # probably trigger a return of None. 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(param_grads) # By now params is a single parameter param = params # Handle Product Rules if not is_coeff_c(operator._coeff, 1.0): # Separate the operator from the coefficient coeff = operator._coeff op = operator / coeff # Get derivative of the operator (recursively) d_op = self.get_gradient(op, param) # ..get derivative of the coeff d_coeff = self.parameter_expression_grad(coeff, param) grad_op = 0 if d_op != ~Zero @ One and not is_coeff_c(coeff, 0.0): grad_op += coeff * d_op if op != ~Zero @ One and not is_coeff_c(d_coeff, 0.0): grad_op += d_coeff * op if grad_op == 0: grad_op = ~Zero @ One return grad_op # Base Case, you've hit a ComposedOp! # Prior to execution, the composite operator was standardized and coefficients were # collected. Any operator measurements were converted to Pauli-Z measurements and rotation # circuits were applied. Additionally, all coefficients within ComposedOps were collected # and moved out front. if isinstance(operator, ComposedOp): # Gradient of an expectation value if not is_coeff_c(operator._coeff, 1.0): raise AquaError( 'Operator pre-processing failed. Coefficients were not properly ' 'collected inside the ComposedOp.') # Do some checks to make sure operator is sensible # TODO add compatibility with sum of circuit state fns if not isinstance(operator[-1], CircuitStateFn): raise TypeError( 'The gradient framework is compatible with states that are given as ' 'CircuitStateFn') return self.grad_method.convert(operator, param) elif isinstance(operator, CircuitStateFn): # Gradient of an a state's sampling probabilities if not is_coeff_c(operator._coeff, 1.0): raise AquaError( 'Operator pre-processing failed. Coefficients were not properly ' 'collected inside the ComposedOp.') return self.grad_method.convert(operator, param) # Handle the chain rule elif isinstance(operator, ListOp): grad_ops = [self.get_gradient(op, param) for op in operator.oplist] # Note: this check to see if the ListOp has a default combo_fn # will fail if the user manually specifies the default combo_fn. # I.e operator = ListOp([...], combo_fn=lambda x:x) will not pass this check and # later on jax will try to differentiate it and raise an error. # An alternative is to check the byte code of the operator's combo_fn against the # default one. if operator._combo_fn == ListOp([])._combo_fn: return ListOp(oplist=grad_ops) elif isinstance(operator, SummedOp): return SummedOp( oplist=[grad for grad in grad_ops if grad != ~Zero @ One]).reduce() elif isinstance(operator, TensoredOp): return TensoredOp(oplist=grad_ops) if operator.grad_combo_fn: grad_combo_fn = operator.grad_combo_fn else: if _HAS_JAX: grad_combo_fn = jit( grad(operator._combo_fn, holomorphic=True)) else: raise AquaError( 'This automatic differentiation function is based on JAX. Please install ' 'jax and use `import jax.numpy as jnp` instead of `import numpy as np` when' 'defining a combo_fn.') def chain_rule_combo_fn(x): result = np.dot(x[1], x[0]) if isinstance(result, np.ndarray): result = list(result) return result return ListOp([ ListOp(operator.oplist, combo_fn=grad_combo_fn), ListOp(grad_ops) ], combo_fn=chain_rule_combo_fn)
def train(self): """ Train the qGAN Raises: AquaError: Batch size bigger than the number of items in the truncated data set """ if self._snapshot_dir is not None: with open(os.path.join(self._snapshot_dir, 'output.csv'), mode='w') as csv_file: fieldnames = [ 'epoch', 'loss_discriminator', 'loss_generator', 'params_generator', 'rel_entropy' ] writer = csv.DictWriter(csv_file, fieldnames=fieldnames) writer.writeheader() if len(self._data) < self._batch_size: raise AquaError('The batch size needs to be less than the ' 'truncated data size of {}'.format(len( self._data))) for e in range(self._num_epochs): aqua_globals.random.shuffle(self._data) index = 0 while (index + self._batch_size) <= len(self._data): real_batch = self._data[index:index + self._batch_size] index += self._batch_size generated_batch, generated_prob = self._generator.get_output( self._quantum_instance, shots=self._batch_size) # 1. Train Discriminator ret_d = self._discriminator.train( [real_batch, generated_batch], [ np.ones(len(real_batch)) / len(real_batch), generated_prob ]) d_loss_min = ret_d['loss'] # 2. Train Generator self._generator.set_discriminator(self._discriminator) ret_g = self._generator.train(self._quantum_instance, shots=self._batch_size) g_loss_min = ret_g['loss'] self._d_loss.append(np.around(float(d_loss_min), 4)) self._g_loss.append(np.around(g_loss_min, 4)) rel_entr = self.get_rel_entr() self._rel_entr.append(np.around(rel_entr, 4)) self._ret['params_d'] = ret_d['params'] self._ret['params_g'] = ret_g['params'] self._ret['loss_d'] = np.around(float(d_loss_min), 4) self._ret['loss_g'] = np.around(g_loss_min, 4) self._ret['rel_entr'] = np.around(rel_entr, 4) if self._snapshot_dir is not None: self._store_params(e, np.around(d_loss_min, 4), np.around(g_loss_min, 4), np.around(rel_entr, 4)) logger.debug('Epoch %s/%s...', e + 1, self._num_epochs) logger.debug('Loss Discriminator: %s', np.around(float(d_loss_min), 4)) logger.debug('Loss Generator: %s', np.around(g_loss_min, 4)) logger.debug('Relative Entropy: %s', np.around(rel_entr, 4)) if self._tol_rel_ent is not None: if rel_entr <= self._tol_rel_ent: break
def solve(self, driver: BaseDriver, aux_operators: Optional[Union[List[FermionicOperator], List[BosonicOperator]]] = None) \ -> Union[ElectronicStructureResult, VibronicStructureResult]: """Computes the ground state. Args: driver: a chemistry driver. aux_operators: Additional auxiliary ``FermionicOperator`` instances to evaluate at the ground state. Raises: AquaError: if a solver other than VQE or a variational form other than UCCSD is provided or if the algorithm finishes due to an unforeseen reason. Returns: An AdaptVQEResult which is an ElectronicStructureResult but also includes runtime information about the AdaptVQE algorithm like the number of iterations, finishing criterion, and the final maximum gradient. """ operator, aux_operators = self._transformation.transform( driver, aux_operators) vqe = self._solver.get_solver(self._transformation) vqe.operator = operator if not isinstance(vqe, VQE): raise AquaError( "The AdaptVQE algorithm requires the use of the VQE solver") if not isinstance(vqe.var_form, UCCSD): raise AquaError( "The AdaptVQE algorithm requires the use of the UCCSD variational form" ) vqe.var_form.manage_hopping_operators() excitation_pool = vqe.var_form.excitation_pool threshold_satisfied = False alternating_sequence = False max_iterations_exceeded = False prev_op_indices: List[int] = [] theta: List[float] = [] max_grad: Tuple[float, Optional[WeightedPauliOperator]] = (0., None) iteration = 0 while self._max_iterations is None or iteration < self._max_iterations: iteration += 1 logger.info('--- Iteration #%s ---', str(iteration)) # compute gradients cur_grads = self._compute_gradients(excitation_pool, theta, vqe) # pick maximum gradient max_grad_index, max_grad = max(enumerate(cur_grads), key=lambda item: np.abs(item[1][0])) # store maximum gradient's index for cycle detection prev_op_indices.append(max_grad_index) # log gradients if logger.isEnabledFor(logging.INFO): gradlog = "\nGradients in iteration #{}".format(str(iteration)) gradlog += "\nID: Excitation Operator: Gradient <(*) maximum>" for i, grad in enumerate(cur_grads): gradlog += '\n{}: {}: {}'.format(str(i), str(grad[1]), str(grad[0])) if grad[1] == max_grad[1]: gradlog += '\t(*)' logger.info(gradlog) if np.abs(max_grad[0]) < self._threshold: logger.info( "Adaptive VQE terminated successfully " "with a final maximum gradient: %s", str(np.abs(max_grad[0]))) threshold_satisfied = True break # check indices of picked gradients for cycles if self._check_cyclicity(prev_op_indices): logger.info("Alternating sequence found. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) alternating_sequence = True break # add new excitation to self._var_form vqe.var_form.push_hopping_operator(max_grad[1]) theta.append(0.0) # run VQE on current Ansatz vqe.initial_point = theta raw_vqe_result = vqe.compute_minimum_eigenvalue(operator) theta = raw_vqe_result.optimal_point.tolist() else: # reached maximum number of iterations max_iterations_exceeded = True logger.info("Maximum number of iterations reached. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) # once finished evaluate auxiliary operators if any if aux_operators is not None: aux_values = self.evaluate_operators(raw_vqe_result.eigenstate, aux_operators) else: aux_values = None raw_vqe_result.aux_operator_eigenvalues = aux_values if threshold_satisfied: finishing_criterion = 'Threshold converged' elif alternating_sequence: finishing_criterion = 'Aborted due to cyclicity' elif max_iterations_exceeded: finishing_criterion = 'Maximum number of iterations reached' else: raise AquaError( 'The algorithm finished due to an unforeseen reason!') electronic_result = self.transformation.interpret(raw_vqe_result) result = AdaptVQEResult(electronic_result.data) result.num_iterations = iteration result.final_max_gradient = max_grad[0] result.finishing_criterion = finishing_criterion logger.info('The final energy is: %s', str(result.computed_energies[0])) return result
def mcry(self, theta, q_controls, q_target, q_ancillae, mode='basic', use_basis_gates=False): """ Apply Multiple-Controlled Y rotation gate Args: self (QuantumCircuit): The QuantumCircuit object to apply the mcry gate on. theta (float): angle theta q_controls (list[Qubit]): The list of control qubits q_target (Qubit): The target qubit q_ancillae (Union(QuantumRegister,tuple(QuantumRegister, int))): The list of ancillary qubits. mode (str): The implementation mode to use use_basis_gates (bool): use basis gates Raises: AquaError: invalid input """ # check controls if isinstance(q_controls, QuantumRegister): control_qubits = [qb for qb in q_controls] elif isinstance(q_controls, list): control_qubits = q_controls else: raise AquaError( 'The mcry gate needs a list of qubits or a quantum register for controls.' ) # check target if isinstance(q_target, Qubit): target_qubit = q_target else: raise AquaError('The mcry gate needs a single qubit as target.') # check ancilla if q_ancillae is None: ancillary_qubits = [] elif isinstance(q_ancillae, QuantumRegister): ancillary_qubits = [qb for qb in q_ancillae] elif isinstance(q_ancillae, list): ancillary_qubits = q_ancillae else: raise AquaError('The mcry gate needs None or a list ' 'of qubits or a quantum register for ancilla.') all_qubits = control_qubits + [target_qubit] + ancillary_qubits self._check_qargs(all_qubits) self._check_dups(all_qubits) if mode == 'basic': self.u3(theta / 2, 0, 0, q_target) self.mct(q_controls, q_target, q_ancillae) self.u3(-theta / 2, 0, 0, q_target) self.mct(q_controls, q_target, q_ancillae) elif mode == 'noancilla': n_c = len(control_qubits) if n_c == 1: # cu3 apply_cu3(self, theta, 0, 0, control_qubits[0], target_qubit, use_basis_gates=use_basis_gates) else: theta_step = theta * (1 / (2**(n_c - 1))) _apply_mcu3_graycode(self, theta_step, 0, 0, control_qubits, target_qubit, use_basis_gates=use_basis_gates) else: raise AquaError( 'Unrecognized mode for building MCRY circuit: {}.'.format(mode))
def __init__(self, bounds: np.ndarray, num_qubits: List[int], generator_circuit: Optional[ Union[UnivariateVariationalDistribution, MultivariateVariationalDistribution, QuantumCircuit]] = None, init_params: Optional[Union[List[float], np.ndarray]] = None, snapshot_dir: Optional[str] = None) -> None: """ Args: bounds: k min/max data values [[min_1,max_1],...,[min_k,max_k]], given input data dim k num_qubits: k numbers of qubits to determine representation resolution, i.e. n qubits enable the representation of 2**n values [n_1,..., n_k] generator_circuit: a UnivariateVariationalDistribution for univariate data, a MultivariateVariationalDistribution for multivariate data, or a QuantumCircuit implementing the generator. init_params: 1D numpy array or list, Initialization for the generator's parameters. snapshot_dir: str or None, if not None save the optimizer's parameter after every update step to the given directory Raises: AquaError: Set multivariate variational distribution to represent multivariate data """ super().__init__() self._bounds = bounds self._num_qubits = num_qubits self.generator_circuit = generator_circuit if self.generator_circuit is None: entangler_map = [] if np.sum(num_qubits) > 2: for i in range(int(np.sum(num_qubits))): entangler_map.append( [i, int(np.mod(i + 1, np.sum(num_qubits)))]) else: if np.sum(num_qubits) > 1: entangler_map.append([0, 1]) if len(num_qubits) > 1: num_qubits = list(map(int, num_qubits)) low = bounds[:, 0].tolist() high = bounds[:, 1].tolist() init_dist = MultivariateUniformDistribution(num_qubits, low=low, high=high) q = QuantumRegister(sum(num_qubits)) qc = QuantumCircuit(q) init_dist.build(qc, q) init_distribution = Custom(num_qubits=sum(num_qubits), circuit=qc) # Set variational form var_form = TwoLocal(sum(num_qubits), 'ry', 'cz', reps=1, initial_state=init_distribution, entanglement=entangler_map) if init_params is None: init_params = aqua_globals.random.random( var_form.num_parameters) * 2 * 1e-2 # Set generator circuit self.generator_circuit = MultivariateVariationalDistribution( num_qubits, var_form, init_params, low=low, high=high) else: init_dist = UniformDistribution(sum(num_qubits), low=bounds[0], high=bounds[1]) q = QuantumRegister(sum(num_qubits), name='q') qc = QuantumCircuit(q) init_dist.build(qc, q) init_distribution = Custom(num_qubits=sum(num_qubits), circuit=qc) var_form = TwoLocal(sum(num_qubits), 'ry', 'cz', reps=1, initial_state=init_distribution, entanglement=entangler_map) if init_params is None: init_params = aqua_globals.random.random( var_form.num_parameters) * 2 * 1e-2 # Set generator circuit self.generator_circuit = UnivariateVariationalDistribution( int(np.sum(num_qubits)), var_form, init_params, low=bounds[0], high=bounds[1]) if len(num_qubits) > 1: if isinstance(self.generator_circuit, MultivariateVariationalDistribution): pass else: raise AquaError('Set multivariate variational distribution ' 'to represent multivariate data') else: if isinstance(self.generator_circuit, UnivariateVariationalDistribution): pass else: raise AquaError('Set univariate variational distribution ' 'to represent univariate data') # Set optimizer for updating the generator network self._optimizer = ADAM(maxiter=1, tol=1e-6, lr=1e-3, beta_1=0.7, beta_2=0.99, noise_factor=1e-6, eps=1e-6, amsgrad=True, snapshot_dir=snapshot_dir) if np.ndim(self._bounds) == 1: bounds = np.reshape(self._bounds, (1, len(self._bounds))) else: bounds = self._bounds for j, prec in enumerate(self._num_qubits): # prepare data grid for dim j grid = np.linspace(bounds[j, 0], bounds[j, 1], (2**prec)) if j == 0: if len(self._num_qubits) > 1: self._data_grid = [grid] else: self._data_grid = grid self._grid_elements = grid elif j == 1: self._data_grid.append(grid) temp = [] for g_e in self._grid_elements: for g in grid: temp0 = [g_e] temp0.append(g) temp.append(temp0) self._grid_elements = temp else: self._data_grid.append(grid) temp = [] for g_e in self._grid_elements: for g in grid: temp0 = deepcopy(g_e) temp0.append(g) temp.append(temp0) self._grid_elements = deepcopy(temp) self._data_grid = np.array(self._data_grid) self._shots = None self._discriminator = None self._ret = {}
def _run(self) -> 'AmplitudeEstimationResult': # check if A factory or state_preparation has been set if self.state_preparation is None: if self._a_factory is None: # getter emits deprecation warnings, therefore nest raise AquaError( 'Either the state_preparation variable or the a_factory ' '(deprecated) must be set to run the algorithm.') if self._quantum_instance.is_statevector: self.construct_circuit(measurement=False) # run circuit on statevector simulator ret = self._quantum_instance.execute(self._circuit) state_vector = np.asarray([ret.get_statevector(self._circuit)]) self._ret['statevector'] = state_vector # get state probabilities state_probabilities = np.real(state_vector.conj() * state_vector)[0] # evaluate results a_probabilities, y_probabilities = self._evaluate_statevector_results( state_probabilities) # store number of shots: convention is 1 shot for statevector, # needed so that MLE works! self._ret['shots'] = 1 else: # run circuit on QASM simulator self.construct_circuit(measurement=True) ret = self._quantum_instance.execute(self._circuit) # get counts self._ret['counts'] = ret.get_counts() # construct probabilities y_probabilities = OrderedDict() a_probabilities = OrderedDict() shots = self._quantum_instance._run_config.shots for state, counts in ret.get_counts().items(): y = int(state.replace(' ', '')[:self._m][::-1], 2) probability = counts / shots y_probabilities[y] = probability a = np.round(np.power(np.sin(y * np.pi / 2**self._m), 2), decimals=7) a_probabilities[a] = a_probabilities.get(a, 0.0) + probability # store shots self._ret['shots'] = shots # construct a_items and y_items a_items = [(a, p) for (a, p) in a_probabilities.items() if p > 1e-6] y_items = [(y, p) for (y, p) in y_probabilities.items() if p > 1e-6] a_items = list(a_probabilities.items()) y_items = list(y_probabilities.items()) a_items = sorted(a_items) y_items = sorted(y_items) self._ret['a_items'] = a_items self._ret['y_items'] = y_items # map estimated values to original range and extract probabilities self._ret['mapped_values'] = [ self.post_processing(a_item[0]) for a_item in self._ret['a_items'] ] self._ret['values'] = [a_item[0] for a_item in self._ret['a_items']] self._ret['y_values'] = [y_item[0] for y_item in y_items] self._ret['probabilities'] = [ a_item[1] for a_item in self._ret['a_items'] ] self._ret['mapped_items'] = [ (self._ret['mapped_values'][i], self._ret['probabilities'][i]) for i in range(len(self._ret['mapped_values'])) ] # determine most likely estimator self._ret['value'] = None # estimate in [0,1] self._ret['estimation'] = None # estimate mapped to right interval self._ret['max_probability'] = 0 for val, (est, prob) in zip(self._ret['values'], self._ret['mapped_items']): if prob > self._ret['max_probability']: self._ret['max_probability'] = prob self._ret['estimation'] = est self._ret['value'] = val # count the number of Q-oracle calls self._ret['num_oracle_queries'] = self._ret['shots'] * (self._M - 1) # get MLE self._run_mle() # get 95% confidence interval alpha = 0.05 kind = 'likelihood_ratio' # empirically the most precise kind self._ret['95%_confidence_interval'] = self.confidence_interval( alpha, kind) ae_result = AmplitudeEstimationAlgorithmResult() ae_result.a_estimation = self._ret['value'] ae_result.estimation = self._ret['estimation'] ae_result.num_oracle_queries = self._ret['num_oracle_queries'] ae_result.confidence_interval = self._ret['95%_confidence_interval'] result = AmplitudeEstimationResult() result.combine(ae_result) result.ml_value = self._ret['ml_value'] result.mapped_a_samples = self._ret['values'] result.probabilities = self._ret['probabilities'] result.shots = self._ret['shots'] result.mle = self._ret['mle'] if 'statevector' in self._ret: result.circuit_result = self._ret['statevector'] elif 'counts' in self._ret: result.circuit_result = dict(self._ret['counts']) result.a_samples = self._ret['a_items'] result.y_measurements = self._ret['y_items'] result.mapped_values = self._ret['mapped_values'] result.max_probability = self._ret['max_probability'] return result
def _run(self) -> 'VQEAdaptResult': """ Run the algorithm to compute the minimum eigenvalue. Returns: dict: Dictionary of results Raises: AquaError: wrong setting of operator and backend. """ self._ret = {} # TODO should be eliminated self._operator = VQE._config_the_best_mode( self, self._operator, self._quantum_instance.backend) self._use_simulator_snapshot_mode = \ is_aer_statevector_backend(self._quantum_instance.backend) \ and isinstance(self._operator, (WeightedPauliOperator, TPBGroupedWeightedPauliOperator)) self._quantum_instance.circuit_summary = True cycle_regex = re.compile(r'(.+)( \1)+') # reg-ex explanation: # 1. (.+) will match at least one number and try to match as many as possible # 2. the match of this part is placed into capture group 1 # 3. ( \1)+ will match a space followed by the contents of capture group 1 # -> this results in any number of repeating numbers being detected threshold_satisfied = False alternating_sequence = False prev_op_indices = [] theta = [] max_grad = () iteration = 0 while not threshold_satisfied and not alternating_sequence: iteration += 1 logger.info('--- Iteration #%s ---', str(iteration)) # compute gradients cur_grads = self._compute_gradients(self._excitation_pool, theta, self._delta, self._var_form_base, self._operator, self._optimizer) # pick maximum gradient max_grad_index, max_grad = max(enumerate(cur_grads), key=lambda item: np.abs(item[1][0])) # store maximum gradient's index for cycle detection prev_op_indices.append(max_grad_index) # log gradients gradlog = "\nGradients in iteration #{}".format(str(iteration)) gradlog += "\nID: Excitation Operator: Gradient <(*) maximum>" for i, grad in enumerate(cur_grads): gradlog += '\n{}: {}: {}'.format(str(i), str(grad[1]), str(grad[0])) if grad[1] == max_grad[1]: gradlog += '\t(*)' logger.info(gradlog) if np.abs(max_grad[0]) < self._threshold: logger.info( "Adaptive VQE terminated succesfully with a final maximum gradient: %s", str(np.abs(max_grad[0]))) threshold_satisfied = True break # check indices of picked gradients for cycles if cycle_regex.search(' '.join(map(str, prev_op_indices))) is not None: logger.info("Alternating sequence found. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) alternating_sequence = True break # add new excitation to self._var_form_base self._var_form_base.push_hopping_operator(max_grad[1]) theta.append(0.0) # run VQE on current Ansatz algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta) vqe_result = algorithm.run(self._quantum_instance) self._ret['opt_params'] = vqe_result.optimal_point theta = vqe_result.optimal_point.tolist() # once finished evaluate auxiliary operators if any if self._aux_operators is not None and self._aux_operators: algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta, aux_operators=self._aux_operators) vqe_result = algorithm.run(self._quantum_instance) self._ret['opt_params'] = vqe_result.optimal_point if threshold_satisfied: finishing_criterion = 'Threshold converged' elif alternating_sequence: finishing_criterion = 'Aborted due to cyclicity' else: raise AquaError( 'The algorithm finished due to an unforeseen reason!') # extend VQE returned information with additional outputs result = VQEAdaptResult() result.combine(vqe_result) result.num_iterations = iteration result.final_max_gradient = max_grad[0] result.finishing_criterion = finishing_criterion logger.info('The final energy is: %s', str(result.optimal_value.real)) return result
def build_eom_matrices(self, excitations_list, q_commutators, w_commutators, m_commutators, v_commutators, available_entry, wave_fn, quantum_instance=None): """Compute M, V, Q and W matrices. Args: excitations_list (list): single excitations list + double excitation list q_commutators (dict): key: a string of matrix indices; value: the commutators for Q matrix w_commutators (dict): key: a string of matrix indices; value: the commutators for W matrix m_commutators (dict): key: a string of matrix indices; value: the commutators for M matrix v_commutators (dict): key: a string of matrix indices; value: the commutators for V matrix available_entry (int): number of entries in the matrix wave_fn (QuantumCircuit or numpy.ndarray): the circuit generated wave function for the ground state energy quantum_instance (QuantumInstance): a quantum instance with configured settings Returns: numpy.ndarray: M matrix numpy.ndarray: V matrix numpy.ndarray: Q matrix numpy.ndarray: W matrix Raises: AquaError: wrong setting for wave_fn and quantum_instance """ if isinstance(wave_fn, QuantumCircuit) and quantum_instance is None: raise AquaError( "quantum_instance is required when wavn_fn is a QuantumCircuit." ) size = len(excitations_list) logger.info('EoM matrix size is %sx%s.', size, size) # get all to-be-processed index if self._is_eom_matrix_symmetric: mus, nus = np.triu_indices(size) else: mus, nus = np.indices((size, size)) mus = np.asarray(mus.flat) nus = np.asarray(nus.flat) m_mat = np.zeros((size, size), dtype=complex) v_mat = np.zeros((size, size), dtype=complex) q_mat = np.zeros((size, size), dtype=complex) w_mat = np.zeros((size, size), dtype=complex) m_mat_std, v_mat_std, q_mat_std, w_mat_std = 0, 0, 0, 0 if quantum_instance is not None: circuit_names = [] circuits = [] for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] for op in [ q_commutators[m_u][n_u], w_commutators[m_u][n_u], m_commutators[m_u][n_u], v_commutators[m_u][n_u] ]: if op is not None and not op.is_empty(): curr_circuits = op.construct_evaluation_circuit( wave_function=wave_fn, statevector_mode=quantum_instance.is_statevector) for c in curr_circuits: if c.name not in circuit_names: circuits.append(c) circuit_names.append(c.name) result = quantum_instance.execute(circuits) # evaluate results for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] def _get_result(op): mean, std = 0.0, 0.0 if op is not None and not op.is_empty(): mean, std = \ op.evaluate_with_result( result=result, statevector_mode=quantum_instance.is_statevector) return mean, std q_mean, q_std = _get_result(q_commutators[m_u][n_u]) w_mean, w_std = _get_result(w_commutators[m_u][n_u]) m_mean, m_std = _get_result(m_commutators[m_u][n_u]) v_mean, v_std = _get_result(v_commutators[m_u][n_u]) q_mat[m_u][n_u] = q_mean if q_mean != 0.0 else q_mat[m_u][n_u] w_mat[m_u][n_u] = w_mean if w_mean != 0.0 else w_mat[m_u][n_u] m_mat[m_u][n_u] = m_mean if m_mean != 0.0 else m_mat[m_u][n_u] v_mat[m_u][n_u] = v_mean if v_mean != 0.0 else v_mat[m_u][n_u] q_mat_std += q_std w_mat_std += w_std m_mat_std += m_std v_mat_std += v_std else: for idx, _ in enumerate(mus): m_u = mus[idx] n_u = nus[idx] q_mean, q_std = q_commutators[m_u][n_u].evaluate_with_statevector(wave_fn) \ if q_commutators[m_u][n_u] is not None else (0.0, 0.0) w_mean, w_std = w_commutators[m_u][n_u].evaluate_with_statevector(wave_fn) \ if w_commutators[m_u][n_u] is not None else (0.0, 0.0) m_mean, m_std = m_commutators[m_u][n_u].evaluate_with_statevector(wave_fn) \ if m_commutators[m_u][n_u] is not None else (0.0, 0.0) v_mean, v_std = v_commutators[m_u][n_u].evaluate_with_statevector(wave_fn) \ if v_commutators[m_u][n_u] is not None else (0.0, 0.0) q_mat[m_u][n_u] = q_mean if q_mean != 0.0 else q_mat[m_u][n_u] w_mat[m_u][n_u] = w_mean if w_mean != 0.0 else w_mat[m_u][n_u] m_mat[m_u][n_u] = m_mean if m_mean != 0.0 else m_mat[m_u][n_u] v_mat[m_u][n_u] = v_mean if v_mean != 0.0 else v_mat[m_u][n_u] # pylint: disable=unsubscriptable-object if self._is_eom_matrix_symmetric: # pylint: disable=unsubscriptable-object q_mat = q_mat + q_mat.T - np.identity(q_mat.shape[0]) * q_mat w_mat = w_mat + w_mat.T - np.identity(w_mat.shape[0]) * w_mat m_mat = m_mat + m_mat.T - np.identity(m_mat.shape[0]) * m_mat v_mat = v_mat + v_mat.T - np.identity(v_mat.shape[0]) * v_mat q_mat = np.real(q_mat) w_mat = np.real(w_mat) m_mat = np.real(m_mat) v_mat = np.real(v_mat) q_mat_std = q_mat_std / float(available_entry) w_mat_std = w_mat_std / float(available_entry) m_mat_std = m_mat_std / float(available_entry) v_mat_std = v_mat_std / float(available_entry) logger.debug("\nQ:=========================\n%s", q_mat) logger.debug("\nW:=========================\n%s", w_mat) logger.debug("\nM:=========================\n%s", m_mat) logger.debug("\nV:=========================\n%s", v_mat) return m_mat, v_mat, q_mat, w_mat, m_mat_std, v_mat_std, q_mat_std, w_mat_std
def __init__(self, optimizer=None, feature_map=None, var_form=None, training_dataset=None, test_dataset=None, datapoints=None, max_evals_grouped=1, minibatch_size=-1, callback=None): """Initialize the object Args: optimizer (Optimizer): The classical optimizer to use. feature_map (FeatureMap): The FeatureMap instance to use. var_form (VariationalForm): The variational form instance. training_dataset (dict): The training dataset, in the format: {'A': np.ndarray, 'B': np.ndarray, ...}. test_dataset (dict): The test dataset, in same format as `training_dataset`. datapoints (np.ndarray): NxD array, N is the number of data and D is data dimension. max_evals_grouped (int): The maximum number of evaluations to perform simultaneously. minibatch_size (int): The size of a mini-batch. callback (Callable): a callback that can access the intermediate data during the optimization. Internally, four arguments are provided as follows the index of data batch, the index of evaluation, parameters of variational form, evaluated value. Notes: We use `label` to denotes numeric results and `class` the class names (str). """ self.validate(locals()) super().__init__(var_form=var_form, optimizer=optimizer, cost_fn=self._cost_function_wrapper) self._optimizer.set_max_evals_grouped(max_evals_grouped) self._callback = callback if feature_map is None: raise AquaError('Missing feature map.') if training_dataset is None: raise AquaError('Missing training dataset.') self._training_dataset, self._class_to_label = split_dataset_to_data_and_labels( training_dataset) self._label_to_class = { label: class_name for class_name, label in self._class_to_label.items() } self._num_classes = len(list(self._class_to_label.keys())) if test_dataset is not None: self._test_dataset = split_dataset_to_data_and_labels( test_dataset, self._class_to_label) else: self._test_dataset = test_dataset if datapoints is not None and not isinstance(datapoints, np.ndarray): datapoints = np.asarray(datapoints) if len(datapoints) == 0: datapoints = None self._datapoints = datapoints self._minibatch_size = minibatch_size self._eval_count = 0 self._ret = {} self._feature_map = feature_map self._num_qubits = feature_map.num_qubits
def mcmt(self, q_controls, q_ancillae, single_control_gate_fun, q_targets, mode="basic"): """ Apply a Multi-Control, Multi-Target using a generic gate. It can also be used to implement a generic Multi-Control gate, as the target could also be of length 1. Args: self (QuantumCircuit): The QuantumCircuit object to apply the mcmt gate on. q_controls (QuantumRegister | list of Qubit): The list of control qubits q_ancillae (QuantumRegister | list of Qubit): The list of ancillary qubits single_control_gate_fun (Gate): The single control gate function (e.g QuantumCircuit.cz or QuantumCircuit.ch) q_targets (QuantumRegister | list of Qubit): A list of qubits or a QuantumRegister to which the gate function should be applied. mode (str): The implementation mode to use (at the moment, only the basic mode is supported) """ # check controls if isinstance(q_controls, QuantumRegister): control_qubits = [qb for qb in q_controls] elif isinstance(q_controls, list): control_qubits = q_controls else: raise AquaError( 'MCT needs a list of qubits or a quantum register for controls.') # check target if isinstance(q_targets, QuantumRegister): target_qubits = [qb for qb in q_targets] elif isinstance(q_targets, list): target_qubits = q_targets else: raise AquaError( 'MCT needs a list of qubits or a quantum register for targets.') # check ancilla if q_ancillae is None: ancillary_qubits = [] elif isinstance(q_ancillae, QuantumRegister): ancillary_qubits = [qb for qb in q_ancillae] elif isinstance(q_ancillae, list): ancillary_qubits = q_ancillae else: raise AquaError( 'MCT needs None or a list of qubits or a quantum register for ancilla.' ) all_qubits = control_qubits + target_qubits + ancillary_qubits self._check_qargs(all_qubits) self._check_dups(all_qubits) if len(q_controls) == 1: for qubit in target_qubits: single_control_gate_fun(self, q_controls[0], qubit) return if mode == 'basic': # last ancillary qubit is the control of the gate ancn = len(ancillary_qubits) _ccx_v_chain_compute(self, control_qubits, ancillary_qubits) for qubit in target_qubits: single_control_gate_fun(self, ancillary_qubits[ancn - 1], qubit) _ccx_v_chain_uncompute(self, control_qubits, ancillary_qubits) else: raise AquaError( 'Unrecognized mode "{0}" for building mcmt circuit, at the moment only "basic" mode is supported.' .format(mode))
def construct_circuit(self, circuit=None, variable_register=None, clause_register=None, output_register=None, ancillary_register=None, mct_mode='basic'): # pylint: disable=arguments-differ """ Construct circuit. Args: circuit (QuantumCircuit): The optional circuit to extend from variable_register (QuantumRegister): The optional quantum register to use for problem variables clause_register (QuantumRegister): The optional quantum register to use for problem clauses output_register (QuantumRegister): The optional quantum register to use for holding the output ancillary_register (QuantumRegister): The optional quantum register to use as ancilla mct_mode (str): The mode to use for building Multiple-Control Toffoli Returns: QuantumCircuit: quantum circuit. Raises: AquaError: invalid input """ circuit = self._set_up_circuit(circuit=circuit, variable_register=variable_register, clause_register=clause_register, output_register=output_register, ancillary_register=ancillary_register, mct_mode=mct_mode) if self._depth == 0: self._construct_circuit_for_tiny_expr(circuit) elif self._depth == 1: lits = [l[1] for l in self._ast[1:]] flags = BooleanLogicNormalForm._lits_to_flags(lits) if flags is not None: or_circuit = OR(num_variable_qubits=len( self._variable_register), flags=flags, mcx_mode=mct_mode) qubits = self._variable_register[:] + [ self._output_register[0] ] if self._ancillary_register: qubits += self._ancillary_register[:or_circuit. num_ancilla_qubits] circuit.compose(or_circuit, qubits, inplace=True) else: circuit.u(pi, 0, pi, self._output_register[0]) else: # self._depth == 2 # compute all clauses for clause_index, clause_expr in enumerate(self._ast[1:]): if clause_expr[0] == 'and': lits = [l[1] for l in clause_expr[1:]] elif clause_expr[0] == 'lit': lits = [clause_expr[1]] else: raise AquaError( 'Operator "{}" of clause {} in logic expression {} is unexpected.' .format(clause_expr[0], clause_index, self._ast)) flags = BooleanLogicNormalForm._lits_to_flags(lits) if flags is not None: and_circuit = AND(num_variable_qubits=len( self._variable_register), flags=flags, mcx_mode=mct_mode) qubits = self._variable_register[:] + [ self._clause_register[clause_index] ] if self._ancillary_register: qubits += self._ancillary_register[:and_circuit. num_ancilla_qubits] circuit.compose(and_circuit, qubits, inplace=True) else: circuit.u(pi, 0, pi, self._clause_register[clause_index]) # init the output qubit to 1 circuit.u(pi, 0, pi, self._output_register[self._output_idx]) # collect results from all clauses circuit.u(pi, 0, pi, self._clause_register) circuit.mct(self._clause_register, self._output_register[self._output_idx], self._ancillary_register, mode=mct_mode) circuit.u(pi, 0, pi, self._clause_register) # uncompute all clauses for clause_index, clause_expr in enumerate(self._ast[1:]): if clause_expr[0] == 'and': lits = [l[1] for l in clause_expr[1:]] elif clause_expr[0] == 'lit': lits = [clause_expr[1]] flags = BooleanLogicNormalForm._lits_to_flags(lits) if flags is not None: and_circuit = AND(num_variable_qubits=len( self._variable_register), flags=flags, mcx_mode=mct_mode) qubits = self._variable_register[:] + [ self._clause_register[clause_index] ] if self._ancillary_register: qubits += self._ancillary_register[:and_circuit. num_ancilla_qubits] circuit.compose(and_circuit, qubits, inplace=True) else: circuit.u(pi, 0, pi, self._clause_register[clause_index]) return circuit
def __init__(self, operator=None, state_in=None, iqft=None, num_time_slices=1, num_ancillae=1, expansion_mode='trotter', expansion_order=1, evo_time=2 * np.pi, state_in_circuit_factory=None, unitary_circuit_factory=None, shallow_circuit_concat=False, pauli_list=None): """ Constructor. Args: operator (WeightedPauliOperator): the hamiltonian Operator object state_in (InitialState): the InitialState pluggable component representing the initial quantum state iqft (IQFT): the Inverse Quantum Fourier Transform pluggable component num_time_slices (int): the number of time slices num_ancillae (int): the number of ancillary qubits to use for the measurement expansion_mode (str): the expansion mode (trotter|suzuki) expansion_order (int): the suzuki expansion order evo_time (float): the evolution time state_in_circuit_factory (CircuitFactory): the initial state represented by a CircuitFactory object unitary_circuit_factory (CircuitFactory): the problem unitary represented by a CircuitFactory object shallow_circuit_concat (bool): indicate whether to use shallow (cheap) mode for circuit concatenation pauli_list (list[Pauli]): the flat list of paulis for the operator Raises: AquaError: Missing input """ if (operator is not None and unitary_circuit_factory is not None) or \ (operator is None and unitary_circuit_factory is None): raise AquaError( 'Please supply either an operator or a unitary circuit ' 'factory but not both.') self._operator = operator if operator is not None: self._pauli_list = operator.reorder_paulis( ) if pauli_list is None else pauli_list self._unitary_circuit_factory = unitary_circuit_factory self._state_in = state_in self._state_in_circuit_factory = state_in_circuit_factory self._iqft = iqft self._num_time_slices = num_time_slices self._num_ancillae = num_ancillae self._expansion_mode = expansion_mode self._expansion_order = expansion_order self._evo_time = evo_time self._shallow_circuit_concat = shallow_circuit_concat self._ancilla_phase_coef = 1 self._state_register = None self._ancillary_register = None self._auxiliary_register = None self._circuit = None
def _run(self) -> 'VQEAdaptResult': """ Run the algorithm to compute the minimum eigenvalue. Returns: dict: Dictionary of results Raises: AquaError: wrong setting of operator and backend. """ self._ret = {} # TODO should be eliminated # self._operator = VQE._config_the_best_mode(self, self._operator, # self._quantum_instance.backend) self._quantum_instance.circuit_summary = True threshold_satisfied = False alternating_sequence = False max_iterations_exceeded = False prev_op_indices = [] theta = [] # type: List max_grad = (0, 0) iteration = 0 while self._max_iterations is None or iteration < self._max_iterations: iteration += 1 logger.info('--- Iteration #%s ---', str(iteration)) # compute gradients cur_grads = self._compute_gradients(self._excitation_pool, theta, self._delta, self._var_form_base, self._operator, self._optimizer) # pick maximum gradient max_grad_index, max_grad = max(enumerate(cur_grads), key=lambda item: np.abs(item[1][0])) # store maximum gradient's index for cycle detection prev_op_indices.append(max_grad_index) # log gradients gradlog = "\nGradients in iteration #{}".format(str(iteration)) gradlog += "\nID: Excitation Operator: Gradient <(*) maximum>" for i, grad in enumerate(cur_grads): gradlog += '\n{}: {}: {}'.format(str(i), str(grad[1]), str(grad[0])) if grad[1] == max_grad[1]: gradlog += '\t(*)' logger.info(gradlog) if np.abs(max_grad[0]) < self._threshold: logger.info( "Adaptive VQE terminated succesfully with a final maximum gradient: %s", str(np.abs(max_grad[0]))) threshold_satisfied = True break # check indices of picked gradients for cycles if VQEAdapt._check_cyclicity(prev_op_indices): logger.info("Alternating sequence found. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) alternating_sequence = True break # add new excitation to self._var_form_base self._var_form_base.push_hopping_operator(max_grad[1]) theta.append(0.0) # run VQE on current Ansatz algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta) vqe_result = algorithm.run(self._quantum_instance) self._ret['opt_params'] = vqe_result.optimal_point theta = vqe_result.optimal_point.tolist() else: # reached maximum number of iterations max_iterations_exceeded = True logger.info("Maximum number of iterations reached. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) # once finished evaluate auxiliary operators if any if self._aux_operators is not None and self._aux_operators: algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta, aux_operators=self._aux_operators) vqe_result = algorithm.run(self._quantum_instance) self._ret['opt_params'] = vqe_result.optimal_point if threshold_satisfied: finishing_criterion = 'Threshold converged' elif alternating_sequence: finishing_criterion = 'Aborted due to cyclicity' elif max_iterations_exceeded: finishing_criterion = 'Maximum number of iterations reached' else: raise AquaError( 'The algorithm finished due to an unforeseen reason!') # extend VQE returned information with additional outputs result = VQEAdaptResult() result.combine(vqe_result) result.num_iterations = iteration result.final_max_gradient = max_grad[0] result.finishing_criterion = finishing_criterion logger.info('The final energy is: %s', str(result.optimal_value.real)) return result
def construct_circuit( self, circuit=None, variable_register=None, clause_register=None, output_register=None, ancillary_register=None, mct_mode='basic' ): """ Construct circuit. Args: circuit (QuantumCircuit): The optional circuit to extend from variable_register (QuantumRegister): The optional quantum register to use for problem variables clause_register (QuantumRegister): The optional quantum register to use for problem clauses output_register (QuantumRegister): The optional quantum register to use for holding the output ancillary_register (QuantumRegister): The optional quantum register to use as ancilla mct_mode (str): The mode to use for building Multiple-Control Toffoli Returns: QuantumCircuit: quantum circuit. """ circuit = self._set_up_circuit( circuit=circuit, variable_register=variable_register, clause_register=clause_register, output_register=output_register, ancillary_register=ancillary_register, mct_mode=mct_mode ) if self._depth == 0: self._construct_circuit_for_tiny_expr(circuit) elif self._depth == 1: circuit.u3(pi, 0, pi, self._variable_register) circuit.u3(pi, 0, pi, self._output_register) lits = [l[1] for l in self._ast[1:]] logic_or( lits, circuit, self._variable_register, self._output_register[0], self._ancillary_register, mct_mode ) else: # self._depth == 2 # compute all clauses for clause_index, clause_expr in enumerate(self._ast[1:]): if clause_expr[0] == 'and': lits = [l[1] for l in clause_expr[1:]] elif clause_expr[0] == 'lit': lits = [clause_expr[1]] else: raise AquaError( 'Operator "{}" of clause {} in logic expression {} is unexpected.'.format( clause_expr[0], clause_index, self._ast) ) logic_and( lits, circuit, self._variable_register, self._clause_register[clause_index], self._ancillary_register, mct_mode ) # init the output qubit to 1 circuit.u3(pi, 0, pi, self._output_register[self._output_idx]) # collect results from all clauses circuit.u3(pi, 0, pi, self._clause_register) circuit.mct( self._clause_register, self._output_register[self._output_idx], self._ancillary_register, mode=mct_mode ) circuit.u3(pi, 0, pi, self._clause_register) # uncompute all clauses for clause_index, clause_expr in enumerate(self._ast[1:]): if clause_expr[0] == 'and': lits = [l[1] for l in clause_expr[1:]] else: # clause_expr[0] == 'lit': lits = [clause_expr[1]] logic_and( lits, circuit, self._variable_register, self._clause_register[clause_index], self._ancillary_register, mct_mode ) return circuit
def get_optimal_circuit(self): if 'opt_params' not in self._ret: raise AquaError("Cannot find optimal circuit before running the " "algorithm to find optimal params.") return self._var_form_base.construct_circuit(self._ret['opt_params'])
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: # type: ignore raise AquaError("The operator was never provided.") self._check_operator_varform() self._quantum_instance.circuit_summary = True self._eval_count = 0 # initial orbital rotation starting point is provided if self._orbital_rotation.matrix_a is not None and self._orbital_rotation.matrix_b is not \ None: self._qmolecule_rotated = copy.copy(self._qmolecule) OOVQE._rotate_orbitals_in_qmolecule(self._qmolecule_rotated, self._orbital_rotation) self._operator, _ = self._core.run(self._qmolecule_rotated) logger.info( '\n\nSetting the initial value for OO matrices and rotating Hamiltonian \n' ) logger.info('Optimising Orbital Coefficient Rotation Alpha: \n%s', repr(self._orbital_rotation.matrix_a)) logger.info('Optimising Orbital Coefficient Rotation Beta: \n%s', repr(self._orbital_rotation.matrix_b)) # save the original number of parameters as we modify their number to bypass the # error checks that are not tailored to OOVQE total_time = 0 # iterative method if self._iterative_oo: for _ in range(self._iterative_oo_iterations): # optimize wavefunction ansatz self.var_form._num_parameters = self.var_form_num_parameters if isinstance(self.operator, LegacyBaseOperator): # type: ignore self.operator = self.operator.to_opflow() # type: ignore self.var_form._bounds = self.var_form_bounds vqresult_wavefun = self.find_minimum( initial_point=self.initial_point[:self. var_form_num_parameters], var_form=self.var_form, cost_fn=self._energy_evaluation, optimizer=self.optimizer) self.initial_point[:self. var_form_num_parameters] = vqresult_wavefun.optimal_point # optimize orbitals self.var_form._bounds = self._bound_oo self.var_form._num_parameters = self._orbital_rotation.num_parameters self._fixed_wavefunction_params = vqresult_wavefun.optimal_point vqresult = self.find_minimum( initial_point=self.initial_point[self. var_form_num_parameters:], var_form=self.var_form, cost_fn=self._energy_evaluation_oo, optimizer=self.optimizer) self.initial_point[ self.var_form_num_parameters:] = vqresult.optimal_point total_time += vqresult.optimizer_time else: # simultaneous method (ansatz and orbitals are optimized at the same time) self.var_form._bounds = self._bounds self.var_form._num_parameters = len(self._bounds) vqresult = self.find_minimum(initial_point=self.initial_point, var_form=self.var_form, cost_fn=self._energy_evaluation_oo, optimizer=self.optimizer) total_time += vqresult.optimizer_time # write original number of parameters to avoid errors due to parameter number mismatch self.var_form._num_parameters = self.var_form_num_parameters # save the results self._ret = {} self._ret['num_optimizer_evals'] = vqresult.optimizer_evals self._ret['min_val'] = vqresult.optimal_value if self._iterative_oo: self._ret['opt_params'] = self.initial_point[ self.var_form_num_parameters:] self._ret[ 'opt_params_orbitals'] = self.initial_point[:self. var_form_num_parameters] else: self._ret[ 'opt_params'] = vqresult.optimal_point[:self. var_form_num_parameters] self._ret['opt_params_orbitals'] = vqresult.optimal_point[ self.var_form_num_parameters:] self._ret['eval_time'] = total_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 = OOVQEResult() result.combine(vqresult) result.optimal_point_orbitals = self._ret["opt_params_orbitals"] result.eigenvalue = vqresult.optimal_value + 0j # record all parameters (wavefunction and orbitals) to overcome error checks _ret_temp_params = copy.copy(self._ret['opt_params']) self._ret['opt_params'] = self._ret[ 'opt_params'][:self.var_form_num_parameters] result.eigenstate = self.get_optimal_vector() self._ret['opt_params'] = _ret_temp_params self._ret['energy'] = self.get_optimal_cost() self._ret['eigvals'] = np.asarray([self._ret['energy']]) self._ret['eigvecs'] = np.asarray([result.eigenstate]) if self.aux_operators: 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