178 lines
5.2 KiB
Markdown
178 lines
5.2 KiB
Markdown
|
|
# Protocol 11: Multi-Objective Optimization Support
|
||
|
|
|
||
|
|
**Status:** MANDATORY
|
||
|
|
**Applies To:** ALL optimization studies
|
||
|
|
**Last Updated:** 2025-11-21
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
ALL optimization engines in Atomizer MUST support both single-objective and multi-objective optimization without requiring code changes. This is a **critical requirement** that prevents runtime failures.
|
||
|
|
|
||
|
|
## The Problem
|
||
|
|
|
||
|
|
Previously, IntelligentOptimizer (Protocol 10) only supported single-objective optimization. When used with multi-objective studies, it would:
|
||
|
|
1. Successfully run all trials
|
||
|
|
2. Save trials to the Optuna database (`study.db`)
|
||
|
|
3. **CRASH** when trying to compile results, causing:
|
||
|
|
- No intelligent optimizer tracking files (confidence_history.json, strategy_transitions.json)
|
||
|
|
- No optimization_summary.json
|
||
|
|
- No final reports
|
||
|
|
- Silent failures that are hard to debug
|
||
|
|
|
||
|
|
## The Root Cause
|
||
|
|
|
||
|
|
Optuna has different APIs for single vs. multi-objective studies:
|
||
|
|
|
||
|
|
### Single-Objective
|
||
|
|
```python
|
||
|
|
study.best_trial # Returns single Trial object
|
||
|
|
study.best_params # Returns dict of parameters
|
||
|
|
study.best_value # Returns float
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multi-Objective
|
||
|
|
```python
|
||
|
|
study.best_trials # Returns LIST of Pareto-optimal trials
|
||
|
|
study.best_params # ❌ RAISES RuntimeError
|
||
|
|
study.best_value # ❌ RAISES RuntimeError
|
||
|
|
study.best_trial # ❌ RAISES RuntimeError
|
||
|
|
```
|
||
|
|
|
||
|
|
## The Solution
|
||
|
|
|
||
|
|
### 1. Always Check Study Type
|
||
|
|
|
||
|
|
```python
|
||
|
|
is_multi_objective = len(study.directions) > 1
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Use Conditional Access Patterns
|
||
|
|
|
||
|
|
```python
|
||
|
|
if is_multi_objective:
|
||
|
|
best_trials = study.best_trials
|
||
|
|
if best_trials:
|
||
|
|
# Select representative trial (e.g., first Pareto solution)
|
||
|
|
representative_trial = best_trials[0]
|
||
|
|
best_params = representative_trial.params
|
||
|
|
best_value = representative_trial.values # Tuple
|
||
|
|
best_trial_num = representative_trial.number
|
||
|
|
else:
|
||
|
|
best_params = {}
|
||
|
|
best_value = None
|
||
|
|
best_trial_num = None
|
||
|
|
else:
|
||
|
|
# Single-objective: safe to use standard API
|
||
|
|
best_params = study.best_params
|
||
|
|
best_value = study.best_value
|
||
|
|
best_trial_num = study.best_trial.number
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Return Rich Metadata
|
||
|
|
|
||
|
|
Always include in results:
|
||
|
|
```python
|
||
|
|
{
|
||
|
|
'best_params': best_params,
|
||
|
|
'best_value': best_value, # float or tuple
|
||
|
|
'best_trial': best_trial_num,
|
||
|
|
'is_multi_objective': is_multi_objective,
|
||
|
|
'pareto_front_size': len(study.best_trials) if is_multi_objective else 1,
|
||
|
|
# ... other fields
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Implementation Checklist
|
||
|
|
|
||
|
|
When creating or modifying any optimization component:
|
||
|
|
|
||
|
|
- [ ] **Study Creation**: Support `directions` parameter
|
||
|
|
```python
|
||
|
|
if directions:
|
||
|
|
study = optuna.create_study(directions=directions, ...)
|
||
|
|
else:
|
||
|
|
study = optuna.create_study(direction='minimize', ...)
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Result Compilation**: Check `len(study.directions) > 1`
|
||
|
|
- [ ] **Best Trial Access**: Use conditional logic (single vs. multi)
|
||
|
|
- [ ] **Logging**: Print Pareto front size for multi-objective
|
||
|
|
- [ ] **Reports**: Handle tuple objectives in visualization
|
||
|
|
- [ ] **Testing**: Test with BOTH single and multi-objective cases
|
||
|
|
|
||
|
|
## Files Fixed
|
||
|
|
|
||
|
|
- ✅ `optimization_engine/intelligent_optimizer.py`
|
||
|
|
- `_compile_results()` method
|
||
|
|
- `_run_fallback_optimization()` method
|
||
|
|
|
||
|
|
## Files That Need Review
|
||
|
|
|
||
|
|
Check these files for similar issues:
|
||
|
|
|
||
|
|
- [ ] `optimization_engine/study_continuation.py` (lines 96, 259-260)
|
||
|
|
- [ ] `optimization_engine/hybrid_study_creator.py` (line 468)
|
||
|
|
- [ ] `optimization_engine/intelligent_setup.py` (line 606)
|
||
|
|
- [ ] `optimization_engine/llm_optimization_runner.py` (line 384)
|
||
|
|
|
||
|
|
## Testing Protocol
|
||
|
|
|
||
|
|
Before marking any optimization study as complete:
|
||
|
|
|
||
|
|
1. **Single-Objective Test**
|
||
|
|
```python
|
||
|
|
directions=None # or ['minimize']
|
||
|
|
# Should complete without errors
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Multi-Objective Test**
|
||
|
|
```python
|
||
|
|
directions=['minimize', 'minimize']
|
||
|
|
# Should complete without errors
|
||
|
|
# Should generate ALL tracking files
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Verify Outputs**
|
||
|
|
- `2_results/study.db` exists
|
||
|
|
- `2_results/intelligent_optimizer/` has tracking files
|
||
|
|
- `2_results/optimization_summary.json` exists
|
||
|
|
- No RuntimeError in logs
|
||
|
|
|
||
|
|
## Design Principle
|
||
|
|
|
||
|
|
**"Write Once, Run Anywhere"**
|
||
|
|
|
||
|
|
Any optimization component should:
|
||
|
|
1. Accept both single and multi-objective problems
|
||
|
|
2. Automatically detect the study type
|
||
|
|
3. Handle result compilation appropriately
|
||
|
|
4. Never raise RuntimeError due to API misuse
|
||
|
|
|
||
|
|
## Example: Bracket Study
|
||
|
|
|
||
|
|
The bracket_stiffness_optimization study is multi-objective:
|
||
|
|
- Objective 1: Maximize stiffness (minimize -stiffness)
|
||
|
|
- Objective 2: Minimize mass
|
||
|
|
- Constraint: mass ≤ 0.2 kg
|
||
|
|
|
||
|
|
This study exposed the bug because:
|
||
|
|
```python
|
||
|
|
directions = ["minimize", "minimize"] # Multi-objective
|
||
|
|
```
|
||
|
|
|
||
|
|
After the fix, it should:
|
||
|
|
- Run all 50 trials successfully
|
||
|
|
- Generate Pareto front with multiple solutions
|
||
|
|
- Save all intelligent optimizer tracking files
|
||
|
|
- Create complete reports with tuple objectives
|
||
|
|
|
||
|
|
## Future Work
|
||
|
|
|
||
|
|
- Add explicit validation in `IntelligentOptimizer.__init__()` to warn about common mistakes
|
||
|
|
- Create helper function `get_best_solution(study)` that handles both cases
|
||
|
|
- Add unit tests for multi-objective support in all optimizers
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Remember:** Multi-objective support is NOT optional. It's a core requirement for production-ready optimization engines.
|