Advanced Customization Guide¶
When should I read this? Read this guide if you need to extend NLSQ beyond configuration files, implement custom logic, or integrate deeply with the optimization pipeline.
Custom Callbacks¶
Create custom callbacks by defining a function with signature:
import numpy as np
import jax.numpy as jnp
from nlsq import curve_fit
def exponential(x, a, b):
return a * jnp.exp(-b * x)
x = np.linspace(0, 5, 100)
y = 2.5 * np.exp(-1.3 * x) + 0.1 * np.random.randn(100)
def custom_callback(iteration, cost, params, info):
"""
Parameters
----------
iteration : int
Current iteration number (0-indexed)
cost : float
Current cost function value
params : ndarray
Current parameter values
info : dict
Additional information (gradient norm, step norm, etc.)
Returns
-------
stop : bool
True to stop optimization early, False to continue
"""
if iteration > 50 and cost < 0.01:
print("Good enough! Stopping early.")
return True
if iteration % 10 == 0:
print(f"Iter {iteration}: cost={cost:.6f}, params={params}")
return False
popt, pcov = curve_fit(
exponential, x, y, p0=[2, 1], callback=custom_callback, max_nfev=100
)
Diagnostic Monitoring¶
Monitor optimization health and numerical stability.
from nlsq.diagnostics import DiagnosticMonitor
monitor = DiagnosticMonitor(
check_condition_number=True,
check_gradient_norm=True,
check_step_quality=True,
log_level="INFO",
)
popt, pcov = curve_fit(exponential, x, y, p0=[2, 0.5], diagnostics=monitor)
print(monitor.summary())
Sparse Jacobian Optimization¶
For models with sparse Jacobian structure, provide a sparsity pattern for significant speedups.
import scipy.sparse as sp
def complex_model(x, *params): ...
sparsity = sp.lil_matrix((len(x), len(p0)))
sparsity[0:50, 0:2] = 1
sparsity[50:100, 2:4] = 1
popt, pcov = curve_fit(complex_model, x, y, p0=p0, jac_sparsity=sparsity)
Adaptive Hybrid Streaming¶
For huge datasets that require streaming Gauss-Newton updates:
from nlsq import AdaptiveHybridStreamingOptimizer, HybridStreamingConfig
config = HybridStreamingConfig(chunk_size=50000, gauss_newton_max_iterations=20)
optimizer = AdaptiveHybridStreamingOptimizer(config)
result = optimizer.fit((x, y), exponential, p0=[2, 0.5], verbose=1)
popt_final = result["x"]
pcov_final = result["pcov"]