4.6. Facades¶
Added in version 0.6.4.
Facades provide lazy-loading wrappers that break circular dependencies while providing convenient access to components.
4.6.1. Why Facades?¶
Circular Dependencies: Some modules depend on each other
Lazy Loading: Load expensive modules only when needed
Convenience: Single import point for related functionality
4.6.2. Available Facades¶
Located in nlsq/facades/:
OptimizationFacade: Global optimization componentsStabilityFacade: Numerical stability componentsDiagnosticsFacade: Diagnostics and monitoring
4.6.3. OptimizationFacade¶
Access global optimization without circular imports:
from nlsq.facades import OptimizationFacade
facade = OptimizationFacade()
# Get CMA-ES optimizer (lazy loaded)
CMAESOptimizer = facade.get_cmaes_optimizer()
optimizer = facade.create_cmaes_optimizer(bounds=([0], [10]))
# Get multi-start orchestrator
MultiStart = facade.get_multistart_optimizer()
multistart = facade.create_multistart_orchestrator(n_starts=20)
Methods:
facade.get_cmaes_optimizer() # Returns CMAESOptimizer class
facade.create_cmaes_optimizer(bounds) # Creates configured instance
facade.get_multistart_optimizer() # Returns MultiStartOrchestrator class
facade.create_multistart_orchestrator(n_starts) # Creates instance
4.6.4. StabilityFacade¶
Access stability components:
from nlsq.facades import StabilityFacade
facade = StabilityFacade()
# Get fallback orchestrator
fallback = facade.get_fallback_orchestrator()
# Get optimization recovery
recovery = facade.get_optimization_recovery()
# Get numerical guard
guard = facade.get_numerical_guard()
4.6.5. DiagnosticsFacade¶
Access diagnostics components:
from nlsq.facades import DiagnosticsFacade
facade = DiagnosticsFacade()
# Get convergence monitor
monitor = facade.get_convergence_monitor()
# Get diagnostics configuration
config = facade.get_diagnostics_config()
4.6.6. Lazy Loading Behavior¶
Components are loaded on first access:
from nlsq.facades import OptimizationFacade
# Fast: no heavy imports yet
facade = OptimizationFacade()
# First access: imports nlsq.global_optimization
CMAESOptimizer = facade.get_cmaes_optimizer()
# Subsequent access: cached
CMAESOptimizer2 = facade.get_cmaes_optimizer() # Same object
4.6.7. Example Use Case¶
Breaking circular dependencies:
# In nlsq/core/minpack.py (can't import global_optimization directly)
from nlsq.facades import OptimizationFacade
def fit_with_global(model, x, y, bounds, n_starts=10):
facade = OptimizationFacade()
# Create multi-start optimizer (lazy loaded)
orchestrator = facade.create_multistart_orchestrator(n_starts=n_starts)
# Run global optimization
results = orchestrator.optimize(lambda p: model(x, *p), bounds=bounds)
return results.best
4.6.8. Complete Example¶
import numpy as np
import jax.numpy as jnp
from nlsq.facades import OptimizationFacade, StabilityFacade
def model(x, a, b, c):
return a * jnp.exp(-b * x) + c
# Generate data
np.random.seed(42)
x = np.linspace(0, 10, 100)
y = 2.5 * np.exp(-0.5 * x) + 0.3 + 0.1 * np.random.randn(100)
# Use facades for components
opt_facade = OptimizationFacade()
stab_facade = StabilityFacade()
# Get multistart optimizer
orchestrator = opt_facade.create_multistart_orchestrator(n_starts=10)
# Define objective
def objective(params):
return jnp.sum((model(x, *params) - y) ** 2)
# Define bounds
bounds = ([0, 0, -1], [10, 5, 1])
# Run multi-start optimization
# (This is a simplified example - actual API may differ)
print("Running multi-start optimization via facade...")
# Get stability guard for checking
guard = stab_facade.get_numerical_guard()
print(f"Stability guard type: {type(guard)}")
4.6.9. Next Steps¶
Custom Workflows - Building custom pipelines
Performance Optimization - Performance optimization