dtrees_rs/algorithms/optimal/rules/
gain.rs1use crate::algorithms::optimal::rules::core::Reason;
2use crate::algorithms::optimal::rules::helpers::StepStrategy;
3use crate::algorithms::optimal::rules::{Rule, RuleContext, RuleResult, RuleState};
4
5pub struct GainRule {
13 gap: f64,
14 delta: f64,
15 limit: f64,
16 increment: Box<dyn StepStrategy>,
17 priority: u8,
18 delay: u8,
19 relaxable: bool,
20 state: RuleState,
21}
22
23impl GainRule {
24 pub fn new(gap: f64, delta: f64, limit: f64, increment: Box<dyn StepStrategy>) -> Self {
26 Self {
27 gap,
28 delta,
29 limit,
30 increment,
31 priority: 91,
32 delay: 0,
33 relaxable: true,
34 state: RuleState::Disabled,
35 }
36 }
37
38 pub fn with_priority(mut self, priority: u8) -> Self {
40 self.priority = priority;
41 self
42 }
43
44 pub fn with_delay(mut self, delay: u8) -> Self {
46 self.delay = delay;
47 self
48 }
49
50 pub fn with_gap(mut self, gap: f64) -> Self {
52 self.gap = gap;
53 self
54 }
55
56 pub fn with_limit(mut self, limit: f64) -> Self {
58 self.limit = limit;
59 self
60 }
61
62 pub fn update_gap_delta(&mut self, delta: f64) {
65 if delta <= 0.0 {
66 return;
67 }
68 self.delta = delta;
69 }
70
71 pub fn update_limit(&mut self, limit: f64) {
73 self.limit = self.limit.min(limit);
74 }
75}
76
77impl Rule for GainRule {
78 fn evaluate(&self, context: &RuleContext) -> RuleResult {
79 if !self.is_active() {
80 return RuleResult::continue_search();
81 }
82 if context.gain > self.gap {
83 RuleResult::stop_with_bound(f64::INFINITY, Reason::RuleReason)
84 } else {
85 RuleResult::continue_search()
86 }
87 }
88
89 fn priority(&self) -> u8 {
90 self.priority
91 }
92
93 fn description(&self) -> String {
94 "Gain rule".to_string()
95 }
96
97 fn state(&self) -> RuleState {
98 self.state
99 }
100
101 fn activate(&mut self) {
102 self.state = RuleState::Active
103 }
104
105 fn deactivate(&mut self) {
106 self.state = RuleState::Disabled
107 }
108
109 fn is_relaxable(&self) -> bool {
110 self.relaxable
111 }
112
113 fn relax(&mut self) {
114 if !self.is_active() {
115 return;
116 }
117 if self.is_relaxable() && self.gap >= self.limit {
118 self.deactivate();
119 return;
120 }
121 self.gap = self.delta * self.increment.next() as f64;
122 if self.gap >= self.limit {
123 self.gap = self.limit
124 }
125 }
126
127 fn delay(&self) -> u8 {
128 self.delay
129 }
130
131 fn as_any(&self) -> &dyn std::any::Any {
132 self
133 }
134
135 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
136 self
137 }
138}