lean2/src/util/interval/interval.cpp
Leonardo de Moura eba31a0516 test(util/interval): add more tests
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2013-11-19 19:07:09 -08:00

2489 lines
82 KiB
C++

/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
Soonho Kong
*/
#pragma once
#include <gmp.h>
#include <mpfr.h>
#include <utility>
#include <algorithm>
#include "util/trace.h"
#include "util/numerics/mpz.h"
#include "util/interval/interval.h"
namespace lean {
template<typename T>
interval_deps interval<T>::dummy;
template<typename T>
void interval<T>::set_closed_endpoints() {
m_lower_open = false;
m_upper_open = false;
m_lower_inf = false;
m_upper_inf = false;
}
template<typename T>
interval<T> & interval<T>::operator=(interval const & n) {
m_lower = n.m_lower;
m_upper = n.m_upper;
m_lower_open = n.m_lower_open;
m_upper_open = n.m_upper_open;
m_lower_inf = n.m_lower_inf;
m_upper_inf = n.m_upper_inf;
return *this;
}
template<typename T>
interval<T> & interval<T>::operator=(interval && n) {
m_lower = std::move(n.m_lower);
m_upper = std::move(n.m_upper);
m_lower_open = n.m_lower_open;
m_upper_open = n.m_upper_open;
m_lower_inf = n.m_lower_inf;
m_upper_inf = n.m_upper_inf;
return *this;
}
template<typename T>
interval<T>::interval():
m_lower(),
m_upper() {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_inf = true;
m_lower_open = true;
m_upper_inf = true;
m_upper_open = true;
lean_assert(check_invariant());
}
template<typename T>
interval<T>::interval(interval<T> const & n):
m_lower(n.m_lower),
m_upper(n.m_upper),
m_lower_open(n.m_lower_open),
m_upper_open(n.m_upper_open),
m_lower_inf(n.m_lower_inf),
m_upper_inf(n.m_upper_inf) {
lean_assert(check_invariant());
}
template<typename T>
interval<T>::interval(interval<T> && n):
m_lower(std::move(n.m_lower)),
m_upper(std::move(n.m_upper)),
m_lower_open(n.m_lower_open),
m_upper_open(n.m_upper_open),
m_lower_inf(n.m_lower_inf),
m_upper_inf(n.m_upper_inf) {
lean_assert(check_invariant());
}
template<typename T>
interval<T>::~interval() {
}
template<typename T>
void interval<T>::_swap(interval<T> & b) {
using std::swap;
swap(m_lower, b.m_lower);
swap(m_upper, b.m_upper);
unsigned tmp;
tmp = m_lower_inf; m_lower_inf = b.m_lower_inf; b.m_lower_inf = tmp;
tmp = m_upper_inf; m_upper_inf = b.m_upper_inf; b.m_upper_inf = tmp;
tmp = m_lower_open; m_lower_open = b.m_lower_open; b.m_lower_open = tmp;
tmp = m_upper_open; m_upper_open = b.m_upper_open; b.m_upper_open = tmp;
}
template<typename T>
bool interval<T>::contains_zero() const {
return
(is_lower_neg() || (is_lower_zero() && !is_lower_open())) &&
(is_upper_pos() || (is_upper_zero() && !is_upper_open()));
}
template<typename T>
bool interval<T>::contains(interval<T> const & b) const {
if (!m_lower_inf) {
if (b.m_lower_inf)
return false;
if (m_lower > b.m_lower)
return false;
if (m_lower == b.m_lower && m_lower_open && !b.m_lower_open)
return false;
}
if (!m_upper_inf) {
if (b.m_upper_inf)
return false;
if (m_upper < b.m_upper)
return false;
if (m_upper == b.m_upper && m_upper_open && !b.m_upper_open)
return false;
}
return true;
}
template<typename T>
bool interval<T>::is_empty() const {
return
(m_lower == m_upper && (m_lower_open || m_upper_open) && !m_lower_inf && !m_upper_inf) ||
(m_lower > m_upper && !m_lower_inf && !m_upper_inf);
}
template<typename T>
void interval<T>::set_empty() {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = false;
}
template<typename T>
bool interval<T>::is_singleton() const {
return !m_lower_inf && !m_upper_inf && !m_lower_open && !m_upper_open && m_lower == m_upper;
}
template<typename T>
bool interval<T>::_eq(interval<T> const & b) const {
return
m_lower_open == b.m_lower_open &&
m_upper_open == b.m_upper_open &&
eq(m_lower, lower_kind(), b.m_lower, b.lower_kind()) &&
eq(m_upper, upper_kind(), b.m_upper, b.upper_kind());
}
template<typename T>
bool interval<T>::before(interval<T> const & b) const {
if (is_upper_inf() || b.is_lower_inf())
return false;
return m_upper < b.m_lower || (is_upper_open() && m_upper == b.m_lower);
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::neg(interval_deps & deps) {
using std::swap;
if (is_lower_inf()) {
if (is_upper_inf()) {
// (-oo, oo) case
// do nothing
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
} else {
// (-oo, a| --> |-a, oo)
if (compute_intv) {
swap(m_lower, m_upper);
neg(m_lower);
m_lower_inf = false;
m_lower_open = m_upper_open;
reset(m_upper);
m_upper_inf = true;
m_upper_open = true;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1;
deps.m_upper_deps = 0;
}
}
} else {
if (is_upper_inf()) {
// |a, oo) --> (-oo, -a|
if (compute_intv) {
swap(m_upper, m_lower);
neg(m_upper);
m_upper_inf = false;
m_upper_open = m_lower_open;
reset(m_lower);
m_lower_inf = true;
m_lower_open = true;
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = DEP_IN_LOWER1;
}
} else {
// |a, b| --> |-b, -a|
if (compute_intv) {
swap(m_lower, m_upper);
neg(m_lower);
neg(m_upper);
unsigned lo = m_lower_open;
unsigned li = m_lower_inf;
m_lower_open = m_upper_open;
m_lower_inf = m_upper_inf;
m_upper_open = lo;
m_upper_inf = li;
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_LOWER1;
deps.m_lower_deps = DEP_IN_UPPER1;
}
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
}
template<typename T>
interval<T> & interval<T>::operator+=(interval<T> const & o) {
return add(o);
}
template<typename T>
interval<T> & interval<T>::operator-=(interval<T> const & o) {
return sub(o);
}
template<typename T>
interval<T> & interval<T>::operator*=(interval<T> const & o) {
return mul(o);
}
template<typename T>
interval<T> & interval<T>::operator/=(interval<T> const & o) {
return div(o);
}
template<typename T>
template<bool compute_intv, bool compute_deps>
interval<T> & interval<T>::add(interval<T> const & o, interval_deps & deps) {
if (compute_intv) {
xnumeral_kind new_l_kind, new_u_kind;
round_to_minus_inf();
lean::add(m_lower, new_l_kind, m_lower, lower_kind(), o.m_lower, o.lower_kind());
round_to_plus_inf();
lean::add(m_upper, new_u_kind, m_upper, upper_kind(), o.m_upper, o.upper_kind());
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
m_lower_open = m_lower_open || o.m_lower_open;
m_upper_open = m_upper_open || o.m_upper_open;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2;
}
return *this;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
interval<T> & interval<T>::sub(interval<T> const & o, interval_deps & deps) {
if (compute_intv) {
using std::swap;
static thread_local T new_l_val;
static thread_local T new_u_val;
xnumeral_kind new_l_kind, new_u_kind;
lean_trace("numerics", tout << "this: " << *this << " o: " << o << "\n";);
round_to_minus_inf();
lean::sub(new_l_val, new_l_kind, m_lower, lower_kind(), o.m_upper, o.upper_kind());
round_to_plus_inf();
lean::sub(new_u_val, new_u_kind, m_upper, upper_kind(), o.m_lower, o.lower_kind());
lean_trace("numerics", tout << "new: " << new_l_val << " " << new_u_val << "\n";);
swap(new_l_val, m_lower);
swap(new_u_val, m_upper);
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
bool o_l = o.m_lower_open;
m_lower_open = m_lower_open || o.m_upper_open;
m_upper_open = m_upper_open || o_l;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2;
}
return *this;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
interval<T> & interval<T>::mul(interval<T> const & o, interval_deps & deps) {
using std::swap;
interval<T> const & i1 = *this;
interval<T> const & i2 = o;
#if defined(LEAN_DEBUG) || defined(LEAN_TRACE)
bool i1_contains_zero = i1.contains_zero();
bool i2_contains_zero = i2.contains_zero();
#endif
if (i1.is_zero()) {
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return *this;
}
if (i2.is_zero()) {
if (compute_intv) {
*this = i2;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return *this;
}
T const & a = i1.m_lower; xnumeral_kind a_k = i1.lower_kind();
T const & b = i1.m_upper; xnumeral_kind b_k = i1.upper_kind();
T const & c = i2.m_lower; xnumeral_kind c_k = i2.lower_kind();
T const & d = i2.m_upper; xnumeral_kind d_k = i2.upper_kind();
bool a_o = i1.is_lower_open();
bool b_o = i1.is_upper_open();
bool c_o = i2.is_lower_open();
bool d_o = i2.is_upper_open();
static thread_local T new_l_val;
static thread_local T new_u_val;
xnumeral_kind new_l_kind, new_u_kind;
if (i1.is_N()) {
if (i2.is_N()) {
// x <= b <= 0, y <= d <= 0 --> b*d <= x*y
// a <= x <= b <= 0, c <= y <= d <= 0 --> x*y <= a*c (we
// can use the fact that x or y is always negative (i.e.,
// b is neg or d is neg))
if (compute_intv) {
set_is_lower_open((i1.is_N0() || i2.is_N0()) ? false : (b_o || d_o));
set_is_upper_open(a_o || c_o);
// if b = 0 (and the interval is closed), then the lower bound is closed
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, b, b_k, d, d_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, a, a_k, c, c_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2 | DEP_IN_UPPER1; // we can replace DEP_IN_UPPER1 with DEP_IN_UPPER2
}
} else if (i2.is_M()) {
// a <= x <= b <= 0, y <= d, d > 0 --> a*d <= x*y (uses the fact that b is not positive)
// a <= x <= b <= 0, c <= y, c < 0 --> x*y <= a*c (uses
// the fact that b is not positive)
if (compute_intv) {
set_is_lower_open(a_o || d_o);
set_is_upper_open(a_o || c_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, a, a_k, d, d_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, a, a_k, c, c_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2 | DEP_IN_UPPER1;
}
} else {
// a <= x <= b <= 0, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that x is neg (b is not positive) or y is pos (c is not negative))
// x <= b <= 0, 0 <= c <= y --> x*y <= b*c
lean_assert(i2.is_P());
// must update upper_is_open first, since value of is_N0(i1) and is_P0(i2) may be affected by update
if (compute_intv) {
set_is_upper_open((i1.is_N0() || i2.is_P0()) ? false : (b_o || c_o));
set_is_lower_open(a_o || d_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, a, a_k, d, d_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, b, b_k, c, c_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2 | DEP_IN_UPPER1; // we can replace DEP_IN_UPPER1 with DEP_IN_UPPER2
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2;
}
}
} else if (i1.is_M()) {
if (i2.is_N()) {
// b > 0, x <= b, c <= y <= d <= 0 --> b*c <= x*y (uses the fact that d is not positive)
// a < 0, a <= x, c <= y <= d <= 0 --> x*y <= a*c (uses
// the fact that d is not positive)
if (compute_intv) {
set_is_lower_open(b_o || c_o);
set_is_upper_open(a_o || c_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, b, b_k, c, c_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, a, a_k, c, c_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
}
} else if (i2.is_M()) {
static thread_local T ad; static thread_local xnumeral_kind ad_k;
static thread_local T bc; static thread_local xnumeral_kind bc_k;
static thread_local T ac; static thread_local xnumeral_kind ac_k;
static thread_local T bd; static thread_local xnumeral_kind bd_k;
bool ad_o = a_o || d_o;
bool bc_o = b_o || c_o;
bool ac_o = a_o || c_o;
bool bd_o = b_o || d_o;
if (compute_intv) {
round_to_minus_inf();
lean::mul(ad, ad_k, a, a_k, d, d_k);
lean::mul(bc, bc_k, b, b_k, c, c_k);
round_to_plus_inf();
lean::mul(ac, ac_k, a, a_k, c, c_k);
lean::mul(bd, bd_k, b, b_k, d, d_k);
}
if (lt(ad, ad_k, bc, bc_k) || (eq(ad, ad_k, bc, bc_k) && !ad_o && bc_o)) {
if (compute_intv) {
swap(new_l_val, ad);
new_l_kind = ad_k;
set_is_lower_open(ad_o);
}
} else {
if (compute_intv) {
swap(new_l_val, bc);
new_l_kind = bc_k;
set_is_lower_open(bc_o);
}
}
if (gt(ac, ac_k, bd, bd_k) || (eq(ac, ac_k, bd, bd_k) && !ac_o && bd_o)) {
if (compute_intv) {
swap(new_u_val, ac);
new_u_kind = ac_k;
set_is_upper_open(ac_o);
}
} else {
if (compute_intv) {
swap(new_u_val, bd);
new_u_kind = bd_k;
set_is_upper_open(bd_o);
}
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
}
} else {
// a < 0, a <= x, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that c is not negative)
// b > 0, x <= b, 0 <= c <= y <= d --> x*y <= b*d (uses the fact that c is not negative)
lean_assert(i2.is_P());
if (compute_intv) {
set_is_lower_open(a_o || d_o);
set_is_upper_open(b_o || d_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, a, a_k, d, d_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, b, b_k, d, d_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2 | DEP_IN_LOWER2;
}
}
} else {
lean_assert(i1.is_P());
if (i2.is_N()) {
// 0 <= a <= x <= b, c <= y <= d <= 0 --> x*y <= b*c (uses the fact that x is pos (a is not neg) or y is neg (d is not pos))
// 0 <= a <= x, y <= d <= 0 --> a*d <= x*y
// must update upper_is_open first, since value of is_P0(i1) and is_N0(i2) may be affected by update
if (compute_intv) {
set_is_upper_open((i1.is_P0() || i2.is_N0()) ? false : a_o || d_o);
set_is_lower_open(b_o || c_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, b, b_k, c, c_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, a, a_k, d, d_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_LOWER1; // we can replace DEP_IN_LOWER1 with DEP_IN_UPPER2
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
}
} else if (i2.is_M()) {
// 0 <= a <= x <= b, c <= y --> b*c <= x*y (uses the fact that a is not negative)
// 0 <= a <= x <= b, y <= d --> x*y <= b*d (uses the fact
// that a is not negative)
if (compute_intv) {
set_is_lower_open(b_o || c_o);
set_is_upper_open(b_o || d_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, b, b_k, c, c_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, b, b_k, d, d_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_LOWER1;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2 | DEP_IN_LOWER1;
}
} else {
lean_assert(i2.is_P());
// 0 n<= a <= x, 0 <= c <= y --> a*c <= x*y
// x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
if (compute_intv) {
set_is_lower_open((i1.is_P0() || i2.is_P0()) ? false : a_o || c_o);
set_is_upper_open(b_o || d_o);
round_to_minus_inf();
lean::mul(new_l_val, new_l_kind, a, a_k, c, c_k);
round_to_plus_inf();
lean::mul(new_u_val, new_u_kind, b, b_k, d, d_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2 | DEP_IN_LOWER1;
}
}
}
if (compute_intv) {
swap(m_lower, new_l_val);
swap(m_upper, new_u_val);
set_is_lower_inf(new_l_kind == XN_MINUS_INFINITY);
set_is_upper_inf(new_u_kind == XN_PLUS_INFINITY);
lean_assert(!(i1_contains_zero || i2_contains_zero) || contains_zero());
lean_assert(check_invariant());
}
return *this;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
interval<T> & interval<T>::div(interval<T> const & o, interval_deps & deps) {
using std::swap;
interval<T> const & i1 = *this;
interval<T> const & i2 = o;
lean_assert(!i2.contains_zero());
if (i1.is_zero()) {
// 0/other = 0 if other != 0
// do nothing
if (compute_deps) {
if (i2.is_P1()) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2;
} else {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
}
}
} else {
T const & a = i1.m_lower; xnumeral_kind a_k = i1.lower_kind();
T const & b = i1.m_upper; xnumeral_kind b_k = i1.upper_kind();
T const & c = i2.m_lower; xnumeral_kind c_k = i2.lower_kind();
T const & d = i2.m_upper; xnumeral_kind d_k = i2.upper_kind();
bool a_o = i1.m_lower_open;
bool b_o = i1.m_upper_open;
bool c_o = i2.m_lower_open;
bool d_o = i2.m_upper_open;
static thread_local T new_l_val;
static thread_local T new_u_val;
xnumeral_kind new_l_kind, new_u_kind;
if (i1.is_N()) {
if (i2.is_N1()) {
// x <= b <= 0, c <= y <= d < 0 --> b/c <= x/y
// a <= x <= b <= 0, y <= d < 0 --> x/y <= a/d
if (compute_intv) {
set_is_lower_open(i1.is_N0() ? false : b_o || c_o);
set_is_upper_open(a_o || d_o);
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, b, b_k, c, c_k);
if (is_zero(d)) {
lean_assert(d_o);
reset(new_u_val);
new_u_kind = XN_PLUS_INFINITY;
} else {
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, a, a_k, d, d_k);
}
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
}
} else {
// a <= x, a < 0, 0 < c <= y --> a/c <= x/y
// x <= b <= 0, 0 < c <= y <= d --> x/y <= b/d
lean_assert(i2.is_P1());
if (compute_intv) {
set_is_upper_open(i1.is_N0() ? false : (b_o || d_o));
set_is_lower_open(a_o || c_o);
if (is_zero(c)) {
lean_assert(c_o);
reset(new_l_val);
new_l_kind = XN_MINUS_INFINITY;
} else {
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, a, a_k, c, c_k);
}
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, b, b_k, d, d_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
}
}
} else if (i1.is_M()) {
if (i2.is_N1()) {
// 0 < a <= x <= b < 0, y <= d < 0 --> b/d <= x/y
// 0 < a <= x <= b < 0, y <= d < 0 --> x/y <= a/d
if (compute_intv) {
set_is_lower_open(b_o || d_o);
set_is_upper_open(a_o || d_o);
if (is_zero(d)) {
lean_assert(d_o);
reset(new_l_val);
reset(new_u_val);
new_l_kind = XN_MINUS_INFINITY;
new_u_kind = XN_PLUS_INFINITY;
} else {
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, b, b_k, d, d_k);
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, a, a_k, d, d_k);
}
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
}
} else {
// 0 < a <= x <= b < 0, 0 < c <= y --> a/c <= x/y
// 0 < a <= x <= b < 0, 0 < c <= y --> x/y <= b/c
lean_assert(i1.is_P1());
if (compute_intv) {
set_is_lower_open(a_o || c_o);
set_is_upper_open(b_o || c_o);
if (is_zero(c)) {
lean_assert(c_o);
reset(new_l_val);
reset(new_u_val);
new_l_kind = XN_MINUS_INFINITY;
new_u_kind = XN_PLUS_INFINITY;
} else {
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, a, a_k, c, c_k);
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, b, b_k, c, c_k);
}
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2;
}
}
} else {
lean_assert(i1.is_P());
if (i2.is_N1()) {
// b > 0, x <= b, c <= y <= d < 0 --> b/d <= x/y
// 0 <= a <= x, c <= y <= d < 0 --> x/y <= a/c
if (compute_intv) {
set_is_upper_open(i1.is_P0() ? false : a_o || c_o);
set_is_lower_open(b_o || d_o);
if (is_zero(d)) {
lean_assert(d_o);
reset(new_l_val);
new_l_kind = XN_MINUS_INFINITY;
} else {
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, b, b_k, d, d_k);
}
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, a, a_k, c, c_k);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
}
} else {
lean_assert(i2.is_P1());
// 0 <= a <= x, 0 < c <= y <= d --> a/d <= x/y
// b > 0 x <= b, 0 < c <= y --> x/y <= b/c
if (compute_intv) {
set_is_lower_open(i1.is_P0() ? false : a_o || d_o);
set_is_upper_open(b_o || c_o);
round_to_minus_inf();
lean::div(new_l_val, new_l_kind, a, a_k, d, d_k);
if (is_zero(c)) {
lean_assert(c_o);
reset(new_u_val);
new_u_kind = XN_PLUS_INFINITY;
} else {
round_to_plus_inf();
lean::div(new_u_val, new_u_kind, b, b_k, c, c_k);
}
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2;
}
}
}
if (compute_intv) {
swap(m_lower, new_l_val);
swap(m_upper, new_u_val);
m_lower_inf = (new_l_kind == XN_MINUS_INFINITY);
m_upper_inf = (new_u_kind == XN_PLUS_INFINITY);
}
}
return *this;
}
template<typename T> void interval<T>::add_jst(interval<T> const & o, interval_deps & deps) {
add<false, true>(o, deps);
return;
}
template<typename T> void interval<T>::sub_jst(interval<T> const & o, interval_deps & deps) {
sub<false, true>(o, deps);
return;
}
template<typename T> void interval<T>::mul_jst(interval<T> const & o, interval_deps & deps) {
mul<false, true>(o, deps);
return;
}
template<typename T> void interval<T>::div_jst(interval<T> const & o, interval_deps & deps) {
div<false, true>(o, deps);
return;
}
template<typename T>
interval<T> & interval<T>::operator+=(T const & o) {
xnumeral_kind new_l_kind, new_u_kind;
round_to_minus_inf();
lean::add(m_lower, new_l_kind, m_lower, lower_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::add(m_upper, new_u_kind, m_upper, upper_kind(), o, XN_NUMERAL);
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
lean_assert(check_invariant());
return *this;
}
template<typename T>
interval<T> & interval<T>::operator-=(T const & o) {
xnumeral_kind new_l_kind, new_u_kind;
round_to_minus_inf();
lean::sub(m_lower, new_l_kind, m_lower, lower_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::sub(m_upper, new_u_kind, m_upper, upper_kind(), o, XN_NUMERAL);
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
lean_assert(check_invariant());
return *this;
}
template<typename T>
interval<T> & interval<T>::operator*=(T const & o) {
xnumeral_kind new_l_kind, new_u_kind;
static thread_local T tmp1;
if (this->is_zero()) {
return *this;
}
if (numeric_traits<T>::is_zero(o)) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = false;
m_lower_inf = m_upper_inf = false;
return *this;
}
if (numeric_traits<T>::is_pos(o)) {
// [a, b] * c = [a*c, b*c] when c > 0
round_to_minus_inf();
lean::mul(m_lower, new_l_kind, m_lower, lower_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::mul(m_upper, new_u_kind, m_upper, upper_kind(), o, XN_NUMERAL);
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
} else {
// [a, b] * c = [b*c, a*c] when c < 0
round_to_minus_inf();
lean::mul(tmp1, new_l_kind, m_upper, upper_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::mul(m_upper, new_u_kind, m_lower, lower_kind(), o, XN_NUMERAL);
m_lower = tmp1;
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
}
return *this;
}
template<typename T>
interval<T> & interval<T>::operator/=(T const & o) {
xnumeral_kind new_l_kind, new_u_kind;
static thread_local T tmp1;
if (this->is_zero()) {
return *this;
}
if (numeric_traits<T>::is_zero(o)) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
return *this;
}
if (numeric_traits<T>::is_pos(o)) {
// [a, b] / c = [a/c, b/c] when c > 0
round_to_minus_inf();
lean::div(m_lower, new_l_kind, m_lower, lower_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::div(m_upper, new_u_kind, m_upper, upper_kind(), o, XN_NUMERAL);
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
} else {
// [a, b] / c = [b/c, a/c] when c < 0
round_to_minus_inf();
lean::div(tmp1, new_l_kind, m_upper, upper_kind(), o, XN_NUMERAL);
round_to_plus_inf();
lean::div(m_upper, new_u_kind, m_lower, lower_kind(), o, XN_NUMERAL);
m_lower = tmp1;
m_lower_inf = new_l_kind == XN_MINUS_INFINITY;
m_upper_inf = new_u_kind == XN_PLUS_INFINITY;
}
return *this;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::inv(interval_deps & deps) {
// If the interval [l, u] does not contain 0, then 1/[l, u] = [1/u, 1/l]
lean_assert(!contains_zero());
using std::swap;
static thread_local T new_l_val;
static thread_local T new_u_val;
xnumeral_kind new_l_kind, new_u_kind;
if (is_P1()) {
// 0 < l <= x --> 1/x <= 1/l
// 0 < l <= x <= u --> 1/u <= 1/x (use lower and upper bounds)
if (compute_intv) {
round_to_minus_inf();
new_l_val = m_upper;
new_l_kind = upper_kind();
::lean::inv(new_l_val, new_l_kind);
lean_assert(new_l_kind == XN_NUMERAL);
bool new_l_open = is_upper_open();
if (is_lower_zero()) {
lean_assert(is_lower_open());
reset(m_upper);
set_is_upper_inf(true);
set_is_upper_open(true);
} else {
round_to_plus_inf();
new_u_val = m_lower;
inv(new_u_val);
swap(m_upper, new_u_val);
set_is_upper_inf(false);
set_is_upper_open(is_lower_open());
}
swap(m_lower, new_l_val);
set_is_lower_inf(false);
set_is_lower_open(new_l_open);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1;
}
} else if (is_N1()) {
// x <= u < 0 --> 1/u <= 1/x
// l <= x <= u < 0 --> 1/l <= 1/x (use lower and upper bounds)
if (compute_intv) {
round_to_plus_inf();
new_u_val = m_lower;
new_u_kind = lower_kind();
::lean::inv(new_u_val, new_u_kind);
lean_assert(new_u_kind == XN_NUMERAL);
bool new_u_open = is_lower_open();
if (is_upper_zero()) {
lean_assert(is_upper_open());
reset(m_lower);
set_is_lower_open(true);
set_is_lower_inf(true);
} else {
round_to_minus_inf();
new_l_val = m_upper;
inv(new_l_val);
swap(m_lower, new_l_val);
set_is_lower_inf(false);
set_is_lower_open(is_upper_open());
}
swap(m_upper, new_u_val);
set_is_upper_inf(false);
set_is_upper_open(new_u_open);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
} else {
lean_unreachable(); // LCOV_EXCL_LINE
}
lean_assert(check_invariant());
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::power(unsigned n, interval_deps & deps) {
using std::swap;
lean_assert(n > 0);
if (n == 1) {
// a^1 = a
// nothing to be done
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
deps.m_upper_deps = DEP_IN_UPPER1;
}
return;
} else if (n % 2 == 0) {
if (is_lower_pos()) {
// [l, u]^n = [l^n, u^n] if l > 0
// 0 < l <= x --> l^n <= x^n (lower bound guarantees that is positive)
// 0 < l <= x <= u --> x^n <= u^n (use lower and upper bound -- need the fact that x is positive)
lean_assert(!is_lower_inf());
if (compute_intv) {
round_to_minus_inf();
power(m_lower, n);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
if (!m_upper_inf) {
if (compute_intv) {
round_to_plus_inf();
power(m_upper, n);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
} else {
deps.m_upper_deps = 0;
}
} else if (is_upper_neg()) {
// [l, u]^n = [u^n, l^n] if u < 0
// l <= x <= u < 0 --> x^n <= l^n (use lower and upper bound -- need the fact that x is negative)
// x <= u < 0 --> u^n <= x^n
lean_assert(!is_upper_inf());
const bool lo = m_lower_open;
const bool li = m_lower_inf;
if (compute_intv) {
swap(m_lower, m_upper);
round_to_minus_inf();
power(m_lower, n);
m_lower_open = m_upper_open;
m_lower_inf = false;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1;
}
if (li) {
if (compute_intv) {
reset(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = 0;
}
} else {
if (compute_intv) {
round_to_plus_inf();
power(m_upper, n);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_lower_deps = 0;
}
}
if (compute_intv) {
m_upper_inf = li;
m_upper_open = lo;
}
} else {
// [l, u]^n = [0, max{l^n, u^n}] otherwise
// we need both bounds to justify upper bound
xnumeral_kind un1_kind = lower_kind();
xnumeral_kind un2_kind = upper_kind();
static thread_local T un1;
static thread_local T un2;
if (compute_intv) {
swap(un1, m_lower);
swap(un2, m_upper);
round_to_plus_inf();
::lean::power(un1, un1_kind, n);
::lean::power(un2, un2_kind, n);
if (gt(un1, un1_kind, un2, un2_kind) || (eq(un1, un1_kind, un2, un2_kind) && !m_lower_open && m_upper_open)) {
swap(m_upper, un1);
m_upper_inf = (un1_kind == XN_PLUS_INFINITY);
m_upper_open = m_lower_open;
} else {
swap(m_upper, un2);
m_upper_inf = (un2_kind == XN_PLUS_INFINITY);
}
reset(m_lower);
m_lower_inf = false;
m_lower_open = false;
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_lower_deps = 0;
}
}
} else {
// Remark: when n is odd x^n is monotonic.
if (!m_lower_inf) {
if (compute_intv) {
round_to_minus_inf();
power(m_lower, n);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
} else {
if (compute_deps) {
deps.m_lower_deps = 0;
}
}
if (!m_upper_inf) {
if (compute_intv) {
round_to_plus_inf();
power(m_upper, n);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
} else {
if (compute_deps) {
deps.m_upper_deps = 0;
}
}
}
}
template<typename T> void interval<T>::power_jst(unsigned n, interval_deps & deps) {
power<false, true>(n, deps);
return;
}
/**
return a/(x^n)
If to_plus_inf, then result >= a/(x^n)
If not to_plus_inf, then result <= a/(x^n)
*/
template<typename T>
T a_div_x_n(T a, T const & x, unsigned n, bool to_plus_inf) {
if (n == 1) {
numeric_traits<T>::set_rounding(to_plus_inf);
a /= x;
} else {
static thread_local T tmp;
numeric_traits<T>::set_rounding(!to_plus_inf);
tmp = x;
numeric_traits<T>::power(tmp, n);
numeric_traits<T>::set_rounding(to_plus_inf);
a /= x;
}
return a;
}
template<typename T>
bool interval<T>::check_invariant() const {
lean_assert(!m_lower_inf || m_lower_open);
lean_assert(!m_upper_inf || m_upper_open);
if (eq(m_lower, lower_kind(), m_upper, upper_kind())) {
lean_assert(!is_lower_open());
lean_assert(!is_upper_open());
} else {
lean_assert(lt(m_lower, lower_kind(), m_upper, upper_kind()));
}
return true;
}
template<typename T>
void interval<T>::display(std::ostream & out) const {
out << (m_lower_open ? "(" : "[");
::lean::display(out, m_lower, lower_kind());
out << ", ";
::lean::display(out, m_upper, upper_kind());
out << (m_upper_open ? ")" : "]");
}
template<typename T> void interval<T>::fmod(interval<T> y) {
T const & yb = numeric_traits<T>::is_neg(m_lower) ? y.m_lower : y.m_upper;
static thread_local T n;
numeric_traits<T>::set_rounding(false);
n = m_lower / yb;
numeric_traits<T>::floor(n);
*this -= n * y;
}
template<typename T> void interval<T>::fmod(T y) {
static thread_local T n;
numeric_traits<T>::set_rounding(false);
n = m_lower / y;
numeric_traits<T>::floor(n);
*this -= n * y;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::exp(interval_deps & deps) {
if (m_lower_inf) {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::exp(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (m_upper_inf) {
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::exp(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::exp2(interval_deps & deps) {
if (m_lower_inf) {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::exp2(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (m_upper_inf) {
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::exp2(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::exp10(interval_deps & deps) {
if (m_lower_inf) {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::exp10(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (m_upper_inf) {
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::exp10(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::log(interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL);
// lower_open => lower >= 0
lean_assert(!m_lower_open || numeric_traits<T>::is_pos(m_lower) || numeric_traits<T>::is_zero(m_lower));
// !lower_open => lower > 0
lean_assert(m_lower_open || numeric_traits<T>::is_pos(m_lower));
if (is_lower_pos()) {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::log(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
} else {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
m_lower_inf = true;
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
}
if (m_upper_inf) {
// Nothing to do
if (compute_deps) {
deps.m_upper_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::log(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::log2(interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL);
// lower_open => lower >= 0
lean_assert(!m_lower_open || numeric_traits<T>::is_pos(m_lower) || numeric_traits<T>::is_zero(m_lower));
// !lower_open => lower > 0
lean_assert(m_lower_open || numeric_traits<T>::is_pos(m_lower));
if (is_lower_pos()) {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::log2(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
} else {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
m_lower_inf = true;
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
}
if (m_upper_inf) {
// Nothing to do
if (compute_deps) {
deps.m_upper_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::log2(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::log10(interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL);
// lower_open => lower >= 0
lean_assert(!m_lower_open || numeric_traits<T>::is_pos(m_lower) || numeric_traits<T>::is_zero(m_lower));
// !lower_open => lower > 0
lean_assert(m_lower_open || numeric_traits<T>::is_pos(m_lower));
if (is_lower_pos()) {
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::log10(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
} else {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
m_lower_inf = true;
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
}
if (m_upper_inf) {
// Nothing to do
if (compute_deps) {
deps.m_upper_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::log10(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
lean_assert(check_invariant());
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::sin(interval_deps & deps) {
if (m_lower_inf || m_upper_inf) {
// sin([-oo, c]) = [-1.0, +1.0]
// sin([c, +oo]) = [-1.0, +1.0]
if (compute_intv) {
m_lower_open = m_upper_open = false;
m_lower_inf = m_upper_inf = false;
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
m_lower_open = m_upper_open = false;
m_lower_inf = m_upper_inf = false;
T const pi_twice = numeric_traits<T>::pi_twice();
fmod(interval<T>(numeric_traits<T>::pi_twice_lower(), numeric_traits<T>::pi_twice_upper()));
if (m_upper - m_lower >= pi_twice) {
// If the input width is bigger than 2pi,
// it covers whole domain and gets [-1.0, 1.0]
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
// Use sin(x - pi) = - sin(x)
// l \in [-pi, pi]
*this -= interval<T>(numeric_traits<T>::pi_lower(), numeric_traits<T>::pi_upper());
T const pi_half = numeric_traits<T>::pi_half();
T const pi = numeric_traits<T>::pi();
if (m_lower <= - pi_half) {
if (m_upper <= - pi_half) {
// 1. -pi <= l' <= u' <= -1/2 pi
// sin(x - pi) = [sin(u'), sin(l')]
// sin(x) = [-sin(l'), -sin(u')]
// sin(x) = [-sin(l'), sin(-u')]
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_lower);
m_lower = -m_lower;
m_upper = -m_upper;
numeric_traits<T>::sin(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_upper <= pi_half) {
// 2. -pi <= l' <= -1/2 pi <= u' <= 1/2 pi
// sin(x - pi) = [-1, max(sin(l'), sin(u'))]
// = [-1, sin(l')] if l' + u' <= - pi
// = [-1, sin(u')] if l' + u' >= - pi
// sin(x) = [-sin(l'), 1] if l' + u' <= - pi
// = [-sin(u'), 1] if l' + u' >= - pi
if (m_lower + m_upper <= - pi) {
// Nothing
} else {
if (compute_intv) {
m_lower = m_upper;
}
}
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_lower);
m_lower = - m_lower;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = 0;
}
return;
}
// 3. -pi <= l' <= -1/2 pi <= 1/2 pi <= u'
// sin(x - pi) = [-1, 1]
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
return;
}
if (m_lower <= pi_half) {
if (m_upper <= pi_half) {
// 4. -1/2 pi <= l' <= u' <= 1/2 pi
// sin(x - pi) = [sin(l'), sin(u')]
// sin(x) = [-sin(u'), -sin(l')]
// = [-sin(u'), sin(-l')]
if (compute_intv) {
std::swap(m_lower, m_upper);
m_upper = -m_upper;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_lower);
numeric_traits<T>::sin(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_upper <= pi_half + pi) {
// 5. -1/2 pi <= l' <= 1/2pi <= u' <= 3/2pi
// sin(x - pi) = [min(sin(l'), sin(u')), 1]
// = [sin(l'), 1] if l' + u' <= pi
// = [sin(u'), 1] if l' + u' >= pi
// sin(x) = [-1, sin(-l')] if l' + u' <= pi
// = [-1, sin(-u')] if l' + u' >= pi
if (m_lower + m_upper <= pi) {
if (compute_intv) {
m_upper = - m_lower;
}
} else {
if (compute_intv) {
m_upper = - m_upper;
}
}
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_upper);
m_lower = -1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
// 6. -1/2 pi <= l' <= 1/2pi <= 3/2pi <= u'
// sin(x - pi) = [-1, 1]
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
lean_assert(pi_half <= m_lower);
if (m_upper <= pi_half + pi) {
// 7. 1/2pi <= l' <= u' <= 3/2 pi
// sin(x - pi) = [sin(u'), sin(l')]
// sin(x) = [-sin(l'), sin(-u')]
if (compute_intv) {
m_upper = -m_upper;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_lower);
numeric_traits<T>::sin(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_upper <= pi_half + pi_twice) {
// 8. 1/2pi <= l' <= 3/2pi <= u' <= 5/2 pi
// sin(x - pi) = [-1, max(sin(l'), sin(u')]
// = [-1, sin(l')] if l' + u' <= 3pi
// = [-1, sin(u')] if l' + u' >= 3pi
// sin(x) = [-sin(l'), 1] if l' + u' <= 3pi
// = [-sin(u'), 1] if l' + u' >= 3pi
if (m_lower + m_upper <= pi + pi_twice) {
// Nothing
} else {
if (compute_intv) {
m_lower = m_upper;
}
}
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sin(m_lower);
m_lower = - m_lower;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = 0;
}
return;
}
// 9. 1/2pi <= l' <= 5/2pi <= u'
// sin(x - pi) = [-1, 1]
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::cos (interval_deps & deps) {
if (m_lower_inf || m_upper_inf) {
// cos([-oo, c]) = [-1.0, +1.0]
// cos([c, +oo]) = [-1.0, +1.0]
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
m_lower_open = m_upper_open = false;
m_lower_inf = m_upper_inf = false;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
m_lower_open = m_upper_open = false;
m_lower_inf = m_upper_inf = false;
T const pi_twice = numeric_traits<T>::pi_twice();
fmod(interval<T>(numeric_traits<T>::pi_twice_lower(), numeric_traits<T>::pi_twice_upper()));
if (m_upper - m_lower >= pi_twice) {
// If the input width is bigger than 2pi,
// it covers whole domain and gets [-1.0, 1.0]
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
if (m_lower >= numeric_traits<T>::pi_upper()) {
// If the input is bigger than pi, we handle it recursively by the fact:
// cos(x) = -cos(x - pi)
if (compute_intv) {
*this -= interval<T>(numeric_traits<T>::pi_lower(), numeric_traits<T>::pi_upper());
}
cos<compute_intv, compute_deps>(deps);
neg<compute_intv, false>();
lean_assert(check_invariant());
return;
}
if (m_upper <= numeric_traits<T>::pi_lower()) {
// 0 <= l <= u <= pi
// cos([l, u]) = [cos_d(u), cos_u(l)]
if (compute_intv) {
std::swap(m_lower, m_upper);
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::cos(m_lower);
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cos(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_upper <= numeric_traits<T>::pi_twice_lower()) {
// If the input is [a, b] and a <= pi <= b,
// Pick the tmp = min(a, 2pi - b) and return [-1, cos(tmp)]
if (m_lower + m_upper < numeric_traits<T>::pi_twice()) {
if (compute_intv) {
m_upper = m_lower;
}
} else {
// Nothing
}
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cos(m_upper);
m_lower = -1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (compute_intv) {
m_lower = -1.0;
m_upper = 1.0;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::tan(interval_deps & deps) {
if (m_lower_inf || m_upper_inf) {
// tan([-oo, c]) = [-oo, +oo]
// tan([c, +oo]) = [-oo, +oo]
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
T const pi_half_lower = numeric_traits<T>::pi_half_lower();
fmod(interval<T>(numeric_traits<T>::pi_lower(), numeric_traits<T>::pi_upper()));
if (m_lower >= pi_half_lower) {
*this -= interval<T>(numeric_traits<T>::pi_lower(), numeric_traits<T>::pi_upper());
}
if (m_lower <= - pi_half_lower || m_upper >= pi_half_lower) {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::tan(m_lower);
m_lower = -m_lower;
numeric_traits<T>::tan(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::csc (interval_deps & deps) {
static thread_local T l;
static thread_local T u;
if (compute_intv) {
l = m_lower;
u = m_upper;
}
// csc(x) = 1 / sin(x)
if (m_lower_inf || m_upper_inf || (m_upper - m_lower > numeric_traits<T>::pi())) {
// csc([-oo, c]) = [-oo, +oo]
// csc([c, +oo]) = [-oo, +oo]
// if the width is bigger than pi, then the result is [-oo, +oo]
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
T const pi_half = numeric_traits<T>::pi_half();
T const pi = numeric_traits<T>::pi();
fmod(interval<T>(numeric_traits<T>::pi_twice_lower(), numeric_traits<T>::pi_twice_upper()));
if (m_upper > numeric_traits<T>::pi_twice() ||
(m_lower < pi && pi < m_upper)) {
// l < 2pi < u or l < pi < u
// then the result = [-oo, +oo]
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
if (m_lower <= pi_half) {
if (m_upper <= pi_half) {
// l <= u <= 1/2 pi
// csc[l, u] = [csc(u), csc(l)]
// = [-csc(-u), csc(l)]
if (compute_intv) {
m_lower = -u;
m_upper = l;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_lower);
numeric_traits<T>::csc(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_upper <= pi) {
// l <= 1/2 pi <= u <= pi
// csc[l, u] = [1, max(csc(l), csc(u))]
// = [1, csc(l)] if l + u <= pi
// = [1, csc(u)] if l + u >= pi
if (m_lower + m_upper < pi) {
if (compute_intv) {
m_upper = l;
}
} else {
// Nothing
if (compute_intv) {
m_upper = u;
}
}
if (compute_intv) {
m_lower = 1.0;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
lean_unreachable(); // LCOV_EXCL_LINE
}
if (m_lower <= pi && m_upper <= pi) {
// l <= u <= pi
// csc[l, u] = [csc(l), csc(u)]
// = [-csc(-l), csc(u)]
if (compute_intv) {
m_lower = -l;
m_upper = u;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_lower);
numeric_traits<T>::csc(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (m_lower <= pi + pi_half) {
if (m_upper <= pi + pi_half) {
// l <= u <= 3/2 pi
// csc[l, u] = [csc(l), csc(u)]
// = [-csc(-l), csc(u)]
if (compute_intv) {
m_lower = -l;
m_upper = u;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_lower);
numeric_traits<T>::csc(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
// l <= 3/2 pi <= u <= 2pi
// csc[l, u] = [min(csc(l), csc(u)), -1]
// = [csc(l), -1] if l + u <= 3pi
// = [csc(u), -1] if l + u >= 3pi
//
// = [-csc(-l), -1] if l + u <= 3pi
// = [-csc(-u), -1] if l + u >= 3pi
if (m_lower + m_upper < pi + numeric_traits<T>::pi_twice()) {
// Nothing
if (compute_intv) {
m_lower = -l;
}
} else {
if (compute_intv) {
m_lower = -u;
}
}
if (compute_intv) {
m_upper = -1.0;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_lower);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = 0;
}
return;
}
// 3/2pi <= l <= u < 2pi
// csc[l, u] = [csc(u), csc(l)]
// = [-csc(-u), csc(l)]
if (compute_intv) {
m_lower = -u;
m_upper = l;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::csc(m_lower);
numeric_traits<T>::csc(m_upper);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::sec (interval_deps & deps) {
if (compute_intv) {
*this += interval<T>(numeric_traits<T>::pi_half_lower(), numeric_traits<T>::pi_half_upper());
}
csc<compute_intv, compute_deps>(deps);
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::cot (interval_deps & deps) {
static thread_local T l;
static thread_local T u;
if (compute_intv) {
l = m_lower;
u = m_upper;
}
if (m_lower_inf || m_upper_inf) {
// cot([-oo, c]) = [-oo, +oo]
// cot([c, +oo]) = [-oo, +oo]
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
fmod(interval<T>(numeric_traits<T>::pi_lower(), numeric_traits<T>::pi_upper()));
if (m_upper >= numeric_traits<T>::pi()) {
if (compute_intv) {
numeric_traits<T>::reset(m_lower);
numeric_traits<T>::reset(m_upper);
m_lower_open = m_upper_open = true;
m_lower_inf = m_upper_inf = true;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
// cot([l, u]) = [cot_d(u), cot_u(l)]
// = [-cot_u(-u), cot_u(l)]
if (compute_intv) {
m_lower = - u;
m_upper = l;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cot(m_lower);
numeric_traits<T>::cot(m_upper);
m_lower = - m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::asin (interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL && upper_kind() == XN_NUMERAL);
lean_assert(-1.0 <= m_lower && m_upper <= 1.0);
// aisn([l, u]) = [asin_d(l), asin_u(u)]
// = [-asin_u(-l), asin_u(u)]
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::asin(m_upper);
m_lower = -m_lower;
numeric_traits<T>::asin(m_lower);
m_lower = -m_lower;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
deps.m_upper_deps = DEP_IN_UPPER1;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::acos (interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL && upper_kind() == XN_NUMERAL);
lean_assert(-1.0 <= m_lower && m_upper <= 1.0);
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::acos(m_lower);
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::acos(m_upper);
std::swap(m_lower, m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::atan (interval_deps & deps) {
if (lower_kind() == XN_MINUS_INFINITY) {
if (compute_intv) {
m_lower = -1.0;
m_lower_open = false;
m_lower_inf = false;
}
if (compute_deps) {
deps.m_lower_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::atan(m_lower);
m_lower = -m_lower;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (upper_kind() == XN_MINUS_INFINITY) {
if (compute_intv) {
m_upper = 1.0;
m_upper_open = false;
m_upper_inf = false;
}
if (compute_deps) {
deps.m_upper_deps = 0;
}
} else {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::atan(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::sinh (interval_deps & deps) {
if (lower_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::sinh(m_lower);
m_lower = -m_lower;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (upper_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::sinh(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::cosh (interval_deps & deps) {
if (lower_kind() == XN_NUMERAL && upper_kind() == XN_NUMERAL) {
if (numeric_traits<T>::is_pos(m_lower) || numeric_traits<T>::is_zero(m_lower)) {
// [a, b] where 0 <= a <= b
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::cosh(m_lower);
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cosh(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
// cos([a, b]) = [cosh(a), cos(b)]
deps.m_lower_deps = DEP_IN_LOWER1;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (numeric_traits<T>::is_neg(m_upper) || numeric_traits<T>::is_zero(m_upper)) {
// [a, b] where a <= b < 0
if (compute_intv) {
std::swap(m_lower, m_upper);
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::cosh(m_lower);
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cosh(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
deps.m_upper_deps = DEP_IN_LOWER1;
}
return;
}
// [a, b] where a < 0 < b
if (m_lower + m_upper < 0.0) {
if (compute_intv) {
m_upper = m_lower;
}
} else {
// Nothing
}
if (compute_intv) {
m_lower = 1.0;
m_lower_open = false;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::cosh(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_upper_deps = 0;
deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER1;
}
return;
}
if (lower_kind() == XN_NUMERAL) {
// [c, +oo]
lean_assert(upper_kind() == XN_PLUS_INFINITY);
if (numeric_traits<T>::is_pos(m_lower)) {
// [c, +oo] where 0 < c < +oo
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::cosh(m_lower);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
deps.m_upper_deps = 0;
}
return;
} else {
// [c, +oo] where c <= 0 < +oo
if (compute_intv) {
m_lower = 1.0;
m_lower_open = false;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
}
}
if (upper_kind() == XN_NUMERAL) {
// [-oo, c]
lean_assert(lower_kind() == XN_MINUS_INFINITY);
if (compute_intv) {
m_upper_inf = true;
m_upper_open = true;
}
if (numeric_traits<T>::is_pos(m_upper)) {
// [-oo, c] where -oo < 0 < c
if (compute_intv) {
m_lower = 1.0;
m_lower_open = false;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
return;
} else {
// [-oo, c] where -oo < c <= 0
if (compute_intv) {
m_lower = m_upper;
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::cosh(m_lower);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_UPPER1;
deps.m_upper_deps = 0;
}
return;
}
}
lean_assert(lower_kind() == XN_MINUS_INFINITY && upper_kind() == XN_PLUS_INFINITY);
// cosh((-oo, +oo)) = [1.0, +oo)
if (compute_intv) {
m_upper_open = true;
m_upper_inf = true;
m_lower = 1.0;
m_lower_open = false;
m_lower_inf = false;
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = 0;
deps.m_upper_deps = 0;
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::tanh (interval_deps & deps) {
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
if (lower_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::tanh(m_lower);
m_lower = -m_lower;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (upper_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::tanh(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::asinh(interval_deps & deps) {
if (compute_deps) {
deps.m_lower_deps = deps.m_upper_deps = 0;
}
if (lower_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::asinh(m_lower);
m_lower = -m_lower;
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
}
if (upper_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::asinh(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::acosh(interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL && m_lower >= 1.0);
if (compute_intv) {
numeric_traits<T>::set_rounding(false);
numeric_traits<T>::acosh(m_lower);
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
}
if (upper_kind() == XN_NUMERAL) {
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::acosh(m_upper);
}
if (compute_deps) {
deps.m_upper_deps = DEP_IN_UPPER1;
}
} else {
// upper_kind() == +oo
if (compute_deps) {
deps.m_upper_deps = 0;
}
}
if (compute_intv) {
lean_assert(check_invariant());
}
return;
}
template<typename T>
template<bool compute_intv, bool compute_deps>
void interval<T>::atanh(interval_deps & deps) {
lean_assert(lower_kind() == XN_NUMERAL && m_lower >= -1.0);
lean_assert(upper_kind() == XN_NUMERAL && m_upper <= 1.0);
if (compute_intv) {
numeric_traits<T>::set_rounding(true);
m_lower = -m_lower;
numeric_traits<T>::atanh(m_lower);
m_lower = -m_lower;
numeric_traits<T>::set_rounding(true);
numeric_traits<T>::atanh(m_upper);
lean_assert(check_invariant());
}
if (compute_deps) {
deps.m_lower_deps = DEP_IN_LOWER1;
deps.m_upper_deps = DEP_IN_UPPER1;
}
return;
}
template<typename T> void interval<T>::exp_jst(interval_deps & deps) {
exp<false, true>(deps);
return;
}
template<typename T> void interval<T>::exp2_jst(interval_deps & deps) {
exp2<false, true>(deps);
return;
}
template<typename T> void interval<T>::exp10_jst(interval_deps & deps) {
exp10<false, true>(deps);
return;
}
template<typename T> void interval<T>::log_jst(interval_deps & deps) {
log<false, true>(deps);
return;
}
template<typename T> void interval<T>::log2_jst(interval_deps & deps) {
log2<false, true>(deps);
return;
}
template<typename T> void interval<T>::log10_jst(interval_deps & deps) {
log10<false, true>(deps);
return;
}
template<typename T> void interval<T>::sin_jst(interval_deps & deps) {
sin<false, true>(deps);
return;
}
template<typename T> void interval<T>::cos_jst(interval_deps & deps) {
cos<false, true>(deps);
return;
}
template<typename T> void interval<T>::tan_jst(interval_deps & deps) {
tan<false, true>(deps);
return;
}
template<typename T> void interval<T>::csc_jst(interval_deps & deps) {
csc<false, true>(deps);
return;
}
template<typename T> void interval<T>::sec_jst(interval_deps & deps) {
sec<false, true>(deps);
return;
}
template<typename T> void interval<T>::cot_jst(interval_deps & deps) {
cot<false, true>(deps);
return;
}
template<typename T> void interval<T>::asin_jst(interval_deps & deps) {
asin<false, true>(deps);
return;
}
template<typename T> void interval<T>::acos_jst(interval_deps & deps) {
acos<false, true>(deps);
return;
}
template<typename T> void interval<T>::atan_jst(interval_deps & deps) {
atan<false, true>(deps);
return;
}
template<typename T> void interval<T>::sinh_jst(interval_deps & deps) {
sinh<false, true>(deps);
return;
}
template<typename T> void interval<T>::cosh_jst(interval_deps & deps) {
cosh<false, true>(deps);
return;
}
template<typename T> void interval<T>::tanh_jst(interval_deps & deps) {
tanh<false, true>(deps);
return;
}
template<typename T> void interval<T>::asinh_jst(interval_deps & deps) {
asinh<false, true>(deps);
return;
}
template<typename T> void interval<T>::acosh_jst(interval_deps & deps) {
acosh<false, true>(deps);
return;
}
template<typename T> void interval<T>::atanh_jst(interval_deps & deps) {
atanh<false, true>(deps);
return;
}
}