From 686592d16627de8ac49df279c9a217907badeb23 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 20:43:51 +0000 Subject: [PATCH 1/2] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.15.13 → v0.16.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.13...v0.16.10) - [github.com/tox-dev/pyproject-fmt: v2.21.0 → v2.30.1](https://github.com/tox-dev/pyproject-fmt/compare/v2.21.0...v2.30.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6fbf629..293512d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,11 +7,11 @@ repos: - id: check-yaml - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.13 + rev: v0.16.10 hooks: - id: ruff-check - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.21.0 + rev: v2.30.1 hooks: - id: pyproject-fmt From 8ca6ccc379ed81479d6d9f86207bb85b50f3ccf5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 20:46:06 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/installation.md | 1 + docs/optimization.md | 55 +++++++++-------------------------------- docs/targets.md | 21 ++++++++-------- docs/training.md | 59 ++++++++++++++------------------------------ pyproject.toml | 23 ++++++++--------- 5 files changed, 55 insertions(+), 104 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 1b1b6db..248539d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -72,6 +72,7 @@ To verify that DESCENT is installed correctly, run: ```python import descent + print(descent.__version__) ``` diff --git a/docs/optimization.md b/docs/optimization.md index f83af44..e207977 100644 --- a/docs/optimization.md +++ b/docs/optimization.md @@ -22,11 +22,7 @@ Adaptive Moment Estimation (Adam) is the default optimizer: ```python from descent.optim import Adam -optimizer = Adam( - lr=1e-3, - betas=(0.9, 0.999), - eps=1e-8 -) +optimizer = Adam(lr=1e-3, betas=(0.9, 0.999), eps=1e-8) ``` **Pros:** @@ -48,7 +44,7 @@ from descent.optim import AdamW optimizer = AdamW( lr=1e-3, weight_decay=1e-4, # L2 regularization - betas=(0.9, 0.999) + betas=(0.9, 0.999), ) ``` @@ -61,11 +57,7 @@ Stochastic Gradient Descent with momentum: ```python from descent.optim import SGD -optimizer = SGD( - lr=1e-2, - momentum=0.9, - nesterov=True -) +optimizer = SGD(lr=1e-2, momentum=0.9, nesterov=True) ``` **Pros:** @@ -83,11 +75,7 @@ Limited-memory BFGS for quasi-Newton optimization: ```python from descent.optim import LBFGS -optimizer = LBFGS( - lr=1.0, - max_iter=20, - history_size=10 -) +optimizer = LBFGS(lr=1.0, max_iter=20, history_size=10) ``` **Pros:** @@ -116,11 +104,7 @@ Reduce learning rate at specified epochs: ```python from torch.optim.lr_scheduler import StepLR -scheduler = StepLR( - optimizer, - step_size=30, - gamma=0.1 -) +scheduler = StepLR(optimizer, step_size=30, gamma=0.1) ``` ### Reduce on Plateau @@ -131,11 +115,7 @@ Reduce when loss plateaus: from torch.optim.lr_scheduler import ReduceLROnPlateau scheduler = ReduceLROnPlateau( - optimizer, - mode='min', - factor=0.5, - patience=10, - threshold=1e-4 + optimizer, mode="min", factor=0.5, patience=10, threshold=1e-4 ) ``` @@ -146,11 +126,7 @@ Cosine decay with warm restarts: ```python from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts -scheduler = CosineAnnealingWarmRestarts( - optimizer, - T_0=10, - T_mult=2 -) +scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=10, T_mult=2) ``` ### Exponential Decay @@ -160,10 +136,7 @@ Exponential learning rate decay: ```python from torch.optim.lr_scheduler import ExponentialLR -scheduler = ExponentialLR( - optimizer, - gamma=0.95 -) +scheduler = ExponentialLR(optimizer, gamma=0.95) ``` ## Gradient Computation @@ -211,11 +184,7 @@ For problems with structured residuals, DESCENT provides Levenberg-Marquardt opt ```python from descent.optim import LevenbergMarquardt -optimizer = LevenbergMarquardt( - lambda_init=1e-3, - lambda_factor=10.0, - max_iter=100 -) +optimizer = LevenbergMarquardt(lambda_init=1e-3, lambda_factor=10.0, max_iter=100) ``` ## Regularization @@ -229,7 +198,7 @@ Add L2 penalty to loss: optimizer = AdamW(lr=1e-3, weight_decay=1e-4) # Or manually -loss = target_loss + 1e-4 * torch.sum(parameters ** 2) +loss = target_loss + 1e-4 * torch.sum(parameters**2) ``` ### L1 Regularization @@ -301,13 +270,13 @@ from itertools import product lr_values = [1e-2, 1e-3, 1e-4] wd_values = [0, 1e-4, 1e-3] -best_loss = float('inf') +best_loss = float("inf") best_params = None for lr, wd in product(lr_values, wd_values): optimizer = AdamW(lr=lr, weight_decay=wd) loss = train(optimizer, ...) - + if loss < best_loss: best_loss = loss best_params = (lr, wd) diff --git a/docs/targets.md b/docs/targets.md index 22ea250..4dc0af0 100644 --- a/docs/targets.md +++ b/docs/targets.md @@ -23,7 +23,7 @@ target = EnergyTarget( dataset="qm_energies.json", weight=1.0, denominator="std", # Normalize by standard deviation - energy_type="absolute" # or "relative" + energy_type="absolute", # or "relative" ) ``` @@ -69,7 +69,7 @@ target = ThermoTarget( weight=0.5, properties=["density", "hvap", "dielectric"], temperatures=[298.15], # K - pressures=[1.0] # atm + pressures=[1.0], # atm ) ``` @@ -150,22 +150,23 @@ Create custom target functions by subclassing `BaseTarget`: from descent.targets import BaseTarget import torch + class CustomTarget(BaseTarget): def __init__(self, dataset, weight=1.0, **kwargs): super().__init__(weight=weight) self.dataset = self.load_dataset(dataset) - + def compute_loss(self, system, parameters): """ Compute loss for this target. - + Parameters ---------- system : System The molecular system parameters : dict Current force field parameters - + Returns ------- loss : torch.Tensor @@ -173,18 +174,18 @@ class CustomTarget(BaseTarget): """ predictions = self.predict(system, parameters) references = self.get_references() - + loss = torch.mean((predictions - references) ** 2) return loss - + def predict(self, system, parameters): """Compute predictions using current parameters.""" # Your implementation here pass - + def get_references(self): """Get reference values.""" - return torch.tensor(self.dataset['values']) + return torch.tensor(self.dataset["values"]) ``` ## Combining Targets @@ -200,7 +201,7 @@ config = TrainingConfig( {"type": "energy", "dataset": "qm.json", "weight": 1.0}, {"type": "thermo", "dataset": "exp.json", "weight": 0.5}, {"type": "dimer", "dataset": "dimers.json", "weight": 0.3}, - ] + ], ) ``` diff --git a/docs/training.md b/docs/training.md index bb97b75..c95eb98 100644 --- a/docs/training.md +++ b/docs/training.md @@ -29,7 +29,7 @@ config = TrainingConfig( force_field="openff-2.0.0.offxml", parameters=["[#6:1]-[#6:2]", "[#6:1]-[#1:2]"], targets=[...], - optimizer_config={...} + optimizer_config={...}, ) # Run training @@ -50,7 +50,7 @@ from descent.targets import EnergyTarget target = EnergyTarget( dataset="energies.json", weight=1.0, - denominator="std" # Normalize by standard deviation + denominator="std", # Normalize by standard deviation ) ``` @@ -61,11 +61,7 @@ Fit to experimental thermodynamic properties (density, enthalpy of vaporization, ```python from descent.targets import ThermoTarget -target = ThermoTarget( - dataset="thermo.json", - weight=0.5, - properties=["density", "hvap"] -) +target = ThermoTarget(dataset="thermo.json", weight=0.5, properties=["density", "hvap"]) ``` ### Dimer Targets @@ -75,10 +71,7 @@ Fit to dimer interaction energies: ```python from descent.targets import DimerTarget -target = DimerTarget( - dataset="dimers.json", - weight=0.3 -) +target = DimerTarget(dataset="dimers.json", weight=0.3) ``` ## Optimization Strategies @@ -88,10 +81,7 @@ DESCENT uses PyTorch optimizers for parameter optimization: ```python from descent.optim import AdamW -optimizer = AdamW( - lr=1e-3, - weight_decay=1e-4 -) +optimizer = AdamW(lr=1e-3, weight_decay=1e-4) ``` Common optimizers: @@ -107,11 +97,9 @@ The overall loss is a weighted combination of target losses: ```python from descent.utils.loss import WeightedLoss -loss_fn = WeightedLoss(targets=[ - (energy_target, 1.0), - (thermo_target, 0.5), - (dimer_target, 0.3) -]) +loss_fn = WeightedLoss( + targets=[(energy_target, 1.0), (thermo_target, 0.5), (dimer_target, 0.3)] +) ``` ## Training Loop @@ -125,12 +113,7 @@ from descent.train import train config = TrainingConfig(...) # Run training -results = train( - config, - max_epochs=100, - batch_size=32, - validation_split=0.2 -) +results = train(config, max_epochs=100, batch_size=32, validation_split=0.2) # Access results print(f"Final loss: {results['final_loss']}") @@ -158,17 +141,17 @@ Save and resume training: ```python # Save checkpoint checkpoint = { - 'epoch': epoch, - 'parameters': parameters, - 'optimizer_state': optimizer.state_dict(), - 'loss': loss + "epoch": epoch, + "parameters": parameters, + "optimizer_state": optimizer.state_dict(), + "loss": loss, } -torch.save(checkpoint, 'checkpoint.pt') +torch.save(checkpoint, "checkpoint.pt") # Resume training -checkpoint = torch.load('checkpoint.pt') -parameters = checkpoint['parameters'] -optimizer.load_state_dict(checkpoint['optimizer_state']) +checkpoint = torch.load("checkpoint.pt") +parameters = checkpoint["parameters"] +optimizer.load_state_dict(checkpoint["optimizer_state"]) ``` ## Best Practices @@ -189,6 +172,7 @@ Create custom target functions by subclassing `BaseTarget`: ```python from descent.targets import BaseTarget + class CustomTarget(BaseTarget): def compute_loss(self, system, parameters): # Custom loss computation @@ -203,12 +187,7 @@ Use PyTorch learning rate schedulers: ```python from torch.optim.lr_scheduler import ReduceLROnPlateau -scheduler = ReduceLROnPlateau( - optimizer, - mode='min', - factor=0.5, - patience=10 -) +scheduler = ReduceLROnPlateau(optimizer, mode="min", factor=0.5, patience=10) ``` ### Regularization diff --git a/pyproject.toml b/pyproject.toml index f606384..db3a514 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", ] dynamic = [ "version" ] @@ -29,21 +30,21 @@ lint.ignore = [ "C901" ] lint.pydocstyle.convention = "google" [tool.mypy] -python_version = "3.12" exclude = "descent/tests/" -plugins = "pydantic.mypy" -warn_unused_configs = true +ignore_missing_imports = true +python_version = "3.12" warn_unused_ignores = true -warn_incomplete_stub = true -show_error_codes = true allow_redefinition = true -overrides = [ { module = [ - "rdkit", - "datasets", - "openff.toolkit.*", -] } ] -ignore_missing_imports = true disable_error_code = [ "arg-type", "assignment", "union-attr" ] # TODO: Try to remove some of these +plugins = "pydantic.mypy" +warn_incomplete_stub = true +warn_unused_configs = true +overrides = [ { module = [ + "datasets", + "openff.toolkit.*", + "rdkit", + ] } ] +show_error_codes = true [tool.coverage] run.omit = [ "**/tests/*" ]