Exemplo n.º 1
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        result.hartree_fock_energy = self._reference_energy
        result.nuclear_repulsion_energy = self._nuclear_repulsion_energy
        result.extracted_transformer_energies = self._shift.copy()
Exemplo n.º 2
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        result.nuclear_dipole_moment = self._nuclear_dipole_moment
        result.reverse_dipole_sign = self._reverse_dipole_sign
        result.computed_dipole_moment = []
        result.extracted_transformer_dipoles = []

        if not isinstance(result.aux_operator_eigenvalues, list):
            aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
        else:
            aux_operator_eigenvalues = result.aux_operator_eigenvalues

        for aux_op_eigenvalues in aux_operator_eigenvalues:
            if aux_op_eigenvalues is None:
                continue

            if isinstance(aux_op_eigenvalues,
                          list) and len(aux_op_eigenvalues) < 6:
                continue

            axes_order = {"x": 0, "y": 1, "z": 2}
            dipole_moment = [None] * 3
            for prop in iter(self):
                moment: Optional[tuple[complex, complex]]
                try:
                    moment = aux_op_eigenvalues[axes_order[prop._axis] + 3]
                except KeyError:
                    moment = aux_op_eigenvalues.get(prop.name, None)
                if moment is not None:
                    dipole_moment[axes_order[
                        prop._axis]] = moment[0].real  # type: ignore

            result.computed_dipole_moment.append(
                cast(DipoleTuple, tuple(dipole_moment)))
            dipole_shifts: dict[str, dict[str, complex]] = {}
            for prop in self._properties.values():
                for name, shift in prop._shift.items():
                    if name not in dipole_shifts:
                        dipole_shifts[name] = {}
                    dipole_shifts[name][prop._axis] = shift

            result.extracted_transformer_dipoles.append({
                name: cast(DipoleTuple, (shift["x"], shift["y"], shift["z"]))
                for name, shift in dipole_shifts.items()
            })
Exemplo n.º 3
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        result.num_occupied_modals_per_mode = []

        if not isinstance(result.aux_operator_eigenvalues, list):
            aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
        else:
            aux_operator_eigenvalues = result.aux_operator_eigenvalues

        num_modes = len(self._basis._num_modals_per_mode)

        for aux_op_eigenvalues in aux_operator_eigenvalues:
            occ_modals = []
            for mode in range(num_modes):
                _key = str(mode) if isinstance(aux_op_eigenvalues,
                                               dict) else mode
                if aux_op_eigenvalues[_key] is not None:
                    occ_modals.append(aux_op_eigenvalues[_key][0].real)
                else:
                    occ_modals.append(None)
            result.num_occupied_modals_per_mode.append(occ_modals)
 def test_interpret(self):
     """Tests that the result is interpreted"""
     num_nodes = 4
     boundary_condition = BoundaryCondition.OPEN
     line_lattice = LineLattice(num_nodes=num_nodes,
                                boundary_condition=boundary_condition)
     fhm = FermiHubbardModel(lattice=line_lattice, onsite_interaction=5.0)
     eigenenergies = np.array([-1])
     eigenstates = [np.array([1, 0])]
     aux_operator_eigenvalues = [(1, 2)]
     # For EigenstateResult
     lmp = LatticeModelProblem(fhm)
     eigenstate_result = EigenstateResult()
     eigenstate_result.eigenenergies = eigenenergies
     eigenstate_result.eigenstates = eigenstates
     eigenstate_result.aux_operator_eigenvalues = aux_operator_eigenvalues
     lmr = lmp.interpret(eigenstate_result)
     self.assertEqual(lmr.eigenenergies, eigenstate_result.eigenenergies)
     self.assertEqual(lmr.eigenstates, eigenstate_result.eigenstates)
     self.assertEqual(lmr.aux_operator_eigenvalues,
                      eigenstate_result.aux_operator_eigenvalues)
     # For EigenSOlverResult
     lmp = LatticeModelProblem(fhm)
     eigensolver_result = EigensolverResult()
     eigensolver_result.eigenvalues = eigenenergies
     eigensolver_result.eigenstates = eigenstates
     eigensolver_result.aux_operator_eigenvalues = [
         aux_operator_eigenvalues
     ]
     lmr = lmp.interpret(eigensolver_result)
     self.assertEqual(lmr.eigenenergies, eigensolver_result.eigenvalues)
     self.assertEqual(lmr.eigenstates, eigensolver_result.eigenstates)
     self.assertEqual(lmr.aux_operator_eigenvalues,
                      eigensolver_result.aux_operator_eigenvalues)
     # For MinimumEigensolverResult
     lmp = LatticeModelProblem(fhm)
     mes_result = MinimumEigensolverResult()
     mes_result.eigenvalue = -1
     mes_result.eigenstate = np.array([1, 0])
     mes_result.aux_operator_eigenvalues = aux_operator_eigenvalues
     lmr = lmp.interpret(mes_result)
     self.assertEqual(lmr.eigenenergies,
                      np.asarray([mes_result.eigenvalue]))
     self.assertEqual(lmr.eigenstates, [mes_result.eigenstate])
     self.assertEqual(lmr.aux_operator_eigenvalues,
                      [mes_result.aux_operator_eigenvalues])
    def solve(
        self,
        problem: BaseProblem,
        aux_operators: Optional[List[Union[SecondQuantizedOp,
                                           PauliSumOp]]] = None,
    ) -> EigenstateResult:
        """Compute Ground and Excited States properties.

        Args:
            problem: a class encoding a problem to be solved.
            aux_operators: Additional auxiliary operators to evaluate.

        Raises:
            NotImplementedError: If an operator in ``aux_operators`` is not of type
                ``FermionicOperator``.

        Returns:
            An interpreted :class:`~.EigenstateResult`. For more information see also
            :meth:`~.BaseProblem.interpret`.
        """
        # get the operator and auxiliary operators, and transform the provided auxiliary operators
        # note that ``aux_operators`` contains not only the transformed ``aux_operators`` passed
        # by the user but also additional ones from the transformation
        second_q_ops = problem.second_q_ops()

        main_operator = self._qubit_converter.convert(
            second_q_ops[0],
            num_particles=problem.num_particles,
            sector_locator=problem.symmetry_sector_locator,
        )
        aux_ops = self._qubit_converter.convert_match(second_q_ops[1:])

        if aux_operators is not None:
            for aux_op in aux_operators:
                if isinstance(aux_op, SecondQuantizedOp):
                    aux_ops.append(
                        self._qubit_converter.convert_match(aux_op, True))
                else:
                    aux_ops.append(aux_op)

        if isinstance(self._solver, EigensolverFactory):
            # this must be called after transformation.transform
            solver = self._solver.get_solver(problem)
        else:
            solver = self._solver

        # if the eigensolver does not support auxiliary operators, reset them
        if not solver.supports_aux_operators():
            aux_ops = None

        raw_es_result = solver.compute_eigenvalues(main_operator, aux_ops)

        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_es_result
        eigenstate_result.eigenenergies = raw_es_result.eigenvalues
        eigenstate_result.eigenstates = raw_es_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = raw_es_result.aux_operator_eigenvalues
        result = problem.interpret(eigenstate_result)
        return result
Exemplo n.º 6
0
    def solve(
        self,
        driver: BaseDriver,
        aux_operators: Optional[List[Any]] = None
    ) -> Union[ElectronicStructureResult, VibronicStructureResult]:
        """Compute Ground and Excited States properties.

        Args:
            driver: a chemistry driver object which defines the chemical problem that is to be
                    solved by this calculation.
            aux_operators: Additional auxiliary operators to evaluate. Must be of type
                ``FermionicOperator`` if the qubit transformation is fermionic and of type
                ``BosonicOperator`` it is bosonic.

        Raises:
            NotImplementedError: If an operator in ``aux_operators`` is not of type
                ``FermionicOperator``.

        Returns:
            An eigenstate result. Depending on the transformation this can be an electronic
            structure or bosonic result.
        """
        if aux_operators is not None:
            if any(not isinstance(op, (PauliSumOp, FermionicOperator))
                   for op in aux_operators):
                raise NotImplementedError(
                    'Currently only fermionic problems are supported.')

        # get the operator and auxiliary operators, and transform the provided auxiliary operators
        # note that ``aux_operators`` contains not only the transformed ``aux_operators`` passed
        # by the user but also additional ones from the transformation
        operator, aux_operators = self.transformation.transform(
            driver, aux_operators)

        if isinstance(self._solver, EigensolverFactory):
            # this must be called after transformation.transform
            solver = self._solver.get_solver(self.transformation)
        else:
            solver = self._solver

        # if the eigensolver does not support auxiliary operators, reset them
        if not solver.supports_aux_operators():
            aux_operators = None

        raw_es_result = solver.compute_eigenvalues(operator, aux_operators)

        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_es_result
        eigenstate_result.eigenenergies = raw_es_result.eigenvalues
        eigenstate_result.eigenstates = raw_es_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = raw_es_result.aux_operator_eigenvalues
        result = self.transformation.interpret(eigenstate_result)
        return result
Exemplo n.º 7
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        result.magnetization = []

        if not isinstance(result.aux_operator_eigenvalues, list):
            aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
        else:
            aux_operator_eigenvalues = result.aux_operator_eigenvalues
        for aux_op_eigenvalues in aux_operator_eigenvalues:
            if aux_op_eigenvalues is None:
                continue

            _key = self.name if isinstance(aux_op_eigenvalues, dict) else 2

            if aux_op_eigenvalues[_key] is not None:
                result.magnetization.append(aux_op_eigenvalues[_key][0].real)
            else:
                result.magnetization.append(None)
Exemplo n.º 8
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        expected = self.spin
        result.total_angular_momentum = []

        if not isinstance(result.aux_operator_eigenvalues, list):
            aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
        else:
            aux_operator_eigenvalues = result.aux_operator_eigenvalues
        for aux_op_eigenvalues in aux_operator_eigenvalues:
            if aux_op_eigenvalues is None:
                continue

            _key = self.name if isinstance(aux_op_eigenvalues, dict) else 1

            if aux_op_eigenvalues[_key] is not None:
                total_angular_momentum = aux_op_eigenvalues[_key][0].real
                result.total_angular_momentum.append(total_angular_momentum)

                if expected is not None:
                    spin = (-1.0 + np.sqrt(1 + 4 * total_angular_momentum)) / 2
                    if not np.isclose(
                            spin,
                            expected,
                            rtol=self._relative_tolerance,
                            atol=self._absolute_tolerance,
                    ):
                        LOGGER.info(
                            "The measured spin %s does NOT match the expected spin %s!",
                            spin,
                            expected,
                        )
            else:
                result.total_angular_momentum.append(None)
Exemplo n.º 9
0
    def interpret(self, result: EigenstateResult) -> None:
        """Interprets an :class:`~qiskit_nature.results.EigenstateResult` in this property's context.

        Args:
            result: the result to add meaning to.
        """
        expected = self.num_alpha + self.num_beta
        result.num_particles = []

        if not isinstance(result.aux_operator_eigenvalues, list):
            aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
        else:
            aux_operator_eigenvalues = result.aux_operator_eigenvalues
        for aux_op_eigenvalues in aux_operator_eigenvalues:
            if aux_op_eigenvalues is None:
                continue

            _key = self.name if isinstance(aux_op_eigenvalues, dict) else 0

            if aux_op_eigenvalues[_key] is not None:
                n_particles = aux_op_eigenvalues[_key][0].real
                result.num_particles.append(n_particles)

                if not np.isclose(
                        n_particles,
                        expected,
                        rtol=self._relative_tolerance,
                        atol=self._absolute_tolerance,
                ):
                    LOGGER.info(
                        "The measured number of particles %s does NOT match the expected number of "
                        "particles %s!",
                        n_particles,
                        expected,
                    )
            else:
                result.num_particles.append(None)
Exemplo n.º 10
0
    def solve(
        self,
        problem: BaseProblem,
        aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp, PauliSumOp]]] = None,
    ) -> EigenstateResult:
        """Compute Ground and Excited States properties.

        Args:
            problem: a class encoding a problem to be solved.
            aux_operators: Additional auxiliary operators to evaluate.

        Raises:
            ValueError: if the grouped property object returned by the driver does not contain a
                main property as requested by the problem being solved (`problem.main_property_name`)
            QiskitNatureError: if the user-provided `aux_operators` contain a name which clashes
                with an internally constructed auxiliary operator. Note: the names used for the
                internal auxiliary operators correspond to the `Property.name` attributes which
                generated the respective operators.

        Returns:
            An interpreted :class:`~.EigenstateResult`. For more information see also
            :meth:`~.BaseProblem.interpret`.
        """
        # get the operator and auxiliary operators, and transform the provided auxiliary operators
        # note that ``aux_operators`` contains not only the transformed ``aux_operators`` passed
        # by the user but also additional ones from the transformation

        main_operator, aux_ops = self.get_qubit_operators(problem, aux_operators)
        raw_es_result = self._solver.compute_eigenvalues(main_operator, aux_ops)  # type: ignore

        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_es_result
        eigenstate_result.eigenenergies = raw_es_result.eigenvalues
        eigenstate_result.eigenstates = raw_es_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = raw_es_result.aux_operator_eigenvalues
        result = problem.interpret(eigenstate_result)
        return result
Exemplo n.º 11
0
    def solve(
        self,
        driver: BaseDriver,
        aux_operators: Optional[Union[List[FermionicOperator],
                                      List[BosonicOperator]]] = None
    ) -> Union[ElectronicStructureResult, VibronicStructureResult]:
        """Run the excited-states calculation.

        Construct and solves the EOM pseudo-eigenvalue problem to obtain the excitation energies
        and the excitation operators expansion coefficients.

        Args:
            driver: a chemistry driver object which defines the chemical problem that is to be
                    solved by this calculation.
            aux_operators: Additional auxiliary operators to evaluate. Must be of type
                ``FermionicOperator`` if the qubit transformation is fermionic and of type
                ``BosonicOperator`` it is bosonic.

        Returns:
            The excited states result. In case of a fermionic problem a
            ``ElectronicStructureResult`` is returned and in the bosonic case a
            ``VibronicStructureResult``.
        """

        if aux_operators is not None:
            logger.warning(
                "With qEOM the auxiliary operators can currently only be "
                "evaluated on the ground state.")

        # 1. Run ground state calculation
        groundstate_result = self._gsc.solve(driver, aux_operators)

        # 2. Prepare the excitation operators
        matrix_operators_dict, size = self._prepare_matrix_operators()

        # 3. Evaluate eom operators
        measurement_results = self._gsc.evaluate_operators(
            groundstate_result.raw_result['eigenstate'], matrix_operators_dict)
        measurement_results = cast(Dict[str, List[float]], measurement_results)

        # 4. Post-process ground_state_result to construct eom matrices
        m_mat, v_mat, q_mat, w_mat, m_mat_std, v_mat_std, q_mat_std, w_mat_std = \
            self._build_eom_matrices(measurement_results, size)

        # 5. solve pseudo-eigenvalue problem
        energy_gaps, expansion_coefs = self._compute_excitation_energies(
            m_mat, v_mat, q_mat, w_mat)

        qeom_result = QEOMResult()
        qeom_result.ground_state_raw_result = groundstate_result.raw_result
        qeom_result.expansion_coefficients = expansion_coefs
        qeom_result.excitation_energies = energy_gaps
        qeom_result.m_matrix = m_mat
        qeom_result.v_matrix = v_mat
        qeom_result.q_matrix = q_mat
        qeom_result.w_matrix = w_mat
        qeom_result.m_matrix_std = m_mat_std
        qeom_result.v_matrix_std = v_mat_std
        qeom_result.q_matrix_std = q_mat_std
        qeom_result.w_matrix_std = w_mat_std

        eigenstate_result = EigenstateResult()
        eigenstate_result.eigenstates = groundstate_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = groundstate_result.aux_operator_eigenvalues
        eigenstate_result.raw_result = qeom_result

        eigenstate_result.eigenenergies = np.append(
            groundstate_result.eigenenergies,
            np.asarray([
                groundstate_result.eigenenergies[0] + gap
                for gap in energy_gaps
            ]))

        result = self._gsc.transformation.interpret(eigenstate_result)

        return result
 def test_groundenergy(self):
     """Tests ground energy"""
     eigenstate_result = EigenstateResult()
     eigenstate_result.eigenenergies = np.array([1, 2, 3])
     self.assertEqual(eigenstate_result.groundenergy, 1)
Exemplo n.º 13
0
    def interpret(
        self, raw_result: Union[EigenstateResult, EigensolverResult,
                                MinimumEigensolverResult]
    ) -> ElectronicStructureResult:
        """Interprets an EigenstateResult in the context of this transformation.

        Args:
            raw_result: an eigenstate result object.

        Returns:
            An electronic structure result.
        """
        eigenstate_result = None
        if isinstance(raw_result, EigenstateResult):
            eigenstate_result = raw_result
        elif isinstance(raw_result, EigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = raw_result.eigenvalues
            eigenstate_result.eigenstates = raw_result.eigenstates
            eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
        elif isinstance(raw_result, MinimumEigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = np.asarray(
                [raw_result.eigenvalue])
            eigenstate_result.eigenstates = [raw_result.eigenstate]
            eigenstate_result.aux_operator_eigenvalues = [
                raw_result.aux_operator_eigenvalues
            ]

        result = ElectronicStructureResult()
        result.combine(eigenstate_result)
        result.computed_energies = np.asarray(
            [e.real for e in eigenstate_result.eigenenergies])
        result.hartree_fock_energy = self._hf_energy
        result.nuclear_repulsion_energy = self._nuclear_repulsion_energy
        if self._nuclear_dipole_moment is not None:
            result.nuclear_dipole_moment = tuple(
                x for x in self._nuclear_dipole_moment)
        result.ph_extracted_energy = self._ph_energy_shift
        result.frozen_extracted_energy = self._energy_shift
        if result.aux_operator_eigenvalues is not None:
            # the first three values are hardcoded to number of particles, angular momentum
            # and magnetization in this order
            result.num_particles = []
            result.total_angular_momentum = []
            result.magnetization = []
            result.computed_dipole_moment = []
            result.ph_extracted_dipole_moment = []
            result.frozen_extracted_dipole_moment = []
            if not isinstance(result.aux_operator_eigenvalues, list):
                aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
            else:
                aux_operator_eigenvalues = result.aux_operator_eigenvalues  # type: ignore
            for aux_op_eigenvalues in aux_operator_eigenvalues:
                if aux_op_eigenvalues is None:
                    continue
                if aux_op_eigenvalues[0] is not None:
                    result.num_particles.append(
                        aux_op_eigenvalues[0][0].real)  # type: ignore

                if aux_op_eigenvalues[1] is not None:
                    result.total_angular_momentum.append(
                        aux_op_eigenvalues[1][0].real)  # type: ignore

                if aux_op_eigenvalues[2] is not None:
                    result.magnetization.append(
                        aux_op_eigenvalues[2][0].real)  # type: ignore

                # the next three are hardcoded to Dipole moments, if they are set
                if len(aux_op_eigenvalues) >= 6 and self._has_dipole_moments:
                    # check if the names match
                    # extract dipole moment in each axis
                    dipole_moment = []
                    for moment in aux_op_eigenvalues[3:6]:
                        if moment is not None:
                            dipole_moment += [moment[0].real]  # type: ignore
                        else:
                            dipole_moment += [None]

                    result.reverse_dipole_sign = self._reverse_dipole_sign
                    result.computed_dipole_moment.append(
                        cast(DipoleTuple, tuple(dipole_moment)))
                    result.ph_extracted_dipole_moment.append(
                        (self._ph_x_dipole_shift, self._ph_y_dipole_shift,
                         self._ph_z_dipole_shift))
                    result.frozen_extracted_dipole_moment.append(
                        (self._x_dipole_shift, self._y_dipole_shift,
                         self._z_dipole_shift))

        return result
Exemplo n.º 14
0
    def interpret(
        self,
        raw_result: Union[EigenstateResult, EigensolverResult,
                          MinimumEigensolverResult],
    ) -> ElectronicStructureResult:
        """Interprets an EigenstateResult in the context of this transformation.

        Args:
            raw_result: an eigenstate result object.

        Returns:
            An electronic structure result.
        """
        eigenstate_result = None
        if isinstance(raw_result, EigenstateResult):
            eigenstate_result = raw_result
        elif isinstance(raw_result, EigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = raw_result.eigenvalues
            eigenstate_result.eigenstates = raw_result.eigenstates
            eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
        elif isinstance(raw_result, MinimumEigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = np.asarray(
                [raw_result.eigenvalue])
            eigenstate_result.eigenstates = [raw_result.eigenstate]
            eigenstate_result.aux_operator_eigenvalues = [
                raw_result.aux_operator_eigenvalues
            ]
        result = ElectronicStructureResult()
        result.combine(eigenstate_result)
        self._grouped_property_transformed.interpret(result)
        result.computed_energies = np.asarray(
            [e.real for e in eigenstate_result.eigenenergies])
        return result
    def interpret(
        self, raw_result: Union[EigenstateResult, EigensolverResult,
                                MinimumEigensolverResult]
    ) -> VibronicStructureResult:
        """Interprets an EigenstateResult in the context of this transformation.

               Args:
                   raw_result: an eigenstate result object.

               Returns:
                   An vibronic structure result.
               """

        eigenstate_result = None
        if isinstance(raw_result, EigenstateResult):
            eigenstate_result = raw_result
        elif isinstance(raw_result, EigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = raw_result.eigenvalues
            eigenstate_result.eigenstates = raw_result.eigenstates
            eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
        elif isinstance(raw_result, MinimumEigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = np.asarray(
                [raw_result.eigenvalue])
            eigenstate_result.eigenstates = [raw_result.eigenstate]
            eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues

        result = VibronicStructureResult()
        result.combine(eigenstate_result)
        result.computed_vibronic_energies = eigenstate_result.eigenenergies
        if result.aux_operator_eigenvalues is not None:
            if not isinstance(result.aux_operator_eigenvalues, list):
                aux_operator_eigenvalues = [result.aux_operator_eigenvalues]
            else:
                aux_operator_eigenvalues = result.aux_operator_eigenvalues  # type: ignore

            result.num_occupied_modals_per_mode = []
            for aux_op_eigenvalues in aux_operator_eigenvalues:
                occ_modals = []
                for mode in range(self._num_modes):
                    if aux_op_eigenvalues[mode] is not None:
                        occ_modals.append(
                            aux_op_eigenvalues[mode][0].real)  # type: ignore
                    else:
                        occ_modals.append(None)
                result.num_occupied_modals_per_mode.append(
                    occ_modals)  # type: ignore

        return result
Exemplo n.º 16
0
    def solve(
        self,
        problem: BaseProblem,
        aux_operators: Optional[List[SecondQuantizedOp]] = None
    ) -> EigenstateResult:
        """Run the excited-states calculation.

        Construct and solves the EOM pseudo-eigenvalue problem to obtain the excitation energies
        and the excitation operators expansion coefficients.

        Args:
            problem: a class encoding a problem to be solved.
            aux_operators: Additional auxiliary operators to evaluate.

        Returns:
            An interpreted :class:`~.EigenstateResult`. For more information see also
            :meth:`~.BaseProblem.interpret`.
        """

        if aux_operators is not None:
            logger.warning(
                "With qEOM the auxiliary operators can currently only be "
                "evaluated on the ground state.")

        # 1. Run ground state calculation
        groundstate_result = self._gsc.solve(problem)

        # 2. Prepare the excitation operators
        self._untapered_qubit_op_main = self._gsc._qubit_converter.map(
            problem.second_q_ops()[0])
        matrix_operators_dict, size = self._prepare_matrix_operators(problem)

        # 3. Evaluate eom operators
        measurement_results = self._gsc.evaluate_operators(
            groundstate_result.eigenstates[0], matrix_operators_dict)
        measurement_results = cast(Dict[str, List[float]], measurement_results)

        # 4. Post-process ground_state_result to construct eom matrices
        m_mat, v_mat, q_mat, w_mat, m_mat_std, v_mat_std, q_mat_std, w_mat_std = \
            self._build_eom_matrices(measurement_results, size)

        # 5. solve pseudo-eigenvalue problem
        energy_gaps, expansion_coefs = self._compute_excitation_energies(
            m_mat, v_mat, q_mat, w_mat)

        qeom_result = QEOMResult()
        qeom_result.ground_state_raw_result = groundstate_result.raw_result
        qeom_result.expansion_coefficients = expansion_coefs
        qeom_result.excitation_energies = energy_gaps
        qeom_result.m_matrix = m_mat
        qeom_result.v_matrix = v_mat
        qeom_result.q_matrix = q_mat
        qeom_result.w_matrix = w_mat
        qeom_result.m_matrix_std = m_mat_std
        qeom_result.v_matrix_std = v_mat_std
        qeom_result.q_matrix_std = q_mat_std
        qeom_result.w_matrix_std = w_mat_std

        eigenstate_result = EigenstateResult()
        eigenstate_result.eigenstates = groundstate_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = groundstate_result.aux_operator_eigenvalues
        eigenstate_result.raw_result = qeom_result

        eigenstate_result.eigenenergies = np.append(
            groundstate_result.eigenenergies,
            np.asarray([
                groundstate_result.eigenenergies[0] + gap
                for gap in energy_gaps
            ]))

        result = problem.interpret(eigenstate_result)

        return result
Exemplo n.º 17
0
    def interpret(
        self,
        raw_result: Union[EigenstateResult, EigensolverResult,
                          MinimumEigensolverResult],
    ) -> LatticeModelResult:
        """Interprets a raw result in the context of this transformation.

        Args:
            raw_result: a raw result to be interpreted

        Returns:
            A lattice model result.
        """
        eigenstate_result = None
        if isinstance(raw_result, EigenstateResult):
            eigenstate_result = raw_result
        elif isinstance(raw_result, EigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = raw_result.eigenvalues
            eigenstate_result.eigenstates = raw_result.eigenstates
            eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
        elif isinstance(raw_result, MinimumEigensolverResult):
            eigenstate_result = EigenstateResult()
            eigenstate_result.raw_result = raw_result
            eigenstate_result.eigenenergies = np.asarray(
                [raw_result.eigenvalue])
            eigenstate_result.eigenstates = [raw_result.eigenstate]
            eigenstate_result.aux_operator_eigenvalues = [
                raw_result.aux_operator_eigenvalues
            ]
        result = LatticeModelResult()
        result.combine(eigenstate_result)
        result.computed_lattice_energies = eigenstate_result.eigenenergies
        return result
    def solve(
        self,
        problem: BaseProblem,
        aux_operators: Optional[ListOrDictType[Union[SecondQuantizedOp,
                                                     PauliSumOp]]] = None,
    ) -> EigenstateResult:
        """Compute Ground and Excited States properties.

        Args:
            problem: a class encoding a problem to be solved.
            aux_operators: Additional auxiliary operators to evaluate.

        Raises:
            ValueError: if the grouped property object returned by the driver does not contain a
                main property as requested by the problem being solved (`problem.main_property_name`)
            QiskitNatureError: if the user-provided `aux_operators` contain a name which clashes
                with an internally constructed auxiliary operator. Note: the names used for the
                internal auxiliary operators correspond to the `Property.name` attributes which
                generated the respective operators.

        Returns:
            An interpreted :class:`~.EigenstateResult`. For more information see also
            :meth:`~.BaseProblem.interpret`.
        """
        # get the operator and auxiliary operators, and transform the provided auxiliary operators
        # note that ``aux_operators`` contains not only the transformed ``aux_operators`` passed
        # by the user but also additional ones from the transformation
        second_q_ops = problem.second_q_ops()

        aux_second_q_ops: ListOrDictType[SecondQuantizedOp]
        if isinstance(second_q_ops, list):
            main_second_q_op = second_q_ops[0]
            aux_second_q_ops = second_q_ops[1:]
        elif isinstance(second_q_ops, dict):
            name = problem.main_property_name
            main_second_q_op = second_q_ops.pop(name, None)
            if main_second_q_op is None:
                raise ValueError(
                    f"The main `SecondQuantizedOp` associated with the {name} property cannot be "
                    "`None`.")
            aux_second_q_ops = second_q_ops

        main_operator = self._qubit_converter.convert(
            main_second_q_op,
            num_particles=problem.num_particles,
            sector_locator=problem.symmetry_sector_locator,
        )
        aux_ops = self._qubit_converter.convert_match(aux_second_q_ops)

        if aux_operators is not None:
            wrapped_aux_operators: ListOrDict[Union[
                SecondQuantizedOp, PauliSumOp]] = ListOrDict(aux_operators)
            for name_aux, aux_op in iter(wrapped_aux_operators):
                if isinstance(aux_op, SecondQuantizedOp):
                    converted_aux_op = self._qubit_converter.convert_match(
                        aux_op, True)
                else:
                    converted_aux_op = aux_op
                if isinstance(aux_ops, list):
                    aux_ops.append(converted_aux_op)
                elif isinstance(aux_ops, dict):
                    if name_aux in aux_ops.keys():
                        raise QiskitNatureError(
                            f"The key '{name_aux}' is already taken by an internally constructed "
                            "auxiliary operator! Please use a different name for your custom "
                            "operator.")
                    aux_ops[name_aux] = converted_aux_op

        if isinstance(self._solver, EigensolverFactory):
            # this must be called after transformation.transform
            solver = self._solver.get_solver(problem)
        else:
            solver = self._solver

        # if the eigensolver does not support auxiliary operators, reset them
        if not solver.supports_aux_operators():
            aux_ops = None

        raw_es_result = solver.compute_eigenvalues(main_operator, aux_ops)

        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_es_result
        eigenstate_result.eigenenergies = raw_es_result.eigenvalues
        eigenstate_result.eigenstates = raw_es_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = raw_es_result.aux_operator_eigenvalues
        result = problem.interpret(eigenstate_result)
        return result
Exemplo n.º 19
0
def _interpret_raw_result(raw_result):
    eigenstate_result = None
    if isinstance(raw_result, EigenstateResult):
        eigenstate_result = raw_result
    elif isinstance(raw_result, EigensolverResult):
        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_result
        eigenstate_result.eigenenergies = raw_result.eigenvalues
        eigenstate_result.eigenstates = raw_result.eigenstates
        eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
    elif isinstance(raw_result, MinimumEigensolverResult):
        eigenstate_result = EigenstateResult()
        eigenstate_result.raw_result = raw_result
        eigenstate_result.eigenenergies = np.asarray([raw_result.eigenvalue])
        eigenstate_result.eigenstates = [raw_result.eigenstate]
        eigenstate_result.aux_operator_eigenvalues = raw_result.aux_operator_eigenvalues
    return eigenstate_result