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