Skip to main content

dtrees_rs/algorithms/common/utils/
mod.rs

1use crate::cover::Cover;
2use crate::globals::item;
3
4/// The features, among `candidates` (all of them when `None`) and other than
5/// `previous`, that leave at least `min_sup` instances on each side.
6pub fn find_valid_split_attributes(
7    cover: &mut Cover,
8    min_sup: usize,
9    candidates: Option<&[usize]>,
10    previous: Option<usize>,
11) -> Vec<usize> {
12    match candidates {
13        Some(attrs) => {
14            let mut valid = Vec::new();
15            for &attribute in attrs {
16                if previous == Some(attribute) {
17                    continue;
18                }
19
20                let left_count = cover.count_if_branch_on(item(attribute, 0));
21                let right_count = cover.count_if_branch_on(item(attribute, 1));
22
23                if left_count >= min_sup && right_count >= min_sup {
24                    valid.push(attribute);
25                }
26            }
27            valid
28        }
29
30        None => {
31            let num_attributes = cover.num_attributes;
32            let mut valid_attributes = Vec::with_capacity(num_attributes);
33
34            for attr_idx in 0..num_attributes {
35                if previous == Some(attr_idx) {
36                    continue;
37                }
38
39                let left_count = cover.count_if_branch_on(item(attr_idx, 0));
40                let right_count = cover.count_if_branch_on(item(attr_idx, 1));
41
42                if left_count >= min_sup && right_count >= min_sup {
43                    valid_attributes.push(attr_idx);
44                }
45            }
46
47            valid_attributes
48        }
49    }
50}
51
52/// Class counts for every pair of candidates: `matrix[i][j]` counts the
53/// instances in the right branch of both `candidates[i]` and `candidates[j]`,
54/// and `matrix[i][i]` those in the right branch of `candidates[i]`. Every
55/// other leaf of a depth-2 tree follows by subtraction.
56pub fn build_labels_count_distribution_matrix(
57    cover: &mut Cover,
58    candidates: &[usize],
59) -> Vec<Vec<Vec<usize>>> {
60    let size = candidates.len();
61    let mut matrix = vec![vec![vec![]; size]; size];
62
63    for i in 0..size {
64        cover.branch_on(item(candidates[i], 1));
65
66        let first_split_distribution = cover.labels_count();
67        matrix[i][i] = first_split_distribution;
68
69        for j in i + 1..size {
70            cover.branch_on(item(candidates[j], 1));
71            let second_split_distribution = cover.labels_count();
72            matrix[i][j] = second_split_distribution.clone();
73            matrix[j][i] = second_split_distribution;
74            cover.backtrack();
75        }
76        cover.backtrack();
77    }
78    matrix
79}
80
81/// Class counts of a child's sibling: the parent's counts minus the child's.
82#[inline]
83pub fn deduce_sibling_error(parent_supports: &[usize], child_supports: &[usize]) -> Vec<usize> {
84    parent_supports
85        .iter()
86        .zip(child_supports.iter())
87        .map(|(root, child)| *root - *child)
88        .collect()
89}
90
91/// [`deduce_sibling_error`] writing into `buffer`.
92#[inline]
93pub fn deduce_sibling_error_with_buffer(parent: &[usize], sibling: &[usize], buffer: &mut [usize]) {
94    for i in 0..parent.len() {
95        buffer[i] = parent[i] - sibling[i];
96    }
97}