intervals_good/
lib.rs

1use rug::{
2    float::Constant, float::Round, ops::AssignRound, ops::DivAssignRound, ops::PowAssignRound,
3    float::OrdFloat, Float
4};
5
6const F64_PREC: u32 = 53;
7
8enum IntervalClassification {
9    StrictlyPos,
10    StrictlyNeg,
11    Mixed,
12}
13
14/// The `lo` field represents whether the computation must error.
15/// The `hi` field represents whether the computation may error.
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct ErrorInterval {
18    pub lo: bool,
19    // the
20    pub hi: bool,
21}
22
23impl ErrorInterval {
24    pub fn union(&self, other: &ErrorInterval) -> ErrorInterval {
25        ErrorInterval {
26            lo: self.lo || other.lo,
27            hi: self.hi || other.hi,
28        }
29    }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct BooleanInterval {
34    pub lo: bool,
35    pub hi: bool,
36    pub err: ErrorInterval,
37}
38
39impl BooleanInterval {
40    pub fn and(&self, other: &BooleanInterval) -> BooleanInterval {
41        BooleanInterval {
42            lo: self.lo && other.lo,
43            hi: self.hi && other.hi,
44            err: self.err.union(&other.err),
45        }
46    }
47
48    pub fn or(&self, other: &BooleanInterval) -> BooleanInterval {
49        BooleanInterval {
50            lo: self.lo || other.lo,
51            hi: self.hi || other.hi,
52            err: self.err.union(&other.err),
53        }
54    }
55
56    pub fn not(&self) -> BooleanInterval {
57        BooleanInterval {
58            lo: !self.hi,
59            hi: !self.lo,
60            err: self.err.clone(),
61        }
62    }
63
64    pub fn if_real_result(&self, other: &Interval, third: &Interval) -> Interval {
65        if self.lo {
66            other.with_error(self.err.union(&other.err))
67        } else if !self.hi {
68            third.with_error(self.err.union(&third.err))
69        } else {
70            other.union(third)
71        }
72    }
73
74    pub fn union(&self, other: &BooleanInterval) -> BooleanInterval {
75        BooleanInterval {
76            lo: self.lo || other.lo,
77            hi: self.hi || other.hi,
78            err: self.err.union(&other.err),
79        }
80    }
81
82    fn with_error(&self, err: ErrorInterval) -> BooleanInterval {
83        BooleanInterval {
84            lo: self.lo,
85            hi: self.hi,
86            err,
87        }
88    }
89
90    pub fn if_boolean_result(
91        &self,
92        other: &BooleanInterval,
93        third: &BooleanInterval,
94    ) -> BooleanInterval {
95        if self.lo {
96            other.with_error(self.err.union(&other.err))
97        } else if !self.hi {
98            third.with_error(self.err.union(&third.err))
99        } else {
100            other.union(third)
101        }
102    }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
106pub struct Interval {
107    pub lo: OrdFloat,
108    pub hi: OrdFloat,
109    pub err: ErrorInterval,
110}
111
112pub(crate) fn is_even(val: &Float) -> bool {
113    if let Some(int) = val.to_integer() {
114        int.is_even()
115    } else {
116        false
117    }
118}
119
120pub(crate) fn is_odd(val: &Float) -> bool {
121    if let Some(int) = val.to_integer() {
122        int.is_odd()
123    } else {
124        false
125    }
126}
127
128pub(crate) fn bf(prec: u32, val: f64) -> Float {
129    Float::with_val(prec, val)
130}
131
132pub(crate) fn add_round(a: &Float, b: &Float, round: Round) -> Float {
133    let mut tmp = a.clone();
134    tmp.mul_add_round(&bf(a.prec(), 1.0), b, round);
135    tmp
136}
137
138pub(crate) fn sub_round(a: &Float, b: &Float, round: Round) -> Float {
139    let mut tmp = a.clone();
140    tmp.mul_add_round(&bf(a.prec(), 1.0), b, round);
141    tmp
142}
143
144pub(crate) fn div_round(a: &Float, b: &Float, round: Round) -> Float {
145    let mut tmp = a.clone();
146    tmp.div_assign_round(b, round);
147    tmp
148}
149
150pub(crate) fn mul_round(a: &Float, b: &Float, round: Round) -> Float {
151    let mut tmp = a.clone();
152    tmp.mul_add_round(b, &bf(a.prec(), 0.0), round);
153    tmp
154}
155
156impl Interval {
157    fn lo(&self) -> Float {
158        self.lo.clone().into()
159    }
160
161    fn hi(&self) -> Float {
162        self.hi.clone().into()
163    }
164
165    pub fn new(prec: u32, lo: f64, hi: f64) -> Interval {
166        Interval {
167            lo: OrdFloat::from(bf(prec, lo)),
168            hi: OrdFloat::from(bf(prec, hi)),
169            err: ErrorInterval {
170                lo: false,
171                hi: false,
172            },
173        }
174    }
175
176    pub fn make(lo: Float, hi: Float, err: ErrorInterval) -> Interval {
177        Interval {
178            lo: OrdFloat::from(lo),
179            hi: OrdFloat::from(hi),
180            err,
181        }
182    }
183
184    fn classify_with(&self, val: &Float) -> IntervalClassification {
185        if &self.lo() > val {
186            IntervalClassification::StrictlyPos
187        } else if &self.hi() < val {
188            IntervalClassification::StrictlyNeg
189        } else {
190            IntervalClassification::Mixed
191        }
192    }
193
194    fn classify(&self) -> IntervalClassification {
195        self.classify_with(&bf(F64_PREC, 0.0))
196    }
197
198    pub fn union(&self, other: &Interval) -> Interval {
199        Interval::make(self.lo().min(&other.lo()), self.hi().max(&other.hi()), self.err.union(&other.err))
200    }
201
202    pub fn neg(&self) -> Interval {
203        Interval::make(-self.hi(), -self.lo(), self.err.clone())
204    }
205
206    pub fn add(&self, other: &Interval) -> Interval {
207        let mut lo = self.lo();
208        lo.mul_add_round(&bf(other.lo().prec(), 1.0), &other.lo(), Round::Down);
209        let mut hi = self.hi();
210        hi.mul_add_round(&bf(other.lo().prec(), 1.0), &other.hi(), Round::Up);
211        Interval::make(lo, hi, self.err.union(&other.err))
212    }
213
214    pub fn sub(&self, other: &Interval) -> Interval {
215        let mut lo = self.lo();
216        lo.mul_sub_round(&bf(other.lo().prec(), 1.0), &other.hi(), Round::Down);
217        let mut hi = self.hi();
218        hi.mul_sub_round(&bf(other.lo().prec(), 1.0), &other.lo(), Round::Up);
219        Interval::make(lo, hi, self.err.union(&other.err))
220    }
221
222    pub fn mul(&self, other: &Interval) -> Interval {
223        let perform_mult = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
224            let mut lo = lo1.clone();
225            lo.mul_add_round(lo2, &bf(lo1.prec(), 0.0), Round::Down);
226            let mut hi = hi1.clone();
227            hi.mul_add_round(&hi2, &bf(hi1.prec(), 0.0), Round::Up);
228            Interval::make(lo, hi, self.err.union(&other.err))
229        };
230
231        use IntervalClassification::*;
232        match (self.classify(), other.classify()) {
233            (StrictlyPos, StrictlyPos) => perform_mult(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
234
235            (StrictlyPos, StrictlyNeg) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
236
237            (StrictlyPos, Mixed) => perform_mult(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
238
239            (StrictlyNeg, Mixed) => perform_mult(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
240
241            (StrictlyNeg, StrictlyPos) => perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
242
243            (StrictlyNeg, StrictlyNeg) => perform_mult(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
244
245            (Mixed, StrictlyPos) => perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.hi()),
246
247            (Mixed, StrictlyNeg) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.lo()),
248
249            (Mixed, Mixed) => perform_mult(&self.hi(), &other.lo(), &self.lo(), &other.lo())
250                .union(&perform_mult(&self.lo(), &other.hi(), &self.hi(), &other.hi())),
251        }
252    }
253
254    pub fn get_const(&self) -> Option<Float> {
255        if self.lo() == self.hi() {
256            Some(self.lo())
257        } else {
258            None
259        }
260    }
261
262    pub fn div(&self, other: &Interval) -> Interval {
263        let zero = bf(other.lo().prec(), 0.0);
264        let error = ErrorInterval {
265            lo: self.err.lo || other.err.lo || other.get_const() == Some(zero.clone()),
266            hi: self.err.hi || other.err.hi || (other.lo() <= zero && other.hi() >= zero),
267        };
268
269        let perform_div = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
270            let mut lo = lo1.clone();
271            lo.div_assign_round(lo2, Round::Down);
272            let mut hi = hi1.clone();
273            hi.div_assign_round(hi2, Round::Up);
274
275            Interval::make(lo, hi, self.err.union(&other.err))
276        };
277
278        use IntervalClassification::*;
279        match (self.classify(), other.classify()) {
280            (_any, Mixed) => 
281            Interval::make(bf(self.lo().prec(), std::f64::NEG_INFINITY), bf(self.lo().prec(), std::f64::INFINITY), error),
282            (StrictlyPos, StrictlyPos) => perform_div(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
283            (StrictlyPos, StrictlyNeg) => perform_div(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
284            (StrictlyNeg, StrictlyPos) => perform_div(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
285            (StrictlyNeg, StrictlyNeg) => perform_div(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
286            (Mixed, StrictlyPos) => perform_div(&self.lo(), &other.lo(), &self.hi(), &other.lo()),
287            (Mixed, StrictlyNeg) => perform_div(&self.hi(), &other.hi(), &self.lo(), &other.hi()),
288        }
289    }
290
291    fn monotonic_mut(&self, fun: fn(&mut Float, Round) -> std::cmp::Ordering) -> Interval {
292        let mut tmplo = self.lo();
293        let mut tmphi = self.hi();
294        fun(&mut tmplo, Round::Down);
295        fun(&mut tmphi, Round::Up);
296        if tmplo.is_nan() {
297            panic!("monotonic_mut: lo is NaN");
298        }
299        if tmphi.is_nan() {
300            panic!("monotonic_mut: hi is NaN");
301        }
302        Interval::make(tmplo, tmphi, self.err.clone())
303    }
304
305    fn comonotonic_mut(&self, fun: fn(&mut Float, Round) -> std::cmp::Ordering) -> Interval {
306        let mut tmplo = self.hi();
307        let mut tmphi = self.lo();
308        fun(&mut tmplo, Round::Down);
309        fun(&mut tmphi, Round::Up);
310        if tmplo.is_nan() {
311            panic!("comonotonic_mut: lo is NaN");
312        }
313        if tmphi.is_nan() {
314            panic!("comonotonic_mut: hi is NaN");
315        }
316        Interval::make(tmplo, tmphi, self.err.clone())
317    }
318
319    fn clamp(&self, lo: &Float, hi: &Float) -> Interval {
320        Interval::make(self.lo().max(lo).min(hi), self.hi().min(hi).max(lo), ErrorInterval {
321            lo: self.err.lo || &self.hi() < lo || &self.lo() > hi,
322            hi: self.err.hi || &self.lo() < lo || &self.hi() > hi,
323        })
324    }
325
326    pub fn round(&self) -> Interval {
327        Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
328    }
329
330    pub fn ceil(&self) -> Interval {
331        Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
332    }
333
334    pub fn floor(&self) -> Interval {
335        Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
336    }
337
338    pub fn trunc(&self) -> Interval {
339        Interval::make(self.lo().floor(), self.hi().ceil(), self.err.clone())
340    }
341
342    pub fn fabs(&self) -> Interval {
343        let zero = bf(self.lo().prec(), 0.0);
344        if self.lo() >= zero {
345            self.clone()
346        } else if self.hi() <= zero {
347            self.neg()
348        } else {
349            Interval::make(zero, self.hi().max(&-self.lo()), self.err.clone())
350        }
351    }
352
353    pub fn exp(&self) -> Interval {
354        self.monotonic_mut(Float::exp_round)
355    }
356
357    pub fn exp_m1(&self) -> Interval {
358        self.monotonic_mut(Float::exp_m1_round)
359    }
360
361    pub fn exp2(&self) -> Interval {
362        self.monotonic_mut(Float::exp2_round)
363    }
364
365    pub fn ln(&self) -> Interval {
366        self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
367            .monotonic_mut(Float::ln_round)
368    }
369
370    pub fn log10(&self) -> Interval {
371        self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
372            .monotonic_mut(Float::log10_round)
373    }
374
375    pub fn log2(&self) -> Interval {
376        self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
377            .monotonic_mut(Float::log2_round)
378    }
379
380    pub fn ln_1p(&self) -> Interval {
381        self.clamp(
382            &bf(self.lo().prec(), -1.0),
383            &bf(self.lo().prec(), f64::INFINITY),
384        )
385        .monotonic_mut(Float::ln_1p_round)
386    }
387
388    pub fn sqrt(&self) -> Interval {
389        self.clamp(&bf(self.lo().prec(), 0.0), &bf(self.lo().prec(), f64::INFINITY))
390            .monotonic_mut(Float::sqrt_round)
391    }
392
393    pub fn cbrt(&self) -> Interval {
394        self.monotonic_mut(Float::cbrt_round)
395    }
396
397    pub fn hypot(&self, other: &Interval) -> Interval {
398        let self_pos = self.fabs();
399        let other_pos = other.fabs();
400        let mut tmp_lo = self_pos.lo();
401        tmp_lo.hypot_round(&other_pos.lo(), Round::Down);
402        let mut tmp_hi = self_pos.hi();
403        tmp_hi.hypot_round(&other_pos.hi(), Round::Up);
404        Interval::make(tmp_lo, tmp_hi, self.err.union(&other.err))
405    }
406
407    // assumes self is positive or zero
408    fn pow_pos(&self, other: &Interval) -> Interval {
409        let perform_pow = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
410            let mut tmp_lo = lo1.clone();
411            tmp_lo.pow_assign_round(lo2, Round::Down);
412            let mut tmp_hi = hi1.clone();
413            tmp_hi.pow_assign_round(hi2, Round::Up);
414            Interval::make(tmp_lo, tmp_hi, self.err.union(&other.err))
415        };
416
417        // copied from mult (just replaced name with perform_pow)
418        use IntervalClassification::*;
419        match (
420            self.classify_with(&bf(other.lo().prec(), 1.0)),
421            other.classify(),
422        ) {
423            (StrictlyPos, StrictlyPos) => perform_pow(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
424
425            (StrictlyPos, StrictlyNeg) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
426
427            (StrictlyPos, Mixed) => perform_pow(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
428
429            (StrictlyNeg, Mixed) => perform_pow(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
430
431            (StrictlyNeg, StrictlyPos) => perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
432
433            (StrictlyNeg, StrictlyNeg) => perform_pow(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
434
435            (Mixed, StrictlyPos) => perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.hi()),
436
437            (Mixed, StrictlyNeg) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.lo()),
438
439            (Mixed, Mixed) => perform_pow(&self.hi(), &other.lo(), &self.lo(), &other.lo())
440                .union(&perform_pow(&self.lo(), &other.hi(), &self.hi(), &other.hi())),
441        }
442    }
443
444    // assumes x negative
445    fn pow_neg(&self, other: &Interval) -> Interval {
446        let pow_ceil = other.lo().ceil();
447        let pow_floor = other.hi().floor();
448        let zero: Float = bf(self.lo().prec(), 0.0);
449
450        let error = ErrorInterval {
451            lo: self.err.lo || other.err.lo,
452            hi: self.err.hi || other.err.hi || other.lo() < other.hi(),
453        };
454        if pow_floor < pow_ceil {
455            if self.hi() == zero {
456                Interval::make(zero.clone(), zero,
457                          ErrorInterval {
458                            lo: self.err.lo,
459                            hi: true
460                          })
461            } else {
462                Interval::make(bf(self.lo().prec(), f64::NAN), bf(self.lo().prec(), f64::NAN), ErrorInterval { lo: true, hi: true })
463            }
464        } else if pow_ceil == pow_floor {
465            let pos = self.fabs().pow_pos(&Interval::make(pow_ceil.clone(), pow_ceil.clone(), error));
466            if pow_ceil.to_integer().unwrap().is_odd() {
467                pos.neg()
468            } else {
469                pos
470            }
471        } else {
472            let odds = Interval::make(
473                if pow_ceil.clone().to_integer().unwrap().is_odd() {
474                    pow_ceil.clone()
475                } else {
476                    pow_ceil.clone() + (1.0)
477                },
478                if pow_floor.to_integer().unwrap().is_odd() {
479                    pow_floor.clone()
480                } else {
481                    pow_floor.clone() - (1.0)
482                },
483                error.clone(),
484            );
485            let evens = Interval::make(
486                if pow_ceil.clone().to_integer().unwrap().is_odd() {
487                    pow_ceil + (1.0)
488                } else {
489                    pow_ceil
490                },
491                if pow_floor.to_integer().unwrap().is_odd() {
492                    pow_floor - (1.0)
493                } else {
494                    pow_floor
495                },
496                error,
497            );
498            self.fabs()
499                .pow_pos(&evens)
500                .union(&self.fabs().pow_pos(&odds).neg())
501        }
502    }
503
504    pub fn contains(&self, value: &Float) -> bool {
505        &self.lo() <= value && value <= &self.hi()
506    }
507
508    pub fn split(&self, along: &Float) -> Option<(Interval, Interval)> {
509        if self.contains(along) {
510            Some((
511                Interval::make(
512                    self.lo(),
513                    along.clone(),
514                    self.err.clone(),
515                ),
516                Interval::make (
517                    along.clone(),
518                    self.hi(),
519                    self.err.clone(),
520                ),
521            ))
522        } else {
523            None
524        }
525    }
526
527    pub fn pow(&self, other: &Interval) -> Interval {
528        if self.hi() < bf(self.lo().prec(), 0.0) {
529            self.pow_neg(&other)
530        } else if self.lo() >= bf(self.lo().prec(), 0.0) {
531            self.pow_pos(&other)
532        } else {
533            let (neg, pos) = self.split(&bf(self.lo().prec(), 0.0)).unwrap();
534            neg.pow_neg(other).union(&pos.pow_pos(&other))
535        }
536    }
537
538    pub fn fma(&self, other: &Interval, third: &Interval) -> Interval {
539        self.mul(other).add(third)
540    }
541
542    fn period_lower(&self, is_even: bool) -> Float {
543        let mut lopi = Float::new(self.lo().prec());
544        lopi.assign_round(Constant::Pi, Round::Down);
545        let mut hipi = Float::new(self.lo().prec());
546        hipi.assign_round(Constant::Pi, Round::Up);
547        let zero = bf(self.lo().prec(), 0.0);
548
549        let mut afactor = self.lo();
550        afactor.div_assign_round(if self.lo() < zero { lopi } else { hipi }, Round::Down);
551        if is_even {
552            afactor.mul_sub_round(
553                &bf(self.lo().prec(), 1 as f64),
554                &bf(self.lo().prec(), 0.5 as f64),
555                Round::Down,
556            );
557        }
558        afactor = afactor.floor();
559
560        afactor
561    }
562
563    fn period_higher(&self, is_even: bool) -> Float {
564        let mut lopi = Float::new(self.lo().prec());
565        lopi.assign_round(Constant::Pi, Round::Down);
566        let mut hipi = Float::new(self.lo().prec());
567        hipi.assign_round(Constant::Pi, Round::Up);
568        let zero = bf(self.lo().prec(), 0.0);
569
570        let mut bfactor = self.hi();
571        bfactor.div_assign_round(if self.hi() < zero { hipi } else { lopi }, Round::Up);
572        if is_even {
573            bfactor.mul_sub_round(
574                &bf(self.hi().prec(), 1 as f64),
575                &bf(self.hi().prec(), 0.5 as f64),
576                Round::Up,
577            );
578        }
579        bfactor = bfactor.ceil();
580        bfactor
581    }
582
583    pub fn cos(&self) -> Interval {
584        let mut lopi = Float::new(self.lo().prec());
585        lopi.assign_round(Constant::Pi, Round::Down);
586        let mut hipi = Float::new(self.lo().prec());
587        hipi.assign_round(Constant::Pi, Round::Up);
588
589        let afactor = self.period_lower(false);
590        let bfactor = self.period_higher(false);
591
592        if afactor == bfactor && is_even(&afactor) {
593            let mut hitmp = self.hi();
594            let mut lotmp = self.lo();
595            hitmp.cos_round(Round::Down);
596            lotmp.cos_round(Round::Up);
597            Interval::make(
598                hitmp,
599                lotmp,
600                 self.err.clone())
601        } else if afactor == bfactor && is_odd(&afactor) {
602            let mut hitmp = self.hi();
603            let mut lotmp = self.lo();
604            hitmp.cos_round(Round::Up);
605            lotmp.cos_round(Round::Down);
606            Interval::make(
607                lotmp,
608                hitmp,
609                 self.err.clone())
610        } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_even(&afactor) {
611            let mut lotmp = self.lo();
612            lotmp.cos_round(Round::Up);
613            let mut hitmp = self.hi();
614            hitmp.cos_round(Round::Up);
615            Interval::make (
616                bf(self.lo().prec(), -1.0),
617                lotmp.max(&hitmp),
618                self.err.clone()
619            )
620        } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_odd(&afactor) {
621            let mut lotmp = self.lo();
622            lotmp.cos_round(Round::Down);
623            let mut hitmp = self.hi();
624            hitmp.cos_round(Round::Down);
625            Interval::make(
626                lotmp.min(&hitmp),
627                bf(self.lo().prec(), 1.0),
628                 self.err.clone())
629        } else {
630            return Interval::make(
631                bf(self.lo().prec(), -1.0),
632                bf(self.lo().prec(), 1.0),
633                 self.err.clone());
634        }
635    }
636
637    pub fn sin(&self) -> Interval {
638        let mut lopi = Float::new(self.lo().prec());
639        lopi.assign_round(Constant::Pi, Round::Down);
640        let mut hipi = Float::new(self.lo().prec());
641        hipi.assign_round(Constant::Pi, Round::Up);
642
643        let afactor = self.period_lower(true);
644        let bfactor = self.period_higher(true);
645
646        if afactor == bfactor && is_even(&afactor) {
647            let mut hitmp = self.hi();
648            let mut lotmp = self.lo();
649            hitmp.sin_round(Round::Down);
650            lotmp.sin_round(Round::Up);
651            Interval::make(
652                hitmp,
653                lotmp,
654                 self.err.clone())
655        } else if afactor == bfactor && is_odd(&afactor) {
656            let mut hitmp = self.hi();
657            let mut lotmp = self.lo();
658            hitmp.sin_round(Round::Up);
659            lotmp.sin_round(Round::Down);
660            Interval::make(
661                lotmp,
662                hitmp,
663                 self.err.clone())
664        } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_even(&afactor) {
665            let mut lotmp = self.lo();
666            lotmp.sin_round(Round::Up);
667            let mut hitmp = self.hi();
668            hitmp.sin_round(Round::Up);
669            Interval::make(
670                bf(self.lo().prec(), -1.0),
671                lotmp.max(&hitmp),
672                 self.err.clone())
673        } else if (bfactor.clone() - afactor.clone()) == (1.0) && is_odd(&afactor) {
674            let mut lotmp = self.lo();
675            lotmp.sin_round(Round::Down);
676            let mut hitmp = self.hi();
677            hitmp.sin_round(Round::Down);
678            Interval::make(
679                lotmp.min(&hitmp),
680                bf(self.lo().prec(), 1.0),
681                 self.err.clone())
682        } else {
683            return Interval::make(
684                bf(self.lo().prec(), -1.0),
685                bf(self.lo().prec(), 1.0),
686                 self.err.clone());
687        }
688    }
689
690    pub fn tan(&self) -> Interval {
691        let mut lopi = Float::new(self.lo().prec());
692        lopi.assign_round(Constant::Pi, Round::Down);
693        let mut hipi = Float::new(self.lo().prec());
694        hipi.assign_round(Constant::Pi, Round::Up);
695
696        let afactor = self.period_lower(true);
697        let bfactor = self.period_higher(true);
698
699        if afactor == bfactor {
700            let mut hitmp = self.hi();
701            let mut lotmp = self.lo();
702            lotmp.tan_round(Round::Down);
703            hitmp.tan_round(Round::Up);
704            Interval::make(
705                lotmp,
706                hitmp,
707                 self.err.clone())
708        } else {
709            return Interval::make(
710                bf(self.lo().prec(), f64::NEG_INFINITY),
711                bf(self.lo().prec(), f64::INFINITY),
712                 self.err.clone());
713        }
714    }
715
716    pub fn atan2(&self, other: &Interval) -> Interval {
717        let mkatan = |lo1: &Float, lo2: &Float, hi1: &Float, hi2: &Float| {
718            let mut lotmp = lo1.clone();
719            let mut hitmp = hi1.clone();
720            lotmp.atan2_round(lo2, Round::Down);
721            hitmp.atan2_round(hi2, Round::Up);
722            Interval::make(
723                lotmp,
724                hitmp,
725                 self.err.clone())
726        };
727
728        use IntervalClassification::*;
729        match (other.classify(), self.classify()) {
730            (StrictlyNeg, StrictlyNeg) => mkatan(&self.hi(), &other.lo(), &self.lo(), &other.hi()),
731            (Mixed, StrictlyNeg) => mkatan(&self.hi(), &other.lo(), &self.hi(), &other.hi()),
732            (StrictlyPos, StrictlyNeg) => mkatan(&self.lo(), &other.lo(), &self.hi(), &other.hi()),
733            (StrictlyPos, Mixed) => mkatan(&self.lo(), &other.lo(), &self.hi(), &other.lo()),
734            (StrictlyPos, StrictlyPos) => mkatan(&self.lo(), &other.hi(), &self.hi(), &other.lo()),
735            (Mixed, StrictlyPos) => mkatan(&self.lo(), &other.hi(), &self.lo(), &other.lo()),
736            (StrictlyNeg, StrictlyPos) => mkatan(&self.hi(), &other.hi(), &self.lo(), &other.lo()),
737            (_, Mixed) => {
738                let mut hipi = Float::new(self.lo().prec());
739                hipi.assign_round(Constant::Pi, Round::Up);
740                let zero = bf(self.lo().prec(), 0.0);
741
742                Interval::make(
743                    -hipi.clone(),
744                    hipi,
745                    ErrorInterval {
746                        lo: self.err.lo
747                            || other.err.lo
748                            || other.err.lo
749                            || (self.lo() == 0 && self.hi() == 0 && other.lo() == 0 && other.hi() == 0),
750                        hi: self.err.lo || self.hi() >= zero,
751                    }
752                )
753            }
754        }
755    }
756
757    pub fn cosh(&self) -> Interval {
758        self.fabs().monotonic_mut(Float::cosh_round)
759    }
760
761    pub fn sinh(&self) -> Interval {
762        self.monotonic_mut(Float::sinh_round)
763    }
764
765    pub fn tanh(&self) -> Interval {
766        self.monotonic_mut(Float::tanh_round)
767    }
768
769    pub fn asinh(&self) -> Interval {
770        self.monotonic_mut(Float::asinh_round)
771    }
772
773    pub fn acosh(&self) -> Interval {
774        self.clamp(&bf(self.lo().prec(), 1.0), &bf(self.lo().prec(), f64::INFINITY))
775            .monotonic_mut(Float::acosh_round)
776    }
777
778    pub fn atanh(&self) -> Interval {
779        self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
780            .monotonic_mut(Float::atanh_round)
781    }
782
783    pub fn asin(&self) -> Interval {
784        self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
785            .monotonic_mut(Float::asin_round)
786    }
787
788    pub fn acos(&self) -> Interval {
789        self.clamp(&bf(self.lo().prec(), -1.0), &bf(self.lo().prec(), 1.0))
790            .comonotonic_mut(Float::acos_round)
791    }
792
793    pub fn atan(&self) -> Interval {
794        self.monotonic_mut(Float::atan_round)
795    }
796
797    // both self and other are positive
798    pub fn fmod_pos(&self, other: &Interval) -> Interval {
799        let a = div_round(&self.lo(), &other.hi(), Round::Down).floor();
800        let b = div_round(&self.hi(), &other.hi(), Round::Up).ceil();
801
802        // no intersection along y.hi edge
803        if a == b {
804            let mut c = self.hi();
805            c.div_assign_round(other.hi(), Round::Down);
806            let mut d = self.hi();
807            d.div_assign_round(other.lo(), Round::Up);
808
809            // no intersection along x.hi either; use top-left/bottom-right point
810            if c == d {
811                let mut tmplo = c.clone();
812                tmplo.mul_sub_round(&other.hi(), &self.lo(), Round::Up);
813                tmplo = -tmplo;
814                let mut tmphi = c;
815                tmphi.mul_sub_round(&other.lo(), &self.hi(), Round::Down);
816                tmphi = -tmphi;
817
818                Interval::make(
819                    tmplo,
820                    tmphi,
821                     self.err.clone())
822            } else {
823                let mut cplusone = c.clone();
824                cplusone.mul_add_round(
825                    &bf(self.lo().prec(), 1.0),
826                    &bf(self.lo().prec(), 1.0),
827                    Round::Down,
828                );
829                let mut tmphi = self.hi();
830                tmphi.div_assign_round(cplusone, Round::Up);
831                Interval::make(
832                    bf(self.lo().prec(), 0.0),
833                    tmphi,
834                     self.err.clone())
835            }
836        } else {
837            return Interval::make(
838                bf(self.lo().prec(), 0 as f64),
839                other.hi(),
840                 self.err.clone());
841        }
842    }
843
844    fn with_error(&self, err: ErrorInterval) -> Interval {
845        Interval::make(
846            self.lo(),
847            self.hi(),
848            err,
849        )
850    }
851
852    pub fn fmod(&self, other: &Interval) -> Interval {
853        let zero = bf(self.lo().prec(), 0.0);
854        let error = ErrorInterval {
855            lo: self.err.lo || other.err.lo || (self.lo() == zero && self.hi() == zero),
856            hi: self.err.lo || other.err.lo || (self.lo() <= zero && self.hi() >= zero),
857        };
858
859        let abs_other = other.fabs();
860
861        if self.hi() <= zero {
862            self.neg().fmod_pos(&abs_other).neg().with_error(error)
863        } else if self.lo() >= zero {
864            self.fmod_pos(&abs_other).with_error(error)
865        } else {
866            let (neg, pos) = self.split(&zero).unwrap();
867            pos.fmod_pos(&abs_other)
868                .union(&neg.neg().fmod_pos(&abs_other).neg())
869                .with_error(error)
870        }
871    }
872
873    // mostly copied from fmod_pos
874    pub fn remainder_pos(&self, other: &Interval) -> Interval {
875        let a = div_round(&self.lo(), &other.hi(), Round::Down).floor();
876        let b = div_round(&self.hi(), &other.hi(), Round::Up).ceil();
877
878        // no intersection along y.hi edge
879        if a == b {
880            let mut c = self.hi();
881            c.div_assign_round(other.hi(), Round::Down);
882            let mut d = self.hi();
883            d.div_assign_round(other.lo(), Round::Up);
884
885            // no intersection along x.hi either; use top-left/bottom-right point
886            if c == d {
887                let halfway = div_round(&other.hi(), &bf(self.lo().prec(), 2.0), Round::Down);
888
889                let mut tmplo = c.clone();
890                tmplo.mul_sub_round(&other.hi(), &self.lo(), Round::Up);
891                tmplo = -tmplo;
892                // DIFFERENCE FROM fmod_pos
893                tmplo = tmplo.max(&-halfway.clone());
894
895                let mut tmphi = c;
896                tmphi.mul_sub_round(&other.lo(), &self.hi(), Round::Down);
897                tmphi = -tmphi;
898                // DIFFERENCE FROM fmod_pos
899                tmphi = tmphi.min(&halfway);
900
901                Interval::make(
902                    tmplo,
903                    tmphi,
904                     self.err.clone())
905            } else {
906                // DIFFERENCE FROM fmod_pos
907                // NOPE! need to subtract half.bf one way, add it another!
908                let y_hi = div_round(
909                    &div_round(
910                        &self.hi(),
911                        &add_round(&c, &bf(self.lo().prec(), 0.5), Round::Down),
912                        Round::Down,
913                    ),
914                    &bf(self.lo().prec(), 2.0),
915                    Round::Down,
916                );
917                let y_lo = sub_round(
918                    &self.lo(),
919                    &mul_round(&c, &other.hi(), Round::Down),
920                    Round::Down,
921                )
922                .max(&-div_round(
923                    &other.hi(),
924                    &bf(self.lo().prec(), 2.0),
925                    Round::Down,
926                ));
927
928                Interval::make(
929                    y_lo.min(&-y_hi.clone()),
930                    y_hi,
931                     self.err.clone())
932            }
933        } else {
934            let y = div_round(&other.hi(), &bf(self.lo().prec(), 2.0), Round::Up);
935            Interval::make(
936                // DIFFERENCE FROM fmod_pos
937                -y.clone(),
938                y,
939                 self.err.clone())
940        }
941    }
942
943    pub fn remainder(&self, other: &Interval) -> Interval {
944        let zero = bf(self.lo().prec(), 0.0);
945        let error = ErrorInterval {
946            lo: self.err.lo || other.err.lo || (self.lo() == zero && self.hi() == zero),
947            hi: self.err.lo || other.err.lo || (self.lo() <= zero && self.hi() >= zero),
948        };
949
950        let abs_other = other.fabs();
951
952        if self.hi() <= zero {
953            self.neg().remainder_pos(&abs_other).neg().with_error(error)
954        } else if self.lo() >= zero {
955            self.remainder_pos(&abs_other).with_error(error)
956        } else {
957            let (neg, pos) = self.split(&zero).unwrap();
958            pos.remainder_pos(&abs_other)
959                .union(&neg.neg().remainder_pos(&abs_other).neg())
960                .with_error(error)
961        }
962    }
963
964    pub fn erf(&self) -> Interval {
965        self.monotonic_mut(Float::erf_round)
966    }
967
968    pub fn erfc(&self) -> Interval {
969        self.comonotonic_mut(Float::erfc_round)
970    }
971
972    pub fn cmp(&self, other: &Interval) -> (bool, bool, bool, bool) {
973        (
974            self.lo() < other.hi(),
975            self.hi() < other.lo(),
976            self.hi() > other.lo(),
977            self.lo() > other.hi(),
978        )
979    }
980
981    pub fn less_than(&self, other: &Interval) -> BooleanInterval {
982        let (can_less, must_less, _can_greater, _must_greater) = self.cmp(other);
983        BooleanInterval {
984            lo: must_less,
985            hi: can_less,
986            err: self.err.union(&other.err),
987        }
988    }
989
990    pub fn less_than_or_equal(&self, other: &Interval) -> BooleanInterval {
991        let (_can_less, _must_less, can_greater, must_greater) = self.cmp(other);
992        BooleanInterval {
993            lo: !can_greater,
994            hi: !must_greater,
995            err: self.err.union(&other.err),
996        }
997    }
998
999    pub fn greater_than(&self, other: &Interval) -> BooleanInterval {
1000        let (_can_less, _must_less, can_greater, must_greater) = self.cmp(other);
1001        BooleanInterval {
1002            lo: must_greater,
1003            hi: can_greater,
1004            err: self.err.union(&other.err),
1005        }
1006    }
1007
1008    pub fn greater_than_or_equal(&self, other: &Interval) -> BooleanInterval {
1009        let (can_less, must_less, _can_greater, _must_greater) = self.cmp(other);
1010        BooleanInterval {
1011            lo: !can_less,
1012            hi: !must_less,
1013            err: self.err.union(&other.err),
1014        }
1015    }
1016
1017    pub fn equal_to(&self, other: &Interval) -> BooleanInterval {
1018        let (can_less, must_less, can_greater, must_greater) = self.cmp(other);
1019        BooleanInterval {
1020            lo: !can_less && !can_greater,
1021            hi: !must_less && !must_greater,
1022            err: self.err.union(&other.err),
1023        }
1024    }
1025
1026    pub fn not_equal_to(&self, other: &Interval) -> BooleanInterval {
1027        let (can_less, must_less, can_greater, must_greater) = self.cmp(other);
1028        BooleanInterval {
1029            lo: must_less || must_greater,
1030            hi: can_less || can_greater,
1031            err: self.err.union(&other.err),
1032        }
1033    }
1034
1035    pub fn fmin(&self, other: &Interval) -> Interval {
1036        Interval::make(
1037            self.lo().min(&other.lo()),
1038            self.hi().min(&other.hi()),
1039             self.err.union(&other.err))
1040    }
1041
1042    pub fn fmax(&self, other: &Interval) -> Interval {
1043        Interval::make(
1044            self.lo().max(&other.lo()),
1045            self.hi().max(&other.hi()),
1046             self.err.union(&other.err))
1047    }
1048
1049    pub fn copysign(&self, other: &Interval) -> Interval {
1050        let abs = self.fabs();
1051        let can_neg = other.lo() < 0.0 as f64;
1052        let can_pos = other.hi() >= 0.0 as f64;
1053        match (can_neg, can_pos) {
1054            (true, true) => Interval::make(
1055                -abs.hi(),
1056                abs.hi(),
1057                 self.err.union(&other.err)),
1058            (true, false) => Interval::make(
1059                -abs.hi(),
1060                -abs.lo(),
1061                 self.err.union(&other.err)),
1062            (false, true) => Interval::make(
1063                abs.lo(),
1064                abs.hi(),
1065                 self.err.union(&other.err)),
1066            (false, false) => panic!("Should not be possible to have neither sign"),
1067        }
1068    }
1069
1070    pub fn fdim(&self, other: &Interval) -> Interval {
1071        self.sub(&other)
1072            .fmax(&Interval::new(other.lo().prec(), 0.0, 0.0))
1073    }
1074
1075    pub fn sort(intervals: Vec<Interval>) -> Vec<Interval> {
1076        let error = ErrorInterval {
1077            lo: intervals.iter().any(|ival| ival.err.lo),
1078            hi: intervals.iter().any(|ival| ival.err.hi),
1079        };
1080        let mut upper = intervals
1081            .iter()
1082            .map(|ival| ival.hi())
1083            .collect::<Vec<Float>>();
1084        upper.sort_by(|a, b| a.partial_cmp(b).unwrap());
1085        let mut lower = intervals
1086            .iter()
1087            .map(|ival| ival.lo())
1088            .collect::<Vec<Float>>();
1089        lower.sort_by(|a, b| a.partial_cmp(b).unwrap());
1090        let mut res = vec![];
1091        for (hi, lo) in upper.into_iter().zip(lower.into_iter()) {
1092            res.push(Interval::make(
1093                lo,
1094                hi,
1095                 error.clone()));
1096        }
1097        res
1098    }
1099}
1100
1101#[cfg(test)]
1102mod tests {
1103    use super::*;
1104    use egg::Symbol;
1105    use rand;
1106    use rand::Rng;
1107    use rug::ops::Pow;
1108
1109    fn random_interval() -> Interval {
1110        let mut rng = rand::thread_rng();
1111        let lo: f64 = rng.gen_range(-40.0..40.0);
1112        let hi = rng.gen_range(lo..41.0);
1113        Interval::new(F64_PREC, lo, hi)
1114    }
1115
1116    #[test]
1117    fn smaller_intervals_refine() {
1118        type Operator = fn(&Interval, &Interval) -> Interval;
1119        type SingleOperator = fn(&Interval) -> Interval;
1120        type FOperator = fn(Float, &Float) -> Float;
1121        type SingleFOperator = fn(Float) -> Float;
1122        type FloatToBool = fn(&Interval, &Interval) -> BooleanInterval;
1123        //type SingleFloatToBool = fn(&Interval) -> BooleanInterval;
1124        type FFloatToBool = fn(Float, &Float) -> bool;
1125        //type SingleFFloatToBool = fn(Float) -> bool;
1126
1127        let interval_functions: Vec<(Symbol, Operator, FOperator)> = vec![
1128            ("add".into(), Interval::add, |x, y| x + y),
1129            ("sub".into(), Interval::sub, |x, y| x - y),
1130            ("mul".into(), Interval::mul, |x, y| x * y),
1131            ("div".into(), Interval::div, |x, y| x / y),
1132            ("hypot".into(), Interval::hypot, |x, y| x.hypot(y)),
1133            ("pow".into(), Interval::pow, |x, y| x.pow(y)),
1134            ("atan2".into(), Interval::atan2, Float::atan2),
1135            ("fmod".into(), Interval::fmod, |x, y| x % y),
1136            ("remainder".into(), Interval::remainder, |x, y| {
1137                x.remainder(y)
1138            }),
1139            ("fmin".into(), Interval::fmin, |x, y| x.min(y)),
1140            ("fmax".into(), Interval::fmax, |x, y| x.max(y)),
1141            ("copysign".into(), Interval::copysign, |x, y| x.copysign(y)),
1142        ];
1143        let to_boolean_functions: Vec<(Symbol, FloatToBool, FFloatToBool)> = vec![
1144            ("less_than".into(), Interval::less_than, |x, y| &x < y),
1145            (
1146                "less_than_or_equal".into(),
1147                Interval::less_than_or_equal,
1148                |x, y| &x <= y,
1149            ),
1150            ("greater_than".into(), Interval::greater_than, |x, y| &x > y),
1151            (
1152                "greater_than_or_equal".into(),
1153                Interval::greater_than_or_equal,
1154                |x, y| &x >= y,
1155            ),
1156            ("equal_to".into(), Interval::equal_to, |x, y| &x == y),
1157        ];
1158        let single_operand_functions: Vec<(Symbol, SingleOperator, SingleFOperator)> = vec![
1159            ("round".into(), Interval::round, |x| x.round()),
1160            ("ceil".into(), Interval::ceil, Float::ceil),
1161            ("floor".into(), Interval::floor, Float::floor),
1162            ("trunc".into(), Interval::trunc, Float::trunc),
1163            ("fabs".into(), Interval::fabs, Float::abs),
1164            ("sqrt".into(), Interval::sqrt, Float::sqrt),
1165            ("exp".into(), Interval::exp, Float::exp),
1166            ("exp_m1".into(), Interval::exp_m1, Float::exp_m1),
1167            ("exp2".into(), Interval::exp2, Float::exp2),
1168            ("ln".into(), Interval::ln, Float::ln),
1169            ("ln_1p".into(), Interval::ln_1p, Float::ln_1p),
1170            ("log2".into(), Interval::log2, Float::log2),
1171            ("log10".into(), Interval::log10, Float::log10),
1172            ("cbrt".into(), Interval::cbrt, Float::cbrt),
1173            ("sin".into(), Interval::sin, Float::sin),
1174            ("cos".into(), Interval::cos, Float::cos),
1175            ("tan".into(), Interval::tan, Float::tan),
1176            ("asin".into(), Interval::asin, Float::asin),
1177            ("acos".into(), Interval::acos, Float::acos),
1178            ("atan".into(), Interval::atan, Float::atan),
1179            ("sinh".into(), Interval::sinh, Float::sinh),
1180            ("cosh".into(), Interval::cosh, Float::cosh),
1181            ("tanh".into(), Interval::tanh, Float::tanh),
1182            ("asinh".into(), Interval::asinh, Float::asinh),
1183            ("acosh".into(), Interval::acosh, Float::acosh),
1184            ("atanh".into(), Interval::atanh, Float::atanh),
1185            ("erf".into(), Interval::erf, Float::erf),
1186            ("erfc".into(), Interval::erfc, Float::erfc),
1187        ];
1188        let mut rng = rand::thread_rng();
1189
1190        for _i in 0..200_000 {
1191            for (name, ifun, realfun) in &to_boolean_functions {
1192                let ival1 = random_interval();
1193                let ival2 = random_interval();
1194
1195                let realval1 = rng.gen_range(ival1.lo().to_f64()..ival1.hi().to_f64());
1196                let realval2 = rng.gen_range(ival2.lo().to_f64()..ival2.hi().to_f64());
1197                let finalival = ifun(&ival1, &ival2);
1198                let finalreal = realfun(bf(F64_PREC, realval1), &bf(F64_PREC, realval2));
1199
1200                if finalreal {
1201                    assert!(
1202                        finalival.hi,
1203                        "Should have a possibility of true value for {}({:?} {:?})",
1204                        name, ival1, ival2
1205                    );
1206                } else {
1207                    assert!(!finalival.lo);
1208                }
1209            }
1210
1211            for (name, ifun, realfun) in &interval_functions {
1212                let ival1 = random_interval();
1213                let ival2 = random_interval();
1214
1215                let realval1 = rng.gen_range(ival1.lo().to_f64()..ival1.hi().to_f64());
1216                let realval2 = rng.gen_range(ival2.lo().to_f64()..ival2.hi().to_f64());
1217                let finalival = ifun(&ival1, &ival2);
1218                let finalreal = realfun(bf(F64_PREC, realval1), &bf(F64_PREC, realval2));
1219
1220                if finalreal.is_nan() {
1221                    assert!(finalival.err.hi);
1222                } else {
1223                    assert!(
1224                        !finalival.err.lo,
1225                        "{} and {} gave us a guaranteed error for {}. Got: {}",
1226                        realval1, realval2, name, finalreal
1227                    );
1228                    assert!(
1229                        finalreal <= finalival.hi(),
1230                        "{}({} {}): {} <= {} \n Intervals: {:?} and {:?} to {:?}",
1231                        name,
1232                        realval1,
1233                        realval2,
1234                        finalreal,
1235                        finalival.hi(),
1236                        ival1,
1237                        ival2,
1238                        finalival
1239                    );
1240                    assert!(
1241                        finalreal >= finalival.lo(),
1242                        "{} >= {}",
1243                        finalreal,
1244                        finalival.lo()
1245                    );
1246                }
1247            }
1248
1249            for (name, ifun, realfun) in &single_operand_functions {
1250                let lo1 = rng.gen_range(-40.0..40.0);
1251                let hi1 = rng.gen_range(lo1..41.0);
1252                let ival1 = Interval::new(F64_PREC, lo1, hi1);
1253                let realval1 = rng.gen_range(lo1..hi1);
1254                let finalival = ifun(&ival1);
1255                let finalreal = realfun(bf(F64_PREC, realval1));
1256
1257                if finalreal.is_nan() {
1258                    assert!(finalival.err.hi);
1259                } else {
1260                    assert!(!finalival.err.lo);
1261                    assert!(
1262                        finalreal <= finalival.hi(),
1263                        "{}: {} <= {}",
1264                        name,
1265                        finalreal,
1266                        finalival.hi()
1267                    );
1268                    assert!(
1269                        finalreal >= finalival.lo(),
1270                        "{}: {} >= {}",
1271                        name,
1272                        finalreal,
1273                        finalival.lo()
1274                    );
1275                }
1276            }
1277        }
1278    }
1279}