implicit_predicates/generated/
points.rs1use core::fmt;
9
10use implicit_predicates_core::{
11 ExactCoords, ExactError, Mark, Point, Scratch, ScratchExhausted, Span, Weight, eft, expansion,
12};
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub enum PointError {
17 NonFinite,
19 ParamOutOfRange,
21}
22
23impl fmt::Display for PointError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 f.write_str(match self {
26 PointError::NonFinite => "an input of the point is not finite",
27 PointError::ParamOutOfRange => "a parameter of the point is out of range",
28 })
29 }
30}
31
32impl core::error::Error for PointError {}
33
34#[derive(Clone, Copy, Debug, PartialEq)]
37#[repr(transparent)]
38pub struct Explicit([f64; 3]);
39
40impl Explicit {
41 #[inline]
47 pub fn new(p: [f64; 3]) -> Result<Self, PointError> {
48 if !(p.iter().all(|x| x.is_finite())) {
49 return Err(PointError::NonFinite);
50 }
51 Ok(Self::new_unchecked(p))
52 }
53
54 #[inline]
57 pub fn new_unchecked(p: [f64; 3]) -> Self {
58 Self(p)
59 }
60}
61
62impl Point for Explicit {
63 #[inline]
64 fn approx(&self) -> &[f64; 3] {
65 &self.0
66 }
67
68 #[inline]
69 fn err(&self) -> &[f64; 3] {
70 &[0.0; 3]
71 }
72
73 #[inline]
74 fn is_explicit(&self) -> bool {
75 true
76 }
77
78 #[inline]
79 fn exact(&self, scratch: &mut Scratch<'_>) -> Result<ExactCoords, ExactError> {
80 self.0.exact(scratch)
81 }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq)]
97pub struct Lnc {
98 p: [f64; 3],
99 q: [f64; 3],
100 t: f64,
101 approx: [f64; 3],
102 err: [f64; 3],
103}
104
105impl Lnc {
106 const ERR_SLACK: f64 = 1.0000000000000009;
110
111 pub fn new(p: [f64; 3], q: [f64; 3], t: f64) -> Result<Self, PointError> {
119 if !(p.iter().all(|x| x.is_finite()) && q.iter().all(|x| x.is_finite()) && t.is_finite()) {
120 return Err(PointError::NonFinite);
121 }
122 if t < 0.0 {
123 return Err(PointError::ParamOutOfRange);
124 }
125 if t > 1.0 {
126 return Err(PointError::ParamOutOfRange);
127 }
128 Ok(Self::new_unchecked(p, q, t))
129 }
130
131 pub fn new_unchecked(p: [f64; 3], q: [f64; 3], t: f64) -> Self {
136 let (approx, err) = Self::evaluate([p, q], [t]);
137 Self {
138 p,
139 q,
140 t,
141 approx,
142 err,
143 }
144 }
145
146 #[inline]
148 pub fn p(&self) -> &[f64; 3] {
149 &self.p
150 }
151
152 #[inline]
154 pub fn q(&self) -> &[f64; 3] {
155 &self.q
156 }
157
158 #[inline]
160 pub fn t(&self) -> f64 {
161 self.t
162 }
163
164 fn evaluate(c: [[f64; 3]; 2], s: [f64; 1]) -> ([f64; 3], [f64; 3]) {
168 let v0 = c[1][0];
169 let v1 = c[1][1];
170 let v2 = c[1][2];
171 let v3 = s[0];
172 let v4 = c[0][0];
173 let v5 = c[0][1];
174 let v6 = c[0][2];
175 let v7 = v4 - v0;
176 let e7 = sum_rounding(v4, v0, v7);
177 let v8 = v5 - v1;
178 let e8 = sum_rounding(v5, v1, v8);
179 let v9 = v6 - v2;
180 let e9 = sum_rounding(v6, v2, v9);
181 let v10 = v3 * v7;
182 let e10 = covered_product(v3.abs(), e7) + product_rounding(v3, v7, v10);
183 let v11 = v3 * v8;
184 let e11 = covered_product(v3.abs(), e8) + product_rounding(v3, v8, v11);
185 let v12 = v3 * v9;
186 let e12 = covered_product(v3.abs(), e9) + product_rounding(v3, v9, v12);
187 let v13 = v0 + v10;
188 let e13 = e10 + sum_rounding(v0, v10, v13);
189 let v14 = v1 + v11;
190 let e14 = e11 + sum_rounding(v1, v11, v14);
191 let v15 = v2 + v12;
192 let e15 = e12 + sum_rounding(v2, v12, v15);
193 let approx = [v13, v14, v15];
194 let err = [
195 finish(approx[0], e13, Self::ERR_SLACK),
196 finish(approx[1], e14, Self::ERR_SLACK),
197 finish(approx[2], e15, Self::ERR_SLACK),
198 ];
199 (approx, err)
200 }
201
202 fn write_exact(
208 scratch: &mut Scratch<'_>,
209 c: [[f64; 3]; 2],
210 s: [f64; 1],
211 ) -> Result<ExactCoords, ExactError> {
212 if !(c.iter().flatten().all(|x| x.is_finite()) && s.iter().all(|x| x.is_finite())) {
213 return Err(ExactError::OutOfRange);
214 }
215 let mark = scratch.mark();
216 let mut in_range = true;
217 let x = scratch.write(5, |out| {
218 let v0 = c[1][0];
219 let v3 = s[0];
220 let v4 = c[0][0];
221 if !(summable(&[v4]) && summable(&[v0])) {
222 in_range = false;
223 return 0;
224 }
225 let mut x7 = [0.0; 2];
226 let n7 = expansion::from_two_diff(v4, v0, &mut x7);
227 if !(multipliable(&x7[..n7]) && multipliable(&[v3])) {
228 in_range = false;
229 return 0;
230 }
231 let mut x10 = [0.0; 4];
232 let n10 = expansion::scale(&x7[..n7], v3, &mut x10);
233 if !(summable(&x10[..n10]) && summable(&[v0])) {
234 in_range = false;
235 return 0;
236 }
237 expansion::grow(&x10[..n10], v0, out)
238 });
239 let x = written(scratch, mark, x, in_range)?;
240 let y = scratch.write(5, |out| {
241 let v1 = c[1][1];
242 let v3 = s[0];
243 let v5 = c[0][1];
244 if !(summable(&[v5]) && summable(&[v1])) {
245 in_range = false;
246 return 0;
247 }
248 let mut x8 = [0.0; 2];
249 let n8 = expansion::from_two_diff(v5, v1, &mut x8);
250 if !(multipliable(&x8[..n8]) && multipliable(&[v3])) {
251 in_range = false;
252 return 0;
253 }
254 let mut x11 = [0.0; 4];
255 let n11 = expansion::scale(&x8[..n8], v3, &mut x11);
256 if !(summable(&x11[..n11]) && summable(&[v1])) {
257 in_range = false;
258 return 0;
259 }
260 expansion::grow(&x11[..n11], v1, out)
261 });
262 let y = written(scratch, mark, y, in_range)?;
263 let z = scratch.write(5, |out| {
264 let v2 = c[1][2];
265 let v3 = s[0];
266 let v6 = c[0][2];
267 if !(summable(&[v6]) && summable(&[v2])) {
268 in_range = false;
269 return 0;
270 }
271 let mut x9 = [0.0; 2];
272 let n9 = expansion::from_two_diff(v6, v2, &mut x9);
273 if !(multipliable(&x9[..n9]) && multipliable(&[v3])) {
274 in_range = false;
275 return 0;
276 }
277 let mut x12 = [0.0; 4];
278 let n12 = expansion::scale(&x9[..n9], v3, &mut x12);
279 if !(summable(&x12[..n12]) && summable(&[v2])) {
280 in_range = false;
281 return 0;
282 }
283 expansion::grow(&x12[..n12], v2, out)
284 });
285 let z = written(scratch, mark, z, in_range)?;
286 Ok(ExactCoords {
287 x,
288 y,
289 z,
290 w: Weight::One,
291 })
292 }
293}
294
295impl Point for Lnc {
296 #[inline]
297 fn approx(&self) -> &[f64; 3] {
298 &self.approx
299 }
300
301 #[inline]
302 fn err(&self) -> &[f64; 3] {
303 &self.err
304 }
305
306 #[inline]
307 fn is_explicit(&self) -> bool {
308 false
309 }
310
311 fn exact(&self, scratch: &mut Scratch<'_>) -> Result<ExactCoords, ExactError> {
312 Self::write_exact(scratch, [self.p, self.q], [self.t])
313 }
314}
315
316#[derive(Clone, Copy, Debug, PartialEq)]
318pub enum AnyPoint {
319 Explicit(Explicit),
321 Lnc(Lnc),
323}
324
325impl Point for AnyPoint {
326 #[inline]
327 fn approx(&self) -> &[f64; 3] {
328 match self {
329 AnyPoint::Explicit(p) => p.approx(),
330 AnyPoint::Lnc(p) => p.approx(),
331 }
332 }
333
334 #[inline]
335 fn err(&self) -> &[f64; 3] {
336 match self {
337 AnyPoint::Explicit(p) => p.err(),
338 AnyPoint::Lnc(p) => p.err(),
339 }
340 }
341
342 #[inline]
343 fn is_explicit(&self) -> bool {
344 match self {
345 AnyPoint::Explicit(p) => p.is_explicit(),
346 AnyPoint::Lnc(p) => p.is_explicit(),
347 }
348 }
349
350 #[inline]
351 fn exact(&self, scratch: &mut Scratch<'_>) -> Result<ExactCoords, ExactError> {
352 match self {
353 AnyPoint::Explicit(p) => p.exact(scratch),
354 AnyPoint::Lnc(p) => p.exact(scratch),
355 }
356 }
357}
358
359impl From<Explicit> for AnyPoint {
360 #[inline]
361 fn from(p: Explicit) -> Self {
362 AnyPoint::Explicit(p)
363 }
364}
365
366impl From<Lnc> for AnyPoint {
367 #[inline]
368 fn from(p: Lnc) -> Self {
369 AnyPoint::Lnc(p)
370 }
371}
372
373const UNIT: f64 = 1.1102230246251565e-16;
375
376const TINY: f64 = 5e-324;
378
379#[inline]
383fn covered_product(a: f64, b: f64) -> f64 {
384 if a == 0.0 || b == 0.0 {
385 0.0
386 } else {
387 a * b + TINY
388 }
389}
390
391#[inline]
395fn sum_rounding(x: f64, y: f64, s: f64) -> f64 {
396 if x != 0.0 && y != 0.0 {
397 covered_product(UNIT, s.abs())
398 } else {
399 0.0
400 }
401}
402
403#[inline]
408fn product_rounding(x: f64, y: f64, p: f64) -> f64 {
409 if x != 0.0 && y != 0.0 {
410 covered_product(UNIT, p.abs()) + TINY
411 } else {
412 0.0
413 }
414}
415
416#[inline]
421fn finish(approx: f64, err: f64, slack: f64) -> f64 {
422 let bound = err * slack;
423 if !(approx.is_finite() && bound.is_finite()) {
424 f64::INFINITY
425 } else if err == 0.0 {
426 0.0
427 } else {
428 bound.next_up()
429 }
430}
431
432const SUM_OPERAND_LIMIT: f64 = 1.1235582092889474e307;
435
436#[inline]
439fn summable(e: &[f64]) -> bool {
440 e.iter().all(|x| x.abs() < SUM_OPERAND_LIMIT)
441}
442
443#[inline]
447fn multipliable(e: &[f64]) -> bool {
448 e.iter().all(|&x| eft::in_product_domain(x))
449}
450
451#[inline]
455fn written(
456 scratch: &mut Scratch<'_>,
457 mark: Mark,
458 span: Result<Span, ScratchExhausted>,
459 in_range: bool,
460) -> Result<Span, ExactError> {
461 match span {
462 Ok(span) if in_range => Ok(span),
463 Ok(_) => {
464 scratch.reset(mark);
465 Err(ExactError::OutOfRange)
466 }
467 Err(e) => {
468 scratch.reset(mark);
469 Err(e.into())
470 }
471 }
472}