b2/core/test/classes/fundamentals_test.cpp
2025-01-14 01:15:53 +01:00

579 lines
12 KiB
C++

//This file is part of Bertini 2.
//
//fundamentals_test.cpp is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//fundamentals_test.cpp is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with fundamentals_test.cpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
//
// See <http://www.gnu.org/licenses/> for a copy of the license,
// as well as COPYING. Bertini2 is provided with permitted
// additional terms in the b2/licenses/ directory.
// individual authors of this file include:
// silviana amethyst, university of wisconsin eau claire
#include <boost/test/unit_test.hpp>
#include <boost/multiprecision/mpfr.hpp>
#include <iostream>
#include "bertini2/double_extensions.hpp"
#include "bertini2/num_traits.hpp"
BOOST_AUTO_TEST_SUITE(super_fundamentals)
using mpfr_float = bertini::mpfr_float;
using mpq_rational = bertini::mpq_rational;
using dbl = bertini::dbl;
using bertini::DefaultPrecision;
#include <limits>
BOOST_AUTO_TEST_CASE(complex_pow)
{
auto x = bertini::rand_complex();
using bertini::pow;
BOOST_CHECK_EQUAL(pow(x, 2), x*x);
}
BOOST_AUTO_TEST_CASE(complex_pow_on_real_stays_real)
{
using bertini::pow;
for (int ii=0; ii<100; ++ii)
{
auto x = dbl(bertini::RandReal());
auto result = pow(x, 2);
BOOST_CHECK_EQUAL(result, x*x);
BOOST_CHECK_EQUAL(imag(result), 0);
}
}
BOOST_AUTO_TEST_CASE(complex_double_nans)
{
dbl x(0., std::numeric_limits<double>::quiet_NaN());
using bertini::isnan;
BOOST_CHECK(isnan(x));
}
BOOST_AUTO_TEST_CASE(complex_double_nans2)
{
dbl x(std::numeric_limits<double>::quiet_NaN(), 0.);
using bertini::isnan;
BOOST_CHECK(isnan(x));
}
BOOST_AUTO_TEST_CASE(complex_double_nans3)
{
dbl x(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN());
using bertini::isnan;
BOOST_CHECK(isnan(x));
}
BOOST_AUTO_TEST_CASE(complex_double_nans4)
{
dbl x(0., 0.);
using bertini::isnan;
BOOST_CHECK(!isnan(x));
}
BOOST_AUTO_TEST_CASE(complex_double_random_subsequent_not_equal)
{
using T = dbl;
auto x = bertini::RandomUnit<T>();
auto y = bertini::RandomUnit<T>();
BOOST_CHECK(x!=y);
}
BOOST_AUTO_TEST_CASE(mpfr_float_can_be_nan)
{
DefaultPrecision(50);
mpfr_float a(std::numeric_limits<double>::quiet_NaN());
BOOST_CHECK(isnan(a));
}
BOOST_AUTO_TEST_CASE(constructing_mpfr_from_double)
{
DefaultPrecision(50);
mpfr_float from_double(0.1);
mpfr_float from_string("0.1");
BOOST_CHECK(abs(from_string - from_double) < std::numeric_limits<double>::epsilon());
}
BOOST_AUTO_TEST_CASE(construct_rational_from_integers)
{
mpq_rational p(1,2);
mpq_rational q(-1,2);
BOOST_CHECK_EQUAL(p+q, mpq_rational(0));
}
// commented out code below checks construction of mpq_rationals from other types. they're broken. :(
// BOOST_AUTO_TEST_CASE(construct_rational_from_mpfr)
// {
// DefaultPrecision(50);
// mpfr_float p("1.1");
// mpq_rational q(p);
// BOOST_CHECK_EQUAL(mpq_rational(11,10), q);
// }
// BOOST_AUTO_TEST_CASE(construct_rational_from_string)
// {
// mpq_rational q("1.1");
// BOOST_CHECK_EQUAL(mpq_rational(11,10), q);
// }
// this commented out test will fail... because of mixed precision arithmetic
// BOOST_AUTO_TEST_CASE(multiple_mpfr_by_double)
// {
// DefaultPrecision(50);
// mpfr_float a("0.1");
// double factor = 0.1;
// mpfr_float result = a*factor;
// mpfr_float expected("0.01");
// BOOST_CHECK_CLOSE(expected, result, 1e-50);
// }
BOOST_AUTO_TEST_CASE(making_mpfr_from_pow_int_base)
{
DefaultPrecision(50);
mpfr_float result = pow(mpfr_float(10), -5);
mpfr_float expected("1e-5");
BOOST_CHECK_CLOSE(expected, result, 1e-50);
}
BOOST_AUTO_TEST_CASE(making_mpfr_from_pow_str_base)
{
DefaultPrecision(50);
mpfr_float result = pow(mpfr_float("10"), -5);
mpfr_float expected("1e-5");
BOOST_CHECK_CLOSE(expected, result, 1e-50);
}
BOOST_AUTO_TEST_CASE(making_mpfr_from_pow_doub_exp)
{
DefaultPrecision(50);
using boost::multiprecision::pow;
mpfr_float result = pow(mpfr_float(10), -5);
mpfr_float expected("1e-5");
BOOST_CHECK_CLOSE(expected, result, 1e-50);
}
BOOST_AUTO_TEST_CASE(making_mpfr_from_pow_int_base_mpfr_exp)
{
DefaultPrecision(50);
mpfr_float result = pow(10, mpfr_float(-5));
mpfr_float expected("1e-5");
BOOST_CHECK_CLOSE(expected, result, 1e-50);
}
BOOST_AUTO_TEST_CASE(make_rational_from_double)
{
mpq_rational result(0.1);
mpq_rational expected(1,10);
BOOST_CHECK_CLOSE(result, expected, 1e-16);
}
BOOST_AUTO_TEST_CASE(make_random_mpfr_float_50)
{
using mpfr_50 = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<50>, boost::multiprecision::et_off>;
using namespace boost::multiprecision;
using namespace boost::random;
DefaultPrecision(50);
uniform_real_distribution<mpfr_50> ur(0,1);
independent_bits_engine<mt19937, 50L*1000L/301L, mpz_int> gen;
auto c = ur(gen);
mpfr_50 r(c);
mpfr_50 s(ur(gen));
}
BOOST_AUTO_TEST_CASE(make_random_mpfr_float_100)
{
using mpfr_100 = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<100>, boost::multiprecision::et_off>;
using namespace boost::multiprecision;
using namespace boost::random;
DefaultPrecision(100);
uniform_real_distribution<mpfr_100> ur(0,1);
independent_bits_engine<mt19937, 100L*1000L/301L, mpz_int> gen;
auto c = ur(gen);
mpfr_100 r(c);
mpfr_100 s(ur(gen));
}
BOOST_AUTO_TEST_CASE(RandomMP_default_precision_50)
{
using namespace bertini;
DefaultPrecision(50);
auto a = RandomMp(mpfr_float(-1),mpfr_float(1));
BOOST_CHECK_EQUAL(a.precision(), DefaultPrecision());
BOOST_CHECK_EQUAL(50, DefaultPrecision());
}
BOOST_AUTO_TEST_CASE(RandomMP_default_precision_100)
{
using namespace bertini;
DefaultPrecision(100);
auto a = RandomMp(mpfr_float(-1),mpfr_float(1));
BOOST_CHECK_EQUAL(a.precision(), DefaultPrecision());
BOOST_CHECK_EQUAL(100, DefaultPrecision());
}
BOOST_AUTO_TEST_CASE(RandomMP_nondefault_precision_100)
{
using namespace bertini;
DefaultPrecision(100);
mpfr_float a;
RandomMpAssign(a,500);
BOOST_CHECK_EQUAL(a.precision(), 500);
BOOST_CHECK_EQUAL(100, DefaultPrecision());
}
BOOST_AUTO_TEST_CASE(max_et_on)
{
mpfr_float a(1), b(2), c(4);
// auto d = max(a,b*b+c);
}
struct scoped_mpfr_precision_options_all_threads
{
boost::multiprecision::variable_precision_options saved_options;
scoped_mpfr_precision_options_all_threads(boost::multiprecision::variable_precision_options opts) : saved_options(mpfr_float::default_variable_precision_options())
{
mpfr_float::default_variable_precision_options(opts);
}
~scoped_mpfr_precision_options_all_threads()
{
mpfr_float::default_variable_precision_options(saved_options);
}
void reset(boost::multiprecision::variable_precision_options opts)
{
mpfr_float::default_variable_precision_options(opts);
}
};
struct scoped_mpfr_precision_options_this_thread
{
boost::multiprecision::variable_precision_options saved_options;
scoped_mpfr_precision_options_this_thread(boost::multiprecision::variable_precision_options opts) : saved_options(mpfr_float::thread_default_variable_precision_options())
{
mpfr_float::thread_default_variable_precision_options(opts);
}
~scoped_mpfr_precision_options_this_thread()
{
mpfr_float::thread_default_variable_precision_options(saved_options);
}
void reset(boost::multiprecision::variable_precision_options opts)
{
mpfr_float::thread_default_variable_precision_options(opts);
}
};
BOOST_AUTO_TEST_CASE(precision_through_arithemetic)
{
DefaultPrecision(50);
scoped_mpfr_precision_options_this_thread scoped_opts1(boost::multiprecision::variable_precision_options::preserve_related_precision);
mpfr_float x("0.01234567890123456789012345678901234567890123456789");
BOOST_CHECK_EQUAL(x.precision(), 50);
// https://github.com/boostorg/multiprecision/issues/60
//
// "Copying or move-assignment copies the precision of the source.
// Assignment keeps the precision of the target."
DefaultPrecision(30);
mpfr_float y = pow(x,2);
BOOST_CHECK_EQUAL(y.precision(), 50);
mpfr_float z = x;
mpfr_float q(x);
BOOST_CHECK_EQUAL(z.precision(), 50);
BOOST_CHECK_EQUAL(q.precision(), 50);
BOOST_CHECK(fabs(z - x) < 1e-50);
DefaultPrecision(70);
z = x;
BOOST_CHECK_EQUAL(z.precision(),50);
BOOST_CHECK(fabs(z - x) < 1e-50);
y.precision(70);
z.precision(30);
BOOST_CHECK_EQUAL(y.precision(),70);
BOOST_CHECK_EQUAL(z.precision(),30);
BOOST_CHECK_EQUAL(x.precision(),50);
scoped_mpfr_precision_options_this_thread scoped_opts2(boost::multiprecision::variable_precision_options::preserve_target_precision);
y = z*x;
BOOST_CHECK_EQUAL(z.precision(),30);
BOOST_CHECK_EQUAL(x.precision(),50);
BOOST_CHECK_EQUAL(y.precision(), 70);
}
BOOST_AUTO_TEST_CASE(precision_in_construction)
{
DefaultPrecision(50);
mpfr_float x("0.01234567890123456789012345678901234567890123456789");
BOOST_CHECK_EQUAL(x.precision(), 50);
DefaultPrecision(30);
mpfr_float a = x;
mpfr_float b(x);
BOOST_CHECK_EQUAL(a.precision(), 50);
BOOST_CHECK_EQUAL(b.precision(), 50);
BOOST_CHECK_EQUAL(a,x);
BOOST_CHECK_EQUAL(b,x);
DefaultPrecision(70);
mpfr_float c = x;
mpfr_float d(x);
BOOST_CHECK_EQUAL(c.precision(), 50);
BOOST_CHECK_EQUAL(d.precision(), 50);
BOOST_CHECK_EQUAL(c,x);
BOOST_CHECK_EQUAL(d,x);
}
BOOST_AUTO_TEST_CASE(precision_through_arithemetic2)
{
DefaultPrecision(50);
mpfr_float a(1);
DefaultPrecision(400);
mpfr_float b(2);
DefaultPrecision(600);
mpfr_float c(3);
a = b;
BOOST_CHECK_EQUAL(a.precision(),400); // the precision of source
a = b+c;
BOOST_CHECK_EQUAL(a.precision(),600); // the bigger of 400,600 is 600
}
BOOST_AUTO_TEST_CASE(precision_mpfr_constructed_from_string)
{
DefaultPrecision(30);
mpfr_float x("0.01234567890123456789012345678901234567890123456789");
BOOST_CHECK_EQUAL(x.precision(),30);
}
BOOST_AUTO_TEST_CASE(precision_of_double_is_16)
{
double a(1.23124);
BOOST_CHECK_EQUAL(bertini::Precision(a), 16);
}
BOOST_AUTO_TEST_CASE(precision_of_complex_double_is_16)
{
std::complex<double> a(1.23124, -0.12345679);
BOOST_CHECK_EQUAL(bertini::Precision(a), 16);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(numtraits)
using bertini::DefaultPrecision;
template<typename T>
using NumTraits = bertini::NumTraits<T>;
BOOST_AUTO_TEST_CASE(num_digits_double)
{
using T = double;
DefaultPrecision(16);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(30);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(100);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
}
BOOST_AUTO_TEST_CASE(num_digits_complex_double)
{
using T = std::complex<double>;
DefaultPrecision(16);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(30);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(100);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
}
BOOST_AUTO_TEST_CASE(num_digits_mpfr_float)
{
using T = bertini::mpfr_float;
DefaultPrecision(16);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(30);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 30);
DefaultPrecision(100);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 100);
}
BOOST_AUTO_TEST_CASE(num_digits_mpfr_complex)
{
using T = bertini::mpfr_complex;
DefaultPrecision(16);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 16);
DefaultPrecision(30);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 30);
DefaultPrecision(100);
BOOST_CHECK_EQUAL(NumTraits<T>::NumDigits(), 100);
}
BOOST_AUTO_TEST_SUITE_END() // numtraits tests