Source code for qvartools.solvers.solver

"""
base --- Abstract solver interface and result dataclass
=======================================================

Defines the :class:`Solver` ABC that every concrete solver must implement,
together with the :class:`SolverResult` immutable dataclass that standardises
solver outputs across all methods.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any

from qvartools.hamiltonians.hamiltonian import Hamiltonian

__all__ = [
    "SolverResult",
    "Solver",
]


# ---------------------------------------------------------------------------
# SolverResult dataclass
# ---------------------------------------------------------------------------


[docs] @dataclass(frozen=True) class SolverResult: """Immutable container for solver output. Parameters ---------- energy : float or None Ground-state energy estimate in Hartree, or ``None`` when the solver fails or skips the computation. diag_dim : int Dimension of the diagonalisation subspace (number of basis configurations used). wall_time : float Wall-clock time in seconds for the full solve. method : str Human-readable solver method name (e.g. ``"FCI"``, ``"SQD"``). converged : bool Whether the solver converged to the requested tolerance. metadata : dict Additional method-specific information (e.g. iteration history, basis size per step, training metrics). Attributes ---------- energy : float or None diag_dim : int wall_time : float method : str converged : bool metadata : dict Examples -------- >>> result = SolverResult( ... diag_dim=100, wall_time=1.5, method="SQD", converged=True, ... energy=-1.137, ... ) >>> result.energy -1.137 """ diag_dim: int wall_time: float method: str converged: bool energy: float | None = None metadata: dict[str, Any] = field(default_factory=dict) def __repr__(self) -> str: energy_str = f"{self.energy:.10f}" if self.energy is not None else "None" return ( f"SolverResult(method={self.method!r}, energy={energy_str}, " f"diag_dim={self.diag_dim}, wall_time={self.wall_time:.2f}s, " f"converged={self.converged})" )
# --------------------------------------------------------------------------- # Solver ABC # ---------------------------------------------------------------------------
[docs] class Solver(ABC): """Abstract base class for all quantum chemistry solvers. Every subclass must implement :meth:`solve`, which takes a Hamiltonian and a molecular information dictionary and returns a :class:`SolverResult`. The ``mol_info`` dictionary is expected to contain at least: - ``"name"`` : str -- molecule name. - ``"n_qubits"`` : int -- number of qubits (spin-orbitals). - ``"basis"`` : str -- Gaussian basis set. - ``"geometry"`` : list -- atomic geometry. - ``"charge"`` : int -- net molecular charge. - ``"spin"`` : int -- spin multiplicity minus one (2S). """
[docs] @abstractmethod def solve(self, hamiltonian: Hamiltonian, mol_info: dict[str, Any]) -> SolverResult: """Compute the ground-state energy. Parameters ---------- hamiltonian : Hamiltonian The molecular Hamiltonian to diagonalise. mol_info : dict Molecular metadata dictionary with keys ``name``, ``n_qubits``, ``basis``, ``geometry``, ``charge``, ``spin``. Returns ------- SolverResult Result containing energy, timing, and convergence information. """