dtrees_rs/algorithms/optimal/rules/
purity.rs1use crate::algorithms::optimal::rules::core::Reason;
2use crate::algorithms::optimal::rules::{Rule, RuleContext, RuleResult, RuleState};
3
4pub struct PurityRule {
10 delta: f64,
11 threshold: f64,
12 priority: u8,
13 state: RuleState,
14 relaxable: bool,
15}
16
17impl PurityRule {
18 pub fn new(initial_threshold: f64, delta: f64) -> Self {
20 Self {
21 delta,
22 threshold: initial_threshold,
23 priority: 90,
24 state: RuleState::Disabled,
25 relaxable: true,
26 }
27 }
28
29 pub fn with_priority(mut self, priority: u8) -> Self {
31 self.priority = priority;
32 self
33 }
34}
35
36impl Rule for PurityRule {
37 fn evaluate(&self, context: &RuleContext) -> RuleResult {
38 let purity = 1.0 - context.error.min(context.leaf_error) / context.support as f64;
39 if purity >= self.threshold {
40 RuleResult::stop_with_bound(f64::INFINITY, Reason::RuleReason)
41 } else {
42 RuleResult::continue_search()
43 }
44 }
45
46 fn priority(&self) -> u8 {
47 self.priority
48 }
49
50 fn description(&self) -> String {
51 "Purity rule".to_string()
52 }
53
54 fn state(&self) -> RuleState {
55 self.state
56 }
57
58 fn activate(&mut self) {
59 self.state = RuleState::Active
60 }
61
62 fn deactivate(&mut self) {
63 self.state = RuleState::Disabled
64 }
65
66 fn relax(&mut self) {
67 if !self.is_active() {
68 return;
69 }
70
71 if self.is_relaxable() && self.threshold >= 1.0 {
72 self.deactivate();
73 return;
74 }
75 self.threshold += self.delta;
76 if self.threshold >= 1.0 {
77 self.threshold = 1.0
78 }
79 }
80
81 fn is_relaxable(&self) -> bool {
82 self.relaxable
83 }
84
85 fn as_any(&self) -> &dyn std::any::Any {
86 self
87 }
88
89 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
90 self
91 }
92}