Skip to main content

use_incidence/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// A point-line incidence pair.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct IncidencePair {
7    point: usize,
8    line: usize,
9}
10
11impl IncidencePair {
12    /// Creates an incidence pair.
13    #[must_use]
14    pub const fn new(point: usize, line: usize) -> Self {
15        Self { point, line }
16    }
17
18    /// Returns the point index.
19    #[must_use]
20    pub const fn point(self) -> usize {
21        self.point
22    }
23
24    /// Returns the line index.
25    #[must_use]
26    pub const fn line(self) -> usize {
27        self.line
28    }
29}
30
31/// A dense incidence matrix.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct IncidenceMatrix {
34    point_count: usize,
35    line_count: usize,
36    entries: Vec<bool>,
37}
38
39impl IncidenceMatrix {
40    /// Creates a dense incidence matrix when the entry count matches `point_count * line_count`.
41    #[must_use]
42    pub fn new(point_count: usize, line_count: usize, entries: Vec<bool>) -> Option<Self> {
43        if point_count > 0 && line_count > 0 && entries.len() == point_count * line_count {
44            Some(Self {
45                point_count,
46                line_count,
47                entries,
48            })
49        } else {
50            None
51        }
52    }
53
54    /// Returns the point count.
55    #[must_use]
56    pub const fn point_count(&self) -> usize {
57        self.point_count
58    }
59
60    /// Returns the line count.
61    #[must_use]
62    pub const fn line_count(&self) -> usize {
63        self.line_count
64    }
65
66    /// Returns whether a point is incident with a line.
67    #[must_use]
68    pub fn is_incident(&self, point: usize, line: usize) -> Option<bool> {
69        if point < self.point_count && line < self.line_count {
70            Some(self.entries[(point * self.line_count) + line])
71        } else {
72            None
73        }
74    }
75}
76
77/// A sparse incidence structure.
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct IncidenceStructure {
80    point_count: usize,
81    line_count: usize,
82    pairs: Vec<IncidencePair>,
83}
84
85impl IncidenceStructure {
86    /// Creates an incidence structure when all pairs are in range.
87    #[must_use]
88    pub fn new(point_count: usize, line_count: usize, pairs: Vec<IncidencePair>) -> Option<Self> {
89        if point_count > 0
90            && line_count > 0
91            && pairs
92                .iter()
93                .all(|pair| pair.point() < point_count && pair.line() < line_count)
94        {
95            Some(Self {
96                point_count,
97                line_count,
98                pairs,
99            })
100        } else {
101            None
102        }
103    }
104
105    /// Returns the point count.
106    #[must_use]
107    pub const fn point_count(&self) -> usize {
108        self.point_count
109    }
110
111    /// Returns the line count.
112    #[must_use]
113    pub const fn line_count(&self) -> usize {
114        self.line_count
115    }
116
117    /// Returns the incidence pairs.
118    #[must_use]
119    pub fn pairs(&self) -> &[IncidencePair] {
120        &self.pairs
121    }
122
123    /// Returns the incidence pair count.
124    #[must_use]
125    pub fn incidence_count(&self) -> usize {
126        self.pairs.len()
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::{IncidenceMatrix, IncidencePair, IncidenceStructure};
133
134    #[test]
135    fn validates_incidence_structures() {
136        let pair = IncidencePair::new(1, 0);
137        let structure = IncidenceStructure::new(2, 1, vec![pair]).expect("valid structure");
138        let matrix = IncidenceMatrix::new(2, 1, vec![false, true]).expect("valid matrix");
139
140        assert_eq!(structure.point_count(), 2);
141        assert_eq!(structure.line_count(), 1);
142        assert_eq!(structure.incidence_count(), 1);
143        assert_eq!(matrix.is_incident(1, 0), Some(true));
144        assert_eq!(IncidenceStructure::new(1, 1, vec![pair]), None);
145    }
146}