solverforge_core/domain/variable.rs
1// Variable type definitions
2
3use std::any::TypeId;
4
5// The type of a planning variable.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum VariableType {
8 // A genuine planning variable that the solver optimizes.
9 Genuine,
10 /* A chained planning variable where entities form chains rooted at anchors.
11
12 Chained variables are used for problems like vehicle routing where:
13 - Each entity points to either an anchor (problem fact) or another entity
14 - Entities form chains: Anchor ← Entity1 ← Entity2 ← Entity3
15 - No cycles or branching allowed
16 */
17 Chained,
18 // A list variable containing multiple values.
19 List,
20 // A shadow variable computed from other variables.
21 Shadow(ShadowVariableKind),
22}
23
24// The kind of shadow variable.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum ShadowVariableKind {
27 // Custom shadow variable with user-defined listener.
28 Custom,
29 // Inverse of another variable (bidirectional relationship).
30 InverseRelation,
31 // Index within a list variable.
32 Index,
33 // Next element in a list variable.
34 NextElement,
35 // Previous element in a list variable.
36 PreviousElement,
37 // Anchor in a chained variable.
38 Anchor,
39 // Cascading update from other shadow variables.
40 Cascading,
41 // Piggyback on another shadow variable's listener.
42 Piggyback,
43}
44
45// The type of value range for a planning variable.
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum ValueRangeType {
48 // A collection of discrete values.
49 Collection,
50 // A countable range (e.g., integers from 1 to 100).
51 CountableRange {
52 // Inclusive start of the range.
53 from: i64,
54 // Exclusive end of the range.
55 to: i64,
56 },
57 // An entity-dependent value range.
58 EntityDependent,
59}
60
61impl VariableType {
62 /// Returns true if this is a genuine (non-shadow) variable.
63 ///
64 /// Genuine variables include basic, chained, and list variables.
65 pub fn is_genuine(&self) -> bool {
66 matches!(
67 self,
68 VariableType::Genuine | VariableType::Chained | VariableType::List
69 )
70 }
71
72 pub fn is_shadow(&self) -> bool {
73 matches!(self, VariableType::Shadow(_))
74 }
75
76 pub fn is_list(&self) -> bool {
77 matches!(self, VariableType::List)
78 }
79
80 /// Returns true if this is a chained variable.
81 ///
82 /// Chained variables form chains rooted at anchor problem facts.
83 pub fn is_chained(&self) -> bool {
84 matches!(self, VariableType::Chained)
85 }
86
87 pub fn is_basic(&self) -> bool {
88 matches!(self, VariableType::Genuine)
89 }
90}
91
92impl ShadowVariableKind {
93 pub fn requires_listener(&self) -> bool {
94 matches!(
95 self,
96 ShadowVariableKind::Custom | ShadowVariableKind::Cascading
97 )
98 }
99
100 pub fn is_automatic(&self) -> bool {
101 matches!(
102 self,
103 ShadowVariableKind::InverseRelation
104 | ShadowVariableKind::Index
105 | ShadowVariableKind::NextElement
106 | ShadowVariableKind::PreviousElement
107 | ShadowVariableKind::Anchor
108 )
109 }
110
111 /// Returns true if this shadow variable piggybacks on another
112 /// shadow variable's listener rather than having its own.
113 pub fn is_piggyback(&self) -> bool {
114 matches!(self, ShadowVariableKind::Piggyback)
115 }
116}
117
118/* Information about a chained variable's configuration.
119
120Chained variables require knowledge of the anchor type to distinguish
121between anchor values (chain roots) and entity values (chain members).
122*/
123#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct ChainedVariableInfo {
125 // The TypeId of the anchor type (problem fact at chain root).
126 pub anchor_type_id: TypeId,
127 // The TypeId of the entity type (chain members).
128 pub entity_type_id: TypeId,
129 // Whether this variable has an associated anchor shadow variable.
130 pub has_anchor_shadow: bool,
131}
132
133impl ChainedVariableInfo {
134 /// Creates new chained variable info.
135 pub fn new<Anchor: 'static, Entity: 'static>() -> Self {
136 Self {
137 anchor_type_id: TypeId::of::<Anchor>(),
138 entity_type_id: TypeId::of::<Entity>(),
139 has_anchor_shadow: false,
140 }
141 }
142
143 /// Creates new chained variable info with anchor shadow variable.
144 pub fn with_anchor_shadow<Anchor: 'static, Entity: 'static>() -> Self {
145 Self {
146 anchor_type_id: TypeId::of::<Anchor>(),
147 entity_type_id: TypeId::of::<Entity>(),
148 has_anchor_shadow: true,
149 }
150 }
151
152 pub fn is_anchor_type(&self, type_id: TypeId) -> bool {
153 self.anchor_type_id == type_id
154 }
155
156 pub fn is_entity_type(&self, type_id: TypeId) -> bool {
157 self.entity_type_id == type_id
158 }
159}