1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct IncidencePair {
7 point: usize,
8 line: usize,
9}
10
11impl IncidencePair {
12 #[must_use]
14 pub const fn new(point: usize, line: usize) -> Self {
15 Self { point, line }
16 }
17
18 #[must_use]
20 pub const fn point(self) -> usize {
21 self.point
22 }
23
24 #[must_use]
26 pub const fn line(self) -> usize {
27 self.line
28 }
29}
30
31#[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 #[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 #[must_use]
56 pub const fn point_count(&self) -> usize {
57 self.point_count
58 }
59
60 #[must_use]
62 pub const fn line_count(&self) -> usize {
63 self.line_count
64 }
65
66 #[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#[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 #[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 #[must_use]
107 pub const fn point_count(&self) -> usize {
108 self.point_count
109 }
110
111 #[must_use]
113 pub const fn line_count(&self) -> usize {
114 self.line_count
115 }
116
117 #[must_use]
119 pub fn pairs(&self) -> &[IncidencePair] {
120 &self.pairs
121 }
122
123 #[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}