Skip to main content

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}