rlu/
dfs.rs

1use crate::debug::debug;
2use crate::traits::{Int, Scalar};
3use crate::Matrix;
4
5// Depth-first-search workspace.
6pub struct DFS {
7    root_list: Vec<usize>,
8    // ptr_list: Vec<usize>,
9    ptr_list2: Vec<(usize, usize)>,
10    flag: Vec<bool>,
11}
12
13impl DFS {
14    pub fn new(n: usize) -> Self {
15        Self {
16            root_list: vec![0; n],
17            // ptr_list: vec![0; n],
18            ptr_list2: vec![(0, 0); n],
19            flag: vec![false; n],
20        }
21    }
22
23    pub fn ludfs<I: Int, S: Scalar>(
24        &mut self,
25        l_mat: &Matrix<I, S>,
26        b_rowidx: &[I],
27        rperm: &[Option<usize>],
28    ) -> &[usize] {
29        debug!("b = {:?}", b_rowidx);
30
31        // let csgraph = matrix_to_csc(l_mat);
32        // debug!("L =\n{}", csgraph.to_table());
33
34        let n = l_mat.len();
35        // let n = csgraph.cols();
36        // let indices = csgraph.rowidx();
37        // let indptr = csgraph.colptr();
38        // let n = l_mat.cols();
39        // let indices = l_mat.rowidx();
40        // let indptr = l_mat.colptr();
41
42        // println!("\nindices = {:?}", indices);
43        // println!("indptr = {:?}", indptr);
44
45        let mut i_rl_start = n;
46
47        for &e0 in b_rowidx {
48            // The depth-first search must mark the vertices it
49            // has reached, to avoid repeating parts of the search.
50            if self.flag[e0.to_index()] {
51                continue;
52            }
53
54            // self.dfs(e0, indices, indptr, &mut i_rl_start, rperm);
55            self.dfs(
56                e0.to_index(),
57                /*indices, indptr,*/ l_mat,
58                &mut i_rl_start,
59                rperm,
60            );
61        }
62
63        let found = &self.root_list[i_rl_start..];
64        debug!(
65            "found = {:?} {} {:?}",
66            found.to_vec(),
67            i_rl_start,
68            self.root_list
69        );
70
71        // debug!("flag = {:?}", self.flag);
72        found.iter().for_each(|i| self.flag[*i] = false);
73
74        found
75    }
76
77    // Based on `depth_first_directed` from SciPy v1.11.
78    // Modified to support repeated calls with different start nodes
79    // and the same permuted input matrix.
80    //
81    // Author: Jake Vanderplas  -- <vanderplas@astro.washington.edu>
82    // License: BSD, (C) 2012
83    pub(crate) fn dfs<I: Int, S: Scalar>(
84        &mut self,
85        head_node: usize,
86        // indices: &[usize],
87        // indptr: &[usize],
88        l_mat: &Matrix<I, S>,
89        i_rl_start: &mut usize,
90        rperm: &[Option<usize>],
91    ) {
92        // let n = node_list.len();
93
94        // node_list[0] = head_node;
95        self.root_list[0] = head_node;
96        let mut i_root_opt: Option<usize> = Some(0);
97        // let mut i_nl_end = 1;
98        // flag[head_node] = true;
99
100        while let Some(mut i_root) = i_root_opt {
101            let pnode = self.root_list[i_root];
102            let pnode_p = rperm[pnode];
103
104            if !self.flag[pnode] {
105                self.flag[pnode] = true;
106                match pnode_p {
107                    Some(pnode_p) => {
108                        // self.ptr_list[i_root] = indptr[pnode_p];
109                        self.ptr_list2[i_root] = (pnode_p, 0);
110                    }
111                    None => {
112                        // self.ptr_list[i_root] = 0;
113                        self.ptr_list2[i_root] = (0, 0);
114                    }
115                }
116            }
117
118            let mut no_children = true;
119
120            // let indptr1 = self.ptr_list[i_root];
121            // let indptr2 = match pnode_p {
122            //     Some(pnode_p) => indptr[pnode_p + 1],
123            //     None => 0,
124            // };
125            // println!(
126            //     "\nind[{}..{}] = {:?}",
127            //     indptr1,
128            //     indptr2,
129            //     indices[indptr1..indptr2].to_vec()
130            // );
131
132            if pnode_p.is_some() {
133                let (lcolind, lrow_offset) = self.ptr_list2[i_root];
134                let lcol = &l_mat[lcolind];
135                // println!(
136                //     "col = {} {} ({}) - {:?}",
137                //     lcolind,
138                //     lrow_offset,
139                //     pnode_p.is_none(),
140                //     lcol
141                // );
142
143                // debug!(
144                //     "pnode = {}, pnode_p = {:?}, p1 = {}, p2 = {}",
145                //     pnode, pnode_p, indptr1, indptr2
146                // );
147                let mut k = 0;
148                // for i in indptr1..indptr2 {
149                for j in lrow_offset..lcol.len() {
150                    k += 1;
151                    let (cnode, _) = &lcol[j];
152                    // let cnode = indices[i];
153                    // let cnode = l_mat[indptr1.0][j].0;
154                    if self.flag[cnode.to_index()] {
155                        continue;
156                    } else {
157                        // self.ptr_list[i_root] = i;
158                        self.ptr_list2[i_root] = (lcolind, k - 1);
159
160                        i_root += 1;
161                        i_root_opt = Some(i_root);
162                        self.root_list[i_root] = cnode.to_index();
163                        // node_list[i_nl_end] = cnode;
164                        // flag[cnode] = true;
165                        // i_nl_end += 1;
166
167                        // debug!("i_root = {}, cnode = {}", i_root, cnode);
168                        no_children = false;
169                        break;
170                    }
171                }
172            }
173
174            if *i_rl_start == 0 {
175                break;
176            }
177
178            if no_children {
179                i_root_opt = if i_root > 0 { Some(i_root - 1) } else { None };
180
181                *i_rl_start -= 1;
182                self.root_list[*i_rl_start] = pnode;
183                // debug!("i_rl_start = {}, pnode = {}", *i_rl_start, pnode);
184            }
185        }
186    }
187}