//This file is part of Bertini 2.
//
//start_system_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.
//
//start_system_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 start_system_test.cpp. If not, see .
//
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
//
// See 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
#include "bertini2/system/start_systems.hpp"
#include "externs.hpp"
BOOST_AUTO_TEST_SUITE(system_class)
using bertini::DefaultPrecision;
using System = bertini::System;
using Variable = bertini::node::Variable;
using Var = std::shared_ptr;
using VariableGroup = bertini::VariableGroup;
using mpq_rational = bertini::mpq_rational;
using mpfr_float = bertini::mpfr_float;
using mpz_int = bertini::mpz_int;
using dbl = bertini::dbl;
using mpfr = bertini::mpfr_complex;
template using Vec = bertini::Vec;
template using Mat = bertini::Mat;
BOOST_AUTO_TEST_CASE(index_and_subscript_generation1)
{
std::vector dimensions{2,2};
std::vector v;
std::vector solution{0,0};
v = bertini::IndexToSubscript(0ul,dimensions);
BOOST_CHECK(v==solution);
solution[0] = 1; solution[1] = 0;
v = bertini::IndexToSubscript(1ul,dimensions);
BOOST_CHECK(v==solution);
solution[0] = 0; solution[1] = 1;
v = bertini::IndexToSubscript(2ul,dimensions);
BOOST_CHECK(v==solution);
solution[0] = 1; solution[1] = 1;
v = bertini::IndexToSubscript(3ul,dimensions);
BOOST_CHECK(v==solution);
}
BOOST_AUTO_TEST_CASE(index_and_subscript_generation2)
{
size_t index = 20;
std::vector dimensions{2,3,4,5};
std::vector v = bertini::IndexToSubscript(index,dimensions);
std::vector solution{0,1,3,0};
BOOST_CHECK(v==solution);
}
BOOST_AUTO_TEST_CASE(index_and_subscript_generation3)
{
size_t index = 119;
std::vector dimensions{2,3,4,5};
std::vector v = bertini::IndexToSubscript(index,dimensions);
std::vector solution{1,2,3,4};
BOOST_CHECK(v==solution);
}
BOOST_AUTO_TEST_CASE(index_and_subscript_generation_out_of_range)
{
std::vector dimensions{2,3,4,5};
BOOST_CHECK_THROW(bertini::IndexToSubscript(120ul,dimensions),std::out_of_range);
}
BOOST_AUTO_TEST_CASE(make_total_degree_system_linear)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y");
VariableGroup v;
v.push_back(x); v.push_back(y);
sys.AddVariableGroup(v);
sys.AddFunction(x + y - 1);
sys.AddFunction(x - mpfr_float("0.5")*y - 1);
bertini::start_system::TotalDegree TD(sys);
auto d = TD.Degrees();
BOOST_CHECK_EQUAL(d.size(),2);
if (d.size()==2)
{
BOOST_CHECK_EQUAL(d[0],1);
BOOST_CHECK_EQUAL(d[1],1);
}
BOOST_CHECK_EQUAL(TD.NumVariables(),2);
BOOST_CHECK_EQUAL(TD.NumStartPoints(), 1);
}
BOOST_AUTO_TEST_CASE(make_total_degree_system_quadratic)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y");
VariableGroup v;
v.push_back(x); v.push_back(y);
sys.AddVariableGroup(v);
sys.AddFunction(x*y + y - 1);
sys.AddFunction(x*x - mpfr_float("0.5")*y - x*y);
bertini::start_system::TotalDegree TD(sys);
auto d = TD.Degrees();
BOOST_CHECK_EQUAL(TD.NumVariables(),2);
BOOST_CHECK_EQUAL(d.size(),2);
if (d.size()==2)
{
BOOST_CHECK_EQUAL(d[0],2);
BOOST_CHECK_EQUAL(d[1],2);
}
BOOST_CHECK_EQUAL(TD.NumVariables(),2);
BOOST_CHECK_EQUAL(TD.NumStartPoints(), 4);
}
BOOST_AUTO_TEST_CASE(linear_total_degree_start_system)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y");
VariableGroup vars{x,y};
sys.AddVariableGroup(vars);
sys.AddFunction(y+1);
sys.AddFunction(x+y+bertini::node::Pi());
bertini::start_system::TotalDegree TD(sys);
auto deg = TD.Degrees();
BOOST_CHECK_EQUAL(TD.NumVariables(),2);
BOOST_CHECK(!TD.IsPatched());
BOOST_CHECK_EQUAL(deg.size(),2);
BOOST_CHECK_EQUAL(deg[0],1);
BOOST_CHECK_EQUAL(deg[1],1);
VariableGroup variable_ordering = TD.Variables();
BOOST_CHECK_EQUAL(variable_ordering.size(), 2);
Vec vals(2);
vals << dbl(1.0),dbl(1.0);
auto sysvals = TD.Eval(vals);
for (unsigned ii = 0; ii < 2; ++ii)
BOOST_CHECK( abs(sysvals(ii) - (1.0 - TD.RandomValue(ii))) < threshold_clearance_d);
auto J = TD.Jacobian(vals);
BOOST_CHECK_EQUAL(J(0,0),1.0);
BOOST_CHECK_EQUAL(J(0,1),0.0);
BOOST_CHECK_EQUAL(J(1,0),0.0);
BOOST_CHECK_EQUAL(J(1,1),1.0);
vals << dbl(0.0),dbl(0.0);
sysvals = TD.Eval(vals);
for (unsigned ii = 0; ii < 2; ++ii)
BOOST_CHECK(abs(sysvals(ii)+TD.RandomValue(ii)) < threshold_clearance_d);
J = TD.Jacobian(vals);
BOOST_CHECK_EQUAL(J(0,0),1.0);
BOOST_CHECK_EQUAL(J(0,1),0.0);
BOOST_CHECK_EQUAL(J(1,0),0.0);
BOOST_CHECK_EQUAL(J(1,1),1.0);
BOOST_CHECK_EQUAL(TD.NumStartPoints(), 1);
}
BOOST_AUTO_TEST_CASE(quadratic_cubic_quartic_total_degree_start_system)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y"), z = Variable::Make("z");
VariableGroup vars;
vars.push_back(x); vars.push_back(y); vars.push_back(z);
sys.AddVariableGroup(vars);
sys.AddFunction(y+x*y + mpfr_float("0.5"));
sys.AddFunction(pow(x,3)+x*y+bertini::node::E());
sys.AddFunction(pow(x,2)*pow(y,2)+x*y*z*z - 1);
bertini::start_system::TotalDegree TD(sys);
auto deg = TD.Degrees();
BOOST_CHECK_EQUAL(deg.size(),3);
if (deg.size()==3)
{
BOOST_CHECK_EQUAL(deg[0],2);
BOOST_CHECK_EQUAL(deg[1],3);
BOOST_CHECK_EQUAL(deg[2],4);
}
Vec vals(3);
vals << dbl(1.0),dbl(1.0),dbl(1.0);
auto sysvals = TD.Eval(vals);
for (unsigned ii = 0; ii < 3; ++ii)
BOOST_CHECK( abs(sysvals(ii) - (1.0 - TD.RandomValue(ii))) < threshold_clearance_d);
auto J = TD.Jacobian(vals);
BOOST_CHECK_EQUAL(J(0,0),2.0);
BOOST_CHECK_EQUAL(J(0,1),0.0);
BOOST_CHECK_EQUAL(J(0,2),0.0);
BOOST_CHECK_EQUAL(J(1,0),0.0);
BOOST_CHECK_EQUAL(J(1,1),3.0);
BOOST_CHECK_EQUAL(J(1,2),0.0);
BOOST_CHECK_EQUAL(J(2,0),0.0);
BOOST_CHECK_EQUAL(J(2,1),0.0);
BOOST_CHECK_EQUAL(J(2,2),4.0);
vals << dbl(0.0),dbl(0.0),dbl(0.0);
sysvals = TD.Eval(vals);
for (unsigned ii = 0; ii < 3; ++ii)
BOOST_CHECK(abs(sysvals(ii)+TD.RandomValue(ii)) < threshold_clearance_d);
J = TD.Jacobian(vals);
BOOST_CHECK_EQUAL(J(0,0),0.0);
BOOST_CHECK_EQUAL(J(0,1),0.0);
BOOST_CHECK_EQUAL(J(0,2),0.0);
BOOST_CHECK_EQUAL(J(1,0),0.0);
BOOST_CHECK_EQUAL(J(1,1),0.0);
BOOST_CHECK_EQUAL(J(1,2),0.0);
BOOST_CHECK_EQUAL(J(2,0),0.0);
BOOST_CHECK_EQUAL(J(2,1),0.0);
BOOST_CHECK_EQUAL(J(2,2),0.0);
BOOST_CHECK_EQUAL(TD.NumStartPoints(), 24);
}
BOOST_AUTO_TEST_CASE(quadratic_cubic_quartic_start_points)
{
bertini::DefaultPrecision(CLASS_TEST_MPFR_DEFAULT_DIGITS);
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y"), z = Variable::Make("z");
VariableGroup vars{x,y,z};
sys.AddVariableGroup(vars);
sys.AddFunction(y+x*y + mpfr_float("0.5"));
sys.AddFunction(pow(x,3)+x*y+bertini::node::E());
sys.AddFunction(pow(x,2)*pow(y,2)+x*y*z*z - 1);
bertini::start_system::TotalDegree TD(sys);
for (decltype(TD.NumStartPoints()) ii = 0; ii < TD.NumStartPoints(); ++ii)
{
auto start = TD.StartPoint(ii);
auto function_values = TD.Eval(start);
const auto& vs = TD.RandomValues();
for (decltype(function_values.size()) jj = 0; jj < function_values.size(); ++jj)
BOOST_CHECK(abs(function_values(jj)) <
abs(vs[jj]->Eval())*relaxed_threshold_clearance_d);
}
for (decltype(TD.NumStartPoints()) ii = 0; ii < TD.NumStartPoints(); ++ii)
{
auto start = TD.StartPoint(ii);
BOOST_CHECK_EQUAL(bertini::Precision(start), CLASS_TEST_MPFR_DEFAULT_DIGITS);
auto function_values = TD.Eval(start);
for (decltype(function_values.size()) jj = 0; jj < function_values.size(); ++jj)
{
BOOST_CHECK(abs(function_values(jj)) < threshold_clearance_mp);
}
}
}
// this one differs from the above only in that the target system was homogenized and patched
BOOST_AUTO_TEST_CASE(quadratic_cubic_quartic_start_points_homogenized_patched)
{
bertini::DefaultPrecision(CLASS_TEST_MPFR_DEFAULT_DIGITS);
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y"), z = Variable::Make("z");
VariableGroup vars{x,y,z};
sys.AddVariableGroup(vars);
sys.AddFunction(y+x*y + mpfr_float("0.5"));
sys.AddFunction(pow(x,3)+x*y+bertini::node::E());
sys.AddFunction(pow(x,2)*pow(y,2)+x*y*z*z - 1);
sys.Homogenize();
sys.AutoPatch();
bertini::start_system::TotalDegree TD(sys);
TD.Homogenize();
BOOST_CHECK(TD.IsHomogeneous());
BOOST_CHECK(TD.IsPatched());
// generate each start point, and
// evaluate the start system at that point.
//
// the function values must be near 0
for (decltype(TD.NumStartPoints()) ii = 0; ii < TD.NumStartPoints(); ++ii)
{
auto start = TD.StartPoint(ii);
auto function_values = TD.Eval(start);
for (decltype(function_values.size()) jj = 0; jj < function_values.size(); ++jj)
BOOST_CHECK(abs(function_values(jj)) <
1000*relaxed_threshold_clearance_d);
}
for (decltype(TD.NumStartPoints()) ii = 0; ii < TD.NumStartPoints(); ++ii)
{
auto start = TD.StartPoint(ii);
BOOST_CHECK_EQUAL(bertini::Precision(start), CLASS_TEST_MPFR_DEFAULT_DIGITS);
auto function_values = TD.Eval(start);
for (decltype(function_values.size()) jj = 0; jj < function_values.size(); ++jj)
{
BOOST_CHECK(abs(function_values(jj)) < threshold_clearance_mp);
}
}
}
BOOST_AUTO_TEST_CASE(total_degree_start_system_precision_16)
{
int this_test_precision{16};
DefaultPrecision(this_test_precision);
Var x = Variable::Make("x");
Var y = Variable::Make("y");
Var t = Variable::Make("t");
System sys;
VariableGroup v{x,y};
sys.AddVariableGroup(v);
sys.AddFunction(pow(x-1,3));
sys.AddFunction(pow(y-1,2));
auto TD = bertini::start_system::TotalDegree(sys);
BOOST_CHECK(!sys.IsHomogeneous());
BOOST_CHECK(!sys.IsPatched());
BOOST_CHECK(!TD.IsHomogeneous());
BOOST_CHECK(!TD.IsPatched());
auto final_system = (1-t)*sys + t*TD;
final_system.AddPathVariable(t);
// test whether all start points have correct precision
for (unsigned ii = 0; ii < TD.NumStartPoints(); ++ii)
{
DefaultPrecision(this_test_precision);
final_system.precision(this_test_precision);
TD.precision(this_test_precision);
auto start_point = TD.StartPoint(ii);
BOOST_CHECK_EQUAL(bertini::Precision(start_point), this_test_precision);
}
}
BOOST_AUTO_TEST_CASE(total_degree_start_system_homogenized_patched_precision_16)
{
int this_test_precision{16};
DefaultPrecision(this_test_precision);
Var x = Variable::Make("x");
Var y = Variable::Make("y");
Var t = Variable::Make("t");
System sys;
VariableGroup v{x,y};
sys.AddVariableGroup(v);
sys.AddFunction(pow(x-1,3));
sys.AddFunction(pow(y-1,2));
sys.Homogenize();
sys.AutoPatch();
BOOST_CHECK(sys.IsHomogeneous());
BOOST_CHECK(sys.IsPatched());
auto TD = bertini::start_system::TotalDegree(sys);
TD.Homogenize();
BOOST_CHECK(TD.IsHomogeneous());
BOOST_CHECK(TD.IsPatched());
auto final_system = (1-t)*sys + t*TD;
final_system.AddPathVariable(t);
// test whether all start points have correct precision
for (unsigned ii = 0; ii < TD.NumStartPoints(); ++ii)
{
DefaultPrecision(this_test_precision);
final_system.precision(this_test_precision);
TD.precision(this_test_precision);
auto start_point = TD.StartPoint(ii);
BOOST_CHECK_EQUAL(bertini::Precision(start_point), this_test_precision);
}
}
BOOST_AUTO_TEST_CASE(quadratic_cubic_quartic_all_the_way_to_final_system)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y"), z = Variable::Make("z");
VariableGroup vars{x,y,z};
sys.AddVariableGroup(vars);
sys.AddFunction(y+x*y + mpfr_float("0.5"));
sys.AddFunction(pow(x,3)+x*y+bertini::node::E());
sys.AddFunction(pow(x,2)*pow(y,2)+x*y*z*z - 1);
bertini::start_system::TotalDegree TD(sys);
Var t = Variable::Make("t");
auto final_mixed_sum = (1-t) * sys + t * TD;
final_mixed_sum.AddPathVariable(t);
BOOST_CHECK(!final_mixed_sum.IsHomogeneous());
BOOST_CHECK(!final_mixed_sum.IsPatched());
final_mixed_sum.Homogenize();
final_mixed_sum.AutoPatch();
BOOST_CHECK_EQUAL(final_mixed_sum.NumVariables(),4);
BOOST_CHECK_EQUAL(final_mixed_sum.NumNaturalVariables(),3);
BOOST_CHECK_EQUAL(final_mixed_sum.NumNaturalFunctions(),3);
BOOST_CHECK_EQUAL(final_mixed_sum.NumTotalFunctions(),4);
BOOST_CHECK(final_mixed_sum.IsHomogeneous());
BOOST_CHECK(final_mixed_sum.IsPolynomial());
BOOST_CHECK(final_mixed_sum.IsPatched());
Vec v(4);
v << mpfr(1), mpfr(1), mpfr(1), mpfr(1);
auto f = final_mixed_sum.Eval(v,bertini::multiprecision::rand());
BOOST_CHECK_EQUAL(f.size(), 4);
auto J = final_mixed_sum.Jacobian(v,bertini::multiprecision::rand());
BOOST_CHECK_EQUAL(J.rows(), 4);
BOOST_CHECK_EQUAL(J.cols(), 4);
}
BOOST_AUTO_TEST_CASE(start_system_total_degree_nonpolynomial_should_throw)
{
bertini::System sys;
Var x = Variable::Make("x"), y = Variable::Make("y"), z = Variable::Make("z");
VariableGroup vars;
vars.push_back(x); vars.push_back(y); vars.push_back(z);
sys.AddVariableGroup(vars);
sys.AddFunction(exp(y)+x*y + mpq_rational(1,2));
sys.AddFunction(pow(x,3)+x*y+bertini::node::E());
sys.AddFunction(pow(x,2)*pow(y,2)+x*y*z*z - 1);
BOOST_CHECK_THROW(bertini::start_system::TotalDegree TD(sys), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(total_degree_start_system_coefficient_bound_degree_bound)
{
/*
In this example we take a decoupled system, homogenize and patch it.
*/
DefaultPrecision(30);
Var x = Variable::Make("x");
Var y = Variable::Make("y");
Var t = Variable::Make("t");
System sys;
VariableGroup v{x,y};
sys.AddVariableGroup(v);
sys.AddFunction(pow(x-1,3));
sys.AddFunction(pow(y-1,2));
sys.Homogenize();
sys.AutoPatch();
BOOST_CHECK(sys.IsHomogeneous());
BOOST_CHECK(sys.IsPatched());
auto TD = bertini::start_system::TotalDegree(sys);
TD.Homogenize();
BOOST_CHECK(TD.IsHomogeneous());
BOOST_CHECK(TD.IsPatched());
auto final_system = (1-t)*sys + t*TD;
final_system.AddPathVariable(t);
}
BOOST_AUTO_TEST_SUITE_END()