PricingModel API¶
The PricingModel
class is the primary interface for running actuarial simulations
with optimization features.
Class Overview¶
Constructor¶
PricingModel(
portfolio: Portfolio,
backend: Optional[Backend] = None,
optimization_selector: Optional[OptimizationSelector] = None
)
Parameters:
portfolio (
Portfolio
) - The portfolio of policies to simulatebackend (
Backend
, optional) - Computational backend (classical/quantum). Defaults to current backend setting.optimization_selector (
OptimizationSelector
, optional) - ML-based optimization selector. If None, creates default selector.
Example:
from quactuary import PricingModel, Portfolio
from quactuary.optimization import OptimizationSelector
# Basic usage
model = PricingModel(portfolio)
# With custom optimization selector
selector = OptimizationSelector(model_path="custom_model.pkl")
model = PricingModel(portfolio, optimization_selector=selector)
# With quantum backend
from quactuary import set_backend
set_backend("quantum")
model = PricingModel(portfolio)
Core Methods¶
simulate()¶
Method Signature:
def simulate(
self,
n_simulations: int = 10000,
use_jit: Optional[bool] = None,
parallel: Optional[bool] = None,
max_workers: Optional[int] = None,
vectorized: bool = True,
memory_limit_gb: Optional[float] = None,
use_qmc: bool = False,
qmc_engine: str = 'sobol',
qmc_method: Optional[str] = None,
qmc_scramble: bool = True,
qmc_skip: int = 0,
qmc_seed: Optional[int] = None,
progress_bar: bool = True,
checkpoint_interval: Optional[int] = None,
random_state: Optional[int] = None,
auto_optimize: bool = True,
optimization_config: Optional[Dict[str, Any]] = None,
**kwargs
) -> SimulationResults
Parameters:
Parameter |
Type |
Description |
---|---|---|
|
|
Number of simulation paths to generate (default: 10,000) |
|
|
Enable JIT compilation. Auto-detected if None based on portfolio size |
|
|
Enable parallel processing. Auto-detected if None |
|
|
Maximum worker processes. Uses CPU count if None |
|
|
Enable vectorization (default: True, recommended) |
|
|
Memory limit in GB. Auto-detected if None |
|
|
Use quasi-Monte Carlo sequences (default: False) |
|
|
QMC engine: ‘sobol’, ‘halton’, ‘latin_hypercube’ |
|
|
QMC generation method (engine-specific) |
|
|
Apply Owen scrambling to QMC sequences (default: True) |
|
|
Number of initial QMC points to skip (default: 0) |
|
|
Seed for QMC scrambling |
|
|
Show progress bar during simulation (default: True) |
|
|
Save progress every N simulations. None disables checkpointing |
|
|
Random seed for reproducibility |
|
|
Enable ML-based automatic optimization selection (default: True) |
|
|
Manual optimization configuration overrides |
Returns:
SimulationResults
- Object containing simulation results and metadata
Examples:
Basic usage with automatic optimization:
from quactuary import PricingModel, Portfolio
# Create portfolio and model
portfolio = Portfolio()
# ... add policies to portfolio ...
model = PricingModel(portfolio)
# Run simulation with automatic optimization
results = model.simulate(n_simulations=100_000)
print(f"Mean loss: ${results.mean():,.0f}")
print(f"95% VaR: ${results.var(0.95):,.0f}")
print(f"99% TVaR: ${results.tvar(0.99):,.0f}")
Explicit optimization configuration:
# High-performance configuration
results = model.simulate(
n_simulations=1_000_000,
use_jit=True,
parallel=True,
max_workers=8,
use_qmc=True,
qmc_engine='sobol'
)
Advanced QMC configuration:
# Enhanced QMC with scrambling and optimized parameters
results = model.simulate(
n_simulations=100_000,
use_qmc=True,
qmc_engine='sobol',
qmc_scramble=True, # Owen scrambling for better uniformity
qmc_skip=1000, # Skip first 1000 points
qmc_seed=42 # Reproducible scrambling
)
# Halton sequence for lower dimensions
results = model.simulate(
n_simulations=50_000,
use_qmc=True,
qmc_engine='halton',
qmc_scramble=True
)
Memory-constrained environment:
# Memory-efficient configuration
results = model.simulate(
n_simulations=10_000_000,
memory_limit_gb=4,
checkpoint_interval=100_000,
parallel=False # Reduce memory usage
)
Automatic optimization with ML-based selection:
# Let the ML model choose optimal settings
results = model.simulate(
n_simulations=500_000,
auto_optimize=True # Uses OptimizationSelector
)
# View selected optimizations
print(f"Selected strategy: {results.optimization_strategy}")
print(f"JIT used: {results.metadata['use_jit']}")
print(f"Parallel used: {results.metadata['parallel']}")
Manual optimization override:
# Override automatic optimization
results = model.simulate(
n_simulations=100_000,
auto_optimize=False,
optimization_config={
'use_jit': True,
'parallel': True,
'max_workers': 4,
'batch_size': 10000
}
)
Auto-Detection Logic:
The simulate()
method uses ML-based optimization selection when auto_optimize=True
:
# The OptimizationSelector uses a trained model to predict optimal settings
# based on portfolio characteristics and system resources
def select_optimizations(portfolio, n_simulations):
"""ML-based optimization selection."""
# Extract features
features = {
'n_policies': len(portfolio),
'n_simulations': n_simulations,
'avg_frequency': portfolio.average_frequency,
'severity_complexity': portfolio.severity_complexity_score,
'has_dependencies': portfolio.has_correlations,
'available_memory_gb': psutil.virtual_memory().available / 1e9,
'cpu_count': os.cpu_count()
}
# ML model predicts optimal strategy
strategy = optimization_selector.predict_strategy(features)
# Strategy includes:
# - use_jit: Whether to use JIT compilation
# - parallel: Whether to use parallel processing
# - max_workers: Optimal number of workers
# - batch_size: Optimal batch size for processing
# - use_qmc: Whether QMC would improve convergence
return strategy
For manual control, set auto_optimize=False
and provide optimization_config
.
Performance Considerations:
JIT Compilation: First run includes compilation overhead (0.5-2 seconds)
Parallel Processing: Overhead makes it unsuitable for small portfolios (< 50 policies)
Memory Management: Automatic batching when memory limit is approached
QMC Convergence: Often achieves better precision with fewer simulations
QMC Scrambling: Owen scrambling improves uniformity and convergence rates
QMC Skip: Skipping initial points can improve sequence quality for some applications
Advanced Usage¶
Custom Optimization Strategies¶
Implement custom optimization logic:
class CustomPricingModel(PricingModel):
"""Custom model with specialized optimization."""
def custom_optimize(self, n_simulations):
"""Custom optimization based on portfolio characteristics."""
# Analyze portfolio complexity
complexity = self.analyze_complexity()
if complexity['has_dependencies']:
# Correlated portfolios benefit from QMC
config = {
'use_qmc': True,
'qmc_engine': 'sobol',
'use_jit': True
}
elif complexity['high_frequency']:
# High-frequency portfolios need parallel processing
config = {
'parallel': True,
'max_workers': os.cpu_count(),
'use_jit': True
}
else:
# Simple portfolios use basic optimization
config = {
'use_jit': True,
'parallel': False
}
return self.simulate(n_simulations=n_simulations, **config)
def analyze_complexity(self):
"""Analyze portfolio complexity."""
return {
'has_dependencies': self.portfolio.correlation_matrix is not None,
'high_frequency': any(p.frequency > 10 for p in self.portfolio),
'complex_terms': any(p.has_complex_terms() for p in self.portfolio)
}
Batch Processing¶
Process multiple scenarios efficiently:
def batch_simulate(model, scenarios, n_simulations=100_000):
"""Simulate multiple scenarios efficiently."""
results = {}
# Warm up JIT compilation once
model.simulate(n_simulations=100, use_jit=True)
for scenario_name, scenario_params in scenarios.items():
# Apply scenario parameters
model.apply_scenario(scenario_params)
# Run optimized simulation
scenario_results = model.simulate(
n_simulations=n_simulations,
use_jit=True, # Already compiled
parallel=True
)
results[scenario_name] = scenario_results
return results
# Define scenarios
scenarios = {
'base_case': {'loss_ratio': 1.0},
'adverse': {'loss_ratio': 1.2},
'severe': {'loss_ratio': 1.5}
}
# Run batch simulation
batch_results = batch_simulate(model, scenarios)
Streaming Results¶
Handle very large simulations with streaming:
def streaming_simulate(model, total_simulations, chunk_size=100_000):
"""Simulate in chunks and stream results."""
aggregated_stats = SimulationAggregator()
n_chunks = (total_simulations + chunk_size - 1) // chunk_size
for i in range(n_chunks):
chunk_sims = min(chunk_size, total_simulations - i * chunk_size)
# Simulate chunk
chunk_results = model.simulate(
n_simulations=chunk_sims,
progress_bar=False # Avoid multiple progress bars
)
# Update aggregated statistics
aggregated_stats.add_chunk(chunk_results)
# Optional: yield intermediate results
yield aggregated_stats.current_stats()
return aggregated_stats.final_results()
Error Handling¶
Common Exceptions¶
The PricingModel
class raises specific exceptions for different error conditions:
from quactuary.exceptions import (
PortfolioValidationError,
MemoryLimitExceededError,
CompilationError,
ParallelProcessingError
)
try:
results = model.simulate(n_simulations=1_000_000)
except PortfolioValidationError as e:
print(f"Portfolio validation failed: {e}")
# Fix portfolio issues
except MemoryLimitExceededError as e:
print(f"Memory limit exceeded: {e}")
# Reduce simulation size or enable memory optimization
results = model.simulate(
n_simulations=500_000,
memory_limit_gb=4
)
except CompilationError as e:
print(f"JIT compilation failed: {e}")
# Fallback to non-JIT simulation
results = model.simulate(
n_simulations=1_000_000,
use_jit=False
)
except ParallelProcessingError as e:
print(f"Parallel processing failed: {e}")
# Fallback to single-threaded
results = model.simulate(
n_simulations=1_000_000,
parallel=False
)
Debugging Mode¶
Enable debugging for troubleshooting:
# Enable debug mode
model.debug = True
# Run simulation with detailed logging
results = model.simulate(
n_simulations=10_000,
verbose=True # Additional parameter for debug output
)
# Access debug information
print("Optimization decisions:")
for decision, reason in results.debug_info['optimization_decisions'].items():
print(f" {decision}: {reason}")
print(f"Compilation time: {results.debug_info['compilation_time']:.2f}s")
print(f"Memory usage: {results.debug_info['peak_memory_mb']:.1f}MB")
See Also¶
SimulationResults
- Results object returned bysimulate()
Portfolio
- Portfolio construction and managementOptimization Overview - Optimization strategies guide
Optimization Configuration Guide - Detailed parameter reference
Performance Benchmarks - Performance benchmarks