Source code for mindquantum.simulator.mqchem.vqe_preparation

# Copyright 2025 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""High-level VQE preparation factory for MQChemSimulator."""

import numpy as np

from mindquantum.simulator import mqchem
from ...core.circuit import Circuit
from ...core.operators import FermionOperator, InteractionOperator
from ...algorithm.nisq.chem import uccsd_singlet_generator, uccsd_singlet_get_packed_amplitudes


[docs]def prepare_uccsd_vqe(molecular, threshold: float = 1e-6): """ Prepare all components for a UCCSD-VQE simulation with the MQChemSimulator. This factory function streamlines the setup for a VQE simulation by: 1. Generating all singlet UCCSD excitation operators using :function:`~.algorithm.nisq.chem.uccsd_singlet_generator`. 2. Extracting the corresponding amplitudes from a pre-computed CCSD calculation included in the `molecular` data. 3. Filtering excitations based on their CCSD amplitudes via the `threshold`. 4. Constructing a parameterized UCCSD ansatz circuit using :class:`~.simulator.mqchem.UCCExcitationGate`. 5. Creating a :class:`~.simulator.mqchem.CIHamiltonian` for expectation evaluation. 6. Returning all necessary components to run a VQE experiment. Args: molecular (openfermion.MolecularData): Molecular data object that must contain CCSD calculation results. threshold (float): The threshold for CCSD amplitudes. Excitations with amplitudes below this value will be discarded. Default: ``1e-6``. Returns: - **hamiltonian** (mqchem.CIHamiltonian), The CI-space Hamiltonian. - **ansatz_circuit** (Circuit), The parameterized UCCSD ansatz circuit. - **initial_amplitudes** (numpy.ndarray), The CCSD amplitudes corresponding to the parameters in `ansatz_circuit`, suitable as an initial guess for an optimizer. Examples: >>> from openfermionpyscf import run_pyscf >>> from openfermion import MolecularData >>> from scipy.optimize import minimize >>> from mindquantum.simulator import mqchem >>> >>> molecule = MolecularData([("H", (i, 0, 0)) for i in range(6)], 'sto-3g', 1, 0) >>> mol = run_pyscf(molecule, run_ccsd=True) >>> hamiltonian, ansatz_circuit, initial_amplitudes = mqchem.prepare_uccsd_vqe(mol, 1e-3) >>> >>> simulator = mqchem.MQChemSimulator(mol.n_qubits, mol.n_electrons) >>> grad_ops = simulator.get_expectation_with_grad(hamiltonian, ansatz_circuit) >>> >>> result = minimize(grad_ops, initial_amplitudes, method='L-BFGS-B', jac=True) >>> print(f"VQE energy: {result.fun}") VQE energy: -3.2354494505390528 """ ham_of = molecular.get_molecular_hamiltonian() inter_ops = InteractionOperator(*ham_of.n_body_tensors.values()) fermion_ham = FermionOperator(inter_ops).normal_ordered() hamiltonian = mqchem.CIHamiltonian(fermion_ham) excitation_generator = uccsd_singlet_generator(molecular.n_qubits, molecular.n_electrons, anti_hermitian=False) if molecular.ccsd_single_amps is None or molecular.ccsd_double_amps is None: raise ValueError("Molecular data must contain CCSD amplitudes. Please run pyscf with 'run_ccsd=True'.") packed_amplitudes = uccsd_singlet_get_packed_amplitudes( molecular.ccsd_single_amps, molecular.ccsd_double_amps, molecular.n_qubits, molecular.n_electrons, ) ansatz_circuit = Circuit() for term_op in excitation_generator: param_names = term_op.singlet_coeff().params_name include_gate = False for p_name in param_names: if abs(packed_amplitudes[p_name]) > threshold: include_gate = True break if include_gate: gate = mqchem.UCCExcitationGate(term_op) ansatz_circuit += gate ordered_params = ansatz_circuit.params_name initial_amplitudes = [packed_amplitudes[p] for p in ordered_params] return hamiltonian, ansatz_circuit, np.array(initial_amplitudes)