powerio_matrix/matrix/
triplet.rs1use rustc_hash::{FxBuildHasher, FxHashMap};
10use sprs::{CsMat, TriMat};
11
12type CoordinateMap = FxHashMap<usize, f64>;
13
14#[derive(Debug, Clone)]
15pub struct CooBuilder {
16 rows: usize,
17 cols: usize,
18 entries: CoordinateMap,
19}
20
21impl CooBuilder {
22 pub fn new(n: usize) -> Self {
24 Self::new_rect(n, n)
25 }
26
27 pub fn with_capacity(n: usize, capacity: usize) -> Self {
29 Self::with_capacity_rect(n, n, capacity)
30 }
31
32 pub fn new_rect(rows: usize, cols: usize) -> Self {
34 Self {
35 rows,
36 cols,
37 entries: CoordinateMap::default(),
38 }
39 }
40
41 pub fn with_capacity_rect(rows: usize, cols: usize, capacity: usize) -> Self {
43 Self {
44 rows,
45 cols,
46 entries: CoordinateMap::with_capacity_and_hasher(capacity, FxBuildHasher),
47 }
48 }
49
50 #[inline]
52 pub fn n(&self) -> usize {
53 self.rows
54 }
55
56 #[inline]
58 pub fn shape(&self) -> (usize, usize) {
59 (self.rows, self.cols)
60 }
61
62 #[inline]
68 pub fn add(&mut self, i: usize, j: usize, v: f64) {
69 if v == 0.0 {
70 return;
71 }
72 assert!(
73 i < self.rows && j < self.cols,
74 "COO coordinate ({i}, {j}) out of bounds for shape {}x{}",
75 self.rows,
76 self.cols
77 );
78 let key = i
79 .checked_mul(self.cols)
80 .and_then(|base| base.checked_add(j))
81 .expect("COO matrix dimensions overflow usize");
82 *self.entries.entry(key).or_insert(0.0) += v;
83 }
84
85 #[inline]
88 pub fn add_sym(&mut self, i: usize, j: usize, v: f64) {
89 if i == j {
90 self.add(i, j, v);
91 } else {
92 self.add(i, j, v);
93 self.add(j, i, v);
94 }
95 }
96
97 pub fn finish_csr(self) -> CsMat<f64> {
99 let mut tri = TriMat::with_capacity((self.rows, self.cols), self.entries.len());
100 for (key, v) in self.entries {
101 if v != 0.0 {
102 let i = key / self.cols;
103 let j = key % self.cols;
104 tri.add_triplet(i, j, v);
105 }
106 }
107 tri.to_csr()
108 }
109
110 pub fn finish_csc(self) -> CsMat<f64> {
112 self.finish_csr().to_csc()
113 }
114}