diff --git a/qmp/models/fcidump.py b/qmp/models/fcidump.py index 23b8102..13b59aa 100644 --- a/qmp/models/fcidump.py +++ b/qmp/models/fcidump.py @@ -2,7 +2,6 @@ This file provides an interface to work with FCIDUMP files. """ -import os import typing import logging import dataclasses @@ -20,8 +19,6 @@ from ..hamiltonian import Hamiltonian from ..utility.model_dict import model_dict, ModelProto, NetworkProto, NetworkConfigProto -QMP_MODEL_PATH = "QMP_MODEL_PATH" - @dataclasses.dataclass class ModelConfig: @@ -29,21 +26,13 @@ class ModelConfig: The configuration of the model. """ - # The openfermion model name - model_name: str - # The path of models folder - model_path: pathlib.Path | None = None + # The complete path to the model file (can be relative or absolute) + model_path: pathlib.Path | str # The ref energy of the model, leave empty to read from FCIDUMP.yaml ref_energy: float | None = None def __post_init__(self) -> None: - if self.model_path is not None: - self.model_path = pathlib.Path(self.model_path) - else: - if QMP_MODEL_PATH in os.environ: - self.model_path = pathlib.Path(os.environ[QMP_MODEL_PATH]) - else: - self.model_path = pathlib.Path("models") + self.model_path = pathlib.Path(self.model_path) def _read_fcidump( @@ -134,58 +123,55 @@ class Model(ModelProto[ModelConfig]): @classmethod def default_group_name(cls, config: ModelConfig) -> str: - return config.model_name + # Use the filename as the group name, removing extensions + name = config.model_path.name + return name.removesuffix(".FCIDUMP.gz").removesuffix(".FCIDUMP") def __init__(self, args: ModelConfig) -> None: # pylint: disable=too-many-locals logging.info("Input arguments successfully parsed") - logging.info("Model name: %s, Model path: %s", args.model_name, args.model_path) + logging.info("Model path: %s", args.model_path) - model_name = args.model_name - model_path = args.model_path + # model_path is now the complete path to the file (already converted to Path in __post_init__) + model_file_name = args.model_path ref_energy = args.ref_energy - assert model_path is not None - - model_file_name = model_path / f"{model_name}.FCIDUMP.gz" - model_file_name = model_file_name if model_file_name.exists() else model_path / model_name checksum = hashlib.sha256(model_file_name.read_bytes()).hexdigest() + "v5" cache_file = platformdirs.user_cache_path("qmp", "kclab") / checksum if cache_file.exists(): - logging.info("Loading FCIDUMP metadata '%s' from file: %s", model_name, model_file_name) + logging.info("Loading FCIDUMP metadata from file: %s", model_file_name) (n_orbit, n_electron, n_spin), _ = _read_fcidump(model_file_name, cached=True) - logging.info("FCIDUMP metadata '%s' successfully loaded", model_name) + logging.info("FCIDUMP metadata successfully loaded") - logging.info("Loading FCIDUMP Hamiltonian '%s' from cache", model_name) + logging.info("Loading FCIDUMP Hamiltonian from cache") openfermion_hamiltonian_data = torch.load(cache_file, map_location="cpu", weights_only=True) - logging.info("FCIDUMP Hamiltonian '%s' successfully loaded", model_name) + logging.info("FCIDUMP Hamiltonian successfully loaded") - logging.info("Recovering internal Hamiltonian representation for model '%s'", model_name) + logging.info("Recovering internal Hamiltonian representation") self.hamiltonian = Hamiltonian(openfermion_hamiltonian_data, kind="fermi") - logging.info("Internal Hamiltonian representation for model '%s' successfully recovered", model_name) + logging.info("Internal Hamiltonian representation successfully recovered") else: - logging.info("Loading FCIDUMP Hamiltonian '%s' from file: %s", model_name, model_file_name) + logging.info("Loading FCIDUMP Hamiltonian from file: %s", model_file_name) (n_orbit, n_electron, n_spin), openfermion_hamiltonian_dict = _read_fcidump(model_file_name) - logging.info("FCIDUMP Hamiltonian '%s' successfully loaded", model_name) + logging.info("FCIDUMP Hamiltonian successfully loaded") logging.info("Converting OpenFermion Hamiltonian to internal Hamiltonian representation") self.hamiltonian = Hamiltonian(openfermion_hamiltonian_dict, kind="fermi") - logging.info("Internal Hamiltonian representation for model '%s' has been successfully created", model_name) + logging.info("Internal Hamiltonian representation has been successfully created") - logging.info("Caching OpenFermion Hamiltonian for model '%s'", model_name) + logging.info("Caching OpenFermion Hamiltonian") cache_file.parent.mkdir(parents=True, exist_ok=True) torch.save((self.hamiltonian.site, self.hamiltonian.kind, self.hamiltonian.coef), cache_file) - logging.info("OpenFermion Hamiltonian for model '%s' successfully cached", model_name) + logging.info("OpenFermion Hamiltonian successfully cached") self.n_qubit: int = n_orbit * 2 self.n_electron: int = n_electron self.n_spin: int = n_spin logging.info( - "Identified %d qubits, %d electrons and %d spin for model '%s'", + "Identified %d qubits, %d electrons and %d spin", self.n_qubit, self.n_electron, self.n_spin, - model_name, ) self.ref_energy: float @@ -196,10 +182,12 @@ def __init__(self, args: ModelConfig) -> None: if fcidump_ref_energy_file.exists(): with open(fcidump_ref_energy_file, "rt", encoding="utf-8") as file: fcidump_ref_energy_data = yaml.safe_load(file) - self.ref_energy = fcidump_ref_energy_data.get(pathlib.Path(model_name).name, 0) + # Extract filename without extensions for YAML lookup + yaml_key = model_file_name.name.removesuffix(".FCIDUMP.gz").removesuffix(".FCIDUMP") + self.ref_energy = fcidump_ref_energy_data.get(yaml_key, 0) else: self.ref_energy = 0 - logging.info("Reference energy for model '%s' is %.10f", model_name, self.ref_energy) + logging.info("Reference energy is %.10f", self.ref_energy) def apply_within(self, configs_i: torch.Tensor, psi_i: torch.Tensor, configs_j: torch.Tensor) -> torch.Tensor: return self.hamiltonian.apply_within(configs_i, psi_i, configs_j) diff --git a/qmp/models/openfermion.py b/qmp/models/openfermion.py index f15b6f4..5565710 100644 --- a/qmp/models/openfermion.py +++ b/qmp/models/openfermion.py @@ -2,7 +2,6 @@ This file provides an interface to work with openfermion models. """ -import os import typing import logging import dataclasses @@ -15,8 +14,6 @@ from ..hamiltonian import Hamiltonian from ..utility.model_dict import model_dict, ModelProto, NetworkProto, NetworkConfigProto -QMP_MODEL_PATH = "QMP_MODEL_PATH" - @dataclasses.dataclass class ModelConfig: @@ -24,19 +21,11 @@ class ModelConfig: The configuration of the model. """ - # The openfermion model name - model_name: str - # The path of models folder - model_path: pathlib.Path | None = None + # The complete path to the model file (can be relative or absolute) + model_path: pathlib.Path | str def __post_init__(self) -> None: - if self.model_path is not None: - self.model_path = pathlib.Path(self.model_path) - else: - if QMP_MODEL_PATH in os.environ: - self.model_path = pathlib.Path(os.environ[QMP_MODEL_PATH]) - else: - self.model_path = pathlib.Path("models") + self.model_path = pathlib.Path(self.model_path) class Model(ModelProto[ModelConfig]): @@ -50,36 +39,33 @@ class Model(ModelProto[ModelConfig]): @classmethod def default_group_name(cls, config: ModelConfig) -> str: - return config.model_name + # Use the filename as the group name, removing extension + return config.model_path.name.removesuffix(".hdf5") def __init__(self, args: ModelConfig) -> None: logging.info("Input arguments successfully parsed") - logging.info("Model name: %s, Model path: %s", args.model_name, args.model_path) + logging.info("Model path: %s", args.model_path) - model_name = args.model_name - model_path = args.model_path - assert model_path is not None + # model_path is now the complete path to the file (already converted to Path in __post_init__) + model_file_name = args.model_path - model_file_name = model_path / f"{model_name}.hdf5" - logging.info("Loading OpenFermion model '%s' from file: %s", model_name, model_file_name) + logging.info("Loading OpenFermion model from file: %s", model_file_name) openfermion_model: openfermion.MolecularData = openfermion.MolecularData(filename=str(model_file_name)) # type: ignore[no-untyped-call] - logging.info("OpenFermion model '%s' successfully loaded", model_name) + logging.info("OpenFermion model successfully loaded") self.n_qubits: int = int(openfermion_model.n_qubits) # type: ignore[arg-type] self.n_electrons: int = int(openfermion_model.n_electrons) # type: ignore[arg-type] - logging.info( - "Identified %d qubits and %d electrons for model '%s'", self.n_qubits, self.n_electrons, model_name - ) + logging.info("Identified %d qubits and %d electrons", self.n_qubits, self.n_electrons) self.ref_energy: float = float(openfermion_model.fci_energy) # type: ignore[arg-type] - logging.info("Reference energy for model '%s' is %.10f", model_name, self.ref_energy) + logging.info("Reference energy is %.10f", self.ref_energy) logging.info("Converting OpenFermion Hamiltonian to internal Hamiltonian representation") self.hamiltonian: Hamiltonian = Hamiltonian( openfermion.transforms.get_fermion_operator(openfermion_model.get_molecular_hamiltonian()).terms, # type: ignore[no-untyped-call] kind="fermi", ) - logging.info("Internal Hamiltonian representation for model '%s' has been successfully created", model_name) + logging.info("Internal Hamiltonian representation has been successfully created") def apply_within(self, configs_i: torch.Tensor, psi_i: torch.Tensor, configs_j: torch.Tensor) -> torch.Tensor: return self.hamiltonian.apply_within(configs_i, psi_i, configs_j)