Skip to main content

dtrees_rs/caching/
entry.rs

1/// What the search knows about one subproblem.
2///
3/// `error` is the best error found so far, an upper bound on the optimum;
4/// `lower_bound` is a proven lower bound. The two meet when the subproblem is
5/// solved.
6#[derive(Copy, Clone, Debug)]
7pub struct CacheEntry {
8    item: usize,
9    test: usize,
10    error: f64,
11    upper_bound: f64,
12    lower_bound: f64,
13    metric: f64,
14    size: usize,
15    leaf_error: f64,
16    out: f64,
17    is_optimal: bool,
18    is_leaf: bool,
19}
20impl CacheEntry {
21    /// An unsolved entry reached by `item`.
22    pub fn new(item: usize) -> Self {
23        Self {
24            item,
25            test: <usize>::MAX,
26            error: f64::INFINITY,
27            upper_bound: f64::INFINITY,
28            lower_bound: 0.0,
29            metric: 0.0,
30            size: 0,
31            leaf_error: f64::INFINITY,
32            out: 0.0,
33            is_optimal: false,
34            is_leaf: false,
35        }
36    }
37
38    /// The item leading to this entry from its parent in the trie.
39    pub fn item(&self) -> usize {
40        self.item
41    }
42
43    /// The feature tested at this node, `usize::MAX` if none.
44    pub fn test(&self) -> usize {
45        self.test
46    }
47
48    /// Best error found so far.
49    pub fn error(&self) -> f64 {
50        self.error
51    }
52
53    /// Upper bound the subproblem was last solved under.
54    pub fn upper_bound(&self) -> f64 {
55        self.upper_bound
56    }
57
58    /// Proven lower bound on the error.
59    pub fn lower_bound(&self) -> f64 {
60        self.lower_bound
61    }
62
63    /// Score used by searches that optimise another metric.
64    pub fn metric(&self) -> f64 {
65        self.metric
66    }
67
68    /// Number of instances in the subproblem.
69    pub fn size(&self) -> usize {
70        self.size
71    }
72
73    /// Error of the subproblem as a leaf.
74    pub fn leaf_error(&self) -> f64 {
75        self.leaf_error
76    }
77
78    /// Prediction of the subproblem as a leaf.
79    pub fn out(&self) -> f64 {
80        self.out
81    }
82
83    /// Whether the subproblem is solved.
84    pub fn is_optimal(&self) -> bool {
85        self.is_optimal
86    }
87
88    /// Whether the best subtree is a leaf.
89    pub fn is_leaf(&self) -> bool {
90        self.is_leaf
91    }
92
93    pub fn has_valid_test(&self) -> bool {
94        self.test != usize::MAX
95    }
96
97    pub fn has_finite_error(&self) -> bool {
98        self.error.is_finite()
99    }
100
101    pub fn has_finite_upper_bound(&self) -> bool {
102        self.upper_bound.is_finite()
103    }
104
105    pub fn has_finite_leaf_error(&self) -> bool {
106        self.leaf_error.is_finite()
107    }
108}
109
110impl Default for CacheEntry {
111    fn default() -> Self {
112        Self {
113            item: <usize>::MAX,
114            test: <usize>::MAX,
115            error: f64::INFINITY,
116            upper_bound: f64::INFINITY,
117            lower_bound: 0.0,
118            metric: 0.0,
119            size: 0,
120            leaf_error: f64::INFINITY,
121            out: 0.0,
122            is_optimal: false,
123            is_leaf: false,
124        }
125    }
126}
127
128/// Chained setters for a [`CacheEntry`].
129pub struct CacheEntryUpdater<'a> {
130    node: &'a mut CacheEntry,
131}
132
133impl<'a> CacheEntryUpdater<'a> {
134    pub fn new(node: &'a mut CacheEntry) -> Self {
135        Self { node }
136    }
137
138    pub fn item(self, item: usize) -> Self {
139        self.node.item = item;
140        self
141    }
142
143    pub fn test(self, test: usize) -> Self {
144        self.node.test = test;
145        self
146    }
147
148    pub fn error(self, error: f64) -> Self {
149        self.node.error = error;
150        self
151    }
152
153    pub fn upper_bound(self, upper_bound: f64) -> Self {
154        self.node.upper_bound = upper_bound;
155        self
156    }
157    pub fn lower_bound(self, lower_bound: f64) -> Self {
158        self.node.lower_bound = lower_bound;
159        self
160    }
161
162    pub fn metric(self, metric: f64) -> Self {
163        self.node.metric = metric;
164        self
165    }
166
167    pub fn size(self, size: usize) -> Self {
168        self.node.size = size;
169        self
170    }
171
172    pub fn leaf_error(self, leaf_error: f64) -> Self {
173        self.node.leaf_error = leaf_error;
174        self
175    }
176
177    pub fn output(self, output: f64) -> Self {
178        self.node.out = output;
179        self
180    }
181
182    /// Marks the entry as solved.
183    pub fn optimal(self) -> Self {
184        self.node.is_optimal = true;
185        self
186    }
187
188    /// Makes the entry a leaf, with its leaf error as its error.
189    pub fn leaf(self) -> Self {
190        self.node.is_leaf = true;
191        self.node.error = self.node.leaf_error;
192        self
193    }
194
195    pub fn get_error(&self) -> f64 {
196        self.node.error
197    }
198
199    pub fn get_leaf_error(&self) -> f64 {
200        self.node.leaf_error
201    }
202
203    pub fn get_lower_bound(&self) -> f64 {
204        self.node.lower_bound
205    }
206}