1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* Shadow variable support traits for solutions with derived values.
Provides [`ShadowVariableSupport`] and [`SolvableSolution`] traits
for integrating shadow variable updates into the solving protocol.
*/
use ;
/* Trait for solutions that maintain shadow variables.
Shadow variables are derived values that depend on planning variables.
When a planning variable changes, the corresponding shadow variables
must be updated before constraint evaluation.
# Entity-Level Updates
This trait provides entity-level granularity: when a variable on entity N
changes, only entity N's shadow variables are updated. This enables O(1)
incremental updates instead of full solution recalculation.
# Example
```
use solverforge_scoring::director::ShadowVariableSupport;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SoftScore;
#[derive(Clone)]
struct Visit {
demand: i32,
// Shadow variable: arrival time depends on previous visit
arrival_time: i64,
}
#[derive(Clone)]
struct Vehicle {
visits: Vec<usize>,
// Cached aggregate: total demand of assigned visits
cached_total_demand: i32,
}
#[derive(Clone)]
struct VrpSolution {
visits: Vec<Visit>,
vehicles: Vec<Vehicle>,
score: Option<SoftScore>,
}
impl PlanningSolution for VrpSolution {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> { self.score }
fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}
impl ShadowVariableSupport for VrpSolution {
fn update_entity_shadows(&mut self, entity_index: usize) {
// Update cached total demand for this vehicle
let total: i32 = self.vehicles[entity_index]
.visits
.iter()
.map(|&idx| self.visits[idx].demand)
.sum();
self.vehicles[entity_index].cached_total_demand = total;
}
fn update_all_shadows(&mut self) {
for i in 0..self.vehicles.len() {
self.update_entity_shadows(i);
}
}
}
```
*/
/* Trait for solutions that can be solved using the fluent builder API.
This trait combines all requirements for automatic solver wiring:
- `PlanningSolution` for score management
- `ShadowVariableSupport` for shadow variable updates
- Solution descriptor for entity metadata
- Entity count for move selector iteration
Typically implemented automatically by the `#[planning_solution]` macro.
# Example
```
use solverforge_scoring::ShadowVariableSupport;
use solverforge_scoring::director::SolvableSolution;
use solverforge_core::domain::{PlanningSolution, SolutionDescriptor};
use solverforge_core::score::SoftScore;
use std::any::TypeId;
#[derive(Clone)]
struct MyPlan {
entities: Vec<i64>,
score: Option<SoftScore>,
}
impl PlanningSolution for MyPlan {
type Score = SoftScore;
fn score(&self) -> Option<Self::Score> { self.score }
fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}
impl ShadowVariableSupport for MyPlan {
fn update_entity_shadows(&mut self, _idx: usize) {}
}
impl SolvableSolution for MyPlan {
fn descriptor() -> SolutionDescriptor {
SolutionDescriptor::new("MyPlan", TypeId::of::<MyPlan>())
}
fn entity_count(solution: &Self, _desc_idx: usize) -> usize {
solution.entities.len()
}
}
```
*/