outram_foam_basic_lib/polynomial/
roots.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[repr(u64)]
25pub enum RootType {
26 Real = 0,
27 Complex = 1,
28 PosInf = 2,
29 NegInf = 3,
30 Nan = 4,
31}
32
33#[derive(Debug, Clone, Copy)]
38pub struct Roots<const N: usize> {
39 pub(crate) values: [f64; N],
40 types: u64,
41}
42
43impl<const N: usize> Roots<N> {
44 #[inline]
46 pub fn get(&self, i: usize) -> f64 {
47 self.values[i]
48 }
49
50 #[inline]
52 pub fn root_type(&self, i: usize) -> RootType {
53 match (self.types >> (3 * i)) & 7 {
54 0 => RootType::Real,
55 1 => RootType::Complex,
56 2 => RootType::PosInf,
57 3 => RootType::NegInf,
58 _ => RootType::Nan,
59 }
60 }
61
62 #[inline]
64 pub fn set_type(&mut self, i: usize, t: RootType) {
65 let shift = 3 * i;
66 self.types = (self.types & !(7u64 << shift)) | ((t as u64) << shift);
67 }
68}
69
70impl<const N: usize> std::ops::Index<usize> for Roots<N> {
71 type Output = f64;
72 #[inline]
73 fn index(&self, i: usize) -> &f64 {
74 &self.values[i]
75 }
76}
77
78impl Roots<1> {
85 #[inline]
87 pub fn new(t: RootType, x: f64) -> Self {
88 Self {
89 values: [x],
90 types: t as u64,
91 }
92 }
93}
94
95impl Roots<2> {
96 #[inline]
98 pub fn from_pair(a: Roots<1>, b: Roots<1>) -> Self {
99 Self {
100 values: [a.values[0], b.values[0]],
101 types: a.types | (b.types << 3),
102 }
103 }
104
105 #[inline]
108 pub fn with_tail(head: Roots<1>, t: RootType, x: f64) -> Self {
109 Self {
110 values: [head.values[0], x],
111 types: head.types | ((t as u64) << 3),
112 }
113 }
114
115 #[inline]
118 pub fn both(r: Roots<1>) -> Self {
119 Self::from_pair(r, r)
120 }
121}
122
123impl Roots<3> {
124 #[inline]
127 pub fn uniform(t: RootType, x: f64) -> Self {
128 let ti = t as u64;
129 Self {
130 values: [x, x, x],
131 types: ti | (ti << 3) | (ti << 6),
132 }
133 }
134
135 #[inline]
138 pub fn concat_1_2(a: Roots<1>, b: Roots<2>) -> Self {
139 Self {
140 values: [a.values[0], b.values[0], b.values[1]],
141 types: a.types | (b.types << 3),
142 }
143 }
144
145 #[inline]
148 pub fn concat_2_1(a: Roots<2>, b: Roots<1>) -> Self {
149 Self {
150 values: [a.values[0], a.values[1], b.values[0]],
151 types: a.types | (b.types << 6),
152 }
153 }
154
155 #[inline]
158 pub fn with_tail(head: Roots<2>, t: RootType, x: f64) -> Self {
159 Self::concat_2_1(head, Roots::<1>::new(t, x))
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn encoding_round_trip() {
169 let r = Roots::<1>::new(RootType::Real, 3.14);
170 assert_eq!(r.root_type(0), RootType::Real);
171 assert_eq!(r.get(0), 3.14);
172 }
173
174 #[test]
175 fn concat_2() {
176 let a = Roots::<1>::new(RootType::Real, 1.0);
177 let b = Roots::<1>::new(RootType::Nan, 0.0);
178 let r = Roots::<2>::from_pair(a, b);
179 assert_eq!(r.root_type(0), RootType::Real);
180 assert_eq!(r.root_type(1), RootType::Nan);
181 assert_eq!(r[0], 1.0);
182 assert_eq!(r[1], 0.0);
183 }
184
185 #[test]
186 fn concat_3() {
187 let a = Roots::<1>::new(RootType::Real, 1.0);
188 let b = Roots::<2>::from_pair(
189 Roots::<1>::new(RootType::Real, 2.0),
190 Roots::<1>::new(RootType::Nan, 0.0),
191 );
192 let r = Roots::<3>::concat_1_2(a, b);
193 assert_eq!(r.root_type(0), RootType::Real);
194 assert_eq!(r.root_type(1), RootType::Real);
195 assert_eq!(r.root_type(2), RootType::Nan);
196 assert_eq!(r[0], 1.0);
197 assert_eq!(r[1], 2.0);
198 }
199
200 #[test]
201 fn uniform_3() {
202 let r = Roots::<3>::uniform(RootType::Complex, -5.0);
203 for i in 0..3 {
204 assert_eq!(r.root_type(i), RootType::Complex);
205 assert_eq!(r[i], -5.0);
206 }
207 }
208}