From a38f5ea4c751ea35bab598d44460c61d8b84034f Mon Sep 17 00:00:00 2001 From: jodavies Date: Tue, 19 May 2026 23:06:27 +0100 Subject: [PATCH 1/2] perf: flint: small improvements to flint interface + symbol cmp,norm These changes are worth ~2% in scripts which make heavy use of polynomial arithmetic. --- sources/flintinterface.cc | 41 ++++++++++++++++++++++--------------- sources/flintinterface.h | 1 + sources/normal.c | 14 +++++++------ sources/sort.c | 43 +++++++++++++++++++++++---------------- 4 files changed, 59 insertions(+), 40 deletions(-) diff --git a/sources/flintinterface.cc b/sources/flintinterface.cc index 2d736839..fc193751 100644 --- a/sources/flintinterface.cc +++ b/sources/flintinterface.cc @@ -276,8 +276,9 @@ WORD* flint::factorize_mpoly(PHEAD const WORD *argin, WORD *argout, const bool w uint64_t output_size = 1; // For finding the highest symbol, in FORM's lexicographic ordering - var_map_t var_map_inv; - for ( auto x: var_map ) { + vector var_map_inv; + var_map_inv.resize(var_map.size()); + for ( auto x : var_map ) { var_map_inv[x.second] = x.first; } @@ -301,10 +302,10 @@ WORD* flint::factorize_mpoly(PHEAD const WORD *argin, WORD *argout, const bool w fmpz_mpoly_get_term_exp_si((slong*)base_term_exponents.data(), base.d, (slong)j, ctx.d); for ( size_t k = 0; k < var_map.size(); k++ ) { - if ( base_term_exponents[k] > 0 && ( var_map_inv.at(k) > max_var || - ( var_map_inv.at(k) == max_var && base_term_exponents[k] > max_pow ) ) ) { + if ( base_term_exponents[k] > 0 && ( var_map_inv[k] > max_var || + ( var_map_inv[k] == max_var && base_term_exponents[k] > max_pow ) ) ) { - max_var = var_map_inv.at(k); + max_var = var_map_inv[k]; max_pow = base_term_exponents[k]; base_sign[i] = fmpz_sgn(fmpz_mpoly_term_coeff_ref(base.d, j, ctx.d)); } @@ -548,6 +549,7 @@ uint64_t flint::from_argument_mpoly(fmpz_mpoly_t poly, fmpz_mpoly_t denpoly, con // Search for numerical or symbol denominators to create "denpoly". flint::fmpz den_coeff, tmp; fmpz_set_si(den_coeff.d, 1); + vector exponents(var_map.size(), 0); vector neg_exponents(var_map.size(), 0); for ( const WORD* term = args; term < arg_stop; term += term[0] ) { @@ -599,7 +601,7 @@ uint64_t flint::from_argument_mpoly(fmpz_mpoly_t poly, fmpz_mpoly_t denpoly, con const WORD* symbol_stop = term_stop - ABS(coeff_size); const WORD* t = term; - vector exponents(var_map.size(), 0); + fill(exponents.begin(), exponents.end(), 0); t++; // skip over the total size entry if ( t == symbol_stop ) { @@ -1125,20 +1127,25 @@ flint::var_map_t flint::get_variables(const vector &es, const bool with else { for ( WORD i = with_arghead ? ARGHEAD:0; with_arghead ? i < e[0]:e[i] != 0; i += e[i] ) { num_terms++; - if ( i+1 < i+e[i]-ABS(e[i+e[i]-1]) && e[i+1] != SYMBOL ) { + const WORD coeff_size = e[i+e[i]-1]; + const WORD symbols_size = e[i] - ABS(coeff_size); + if ( e[i+1] != SYMBOL && 1 < symbols_size ) { MLOCK(ErrorMessageLock); MesPrint("ERROR: polynomials and polyratfuns must contain symbols only"); MUNLOCK(ErrorMessageLock); Terminate(1); } - for ( WORD j = i+3; jsecond] = MaX(degrees[it->second], degree); } } } @@ -1797,8 +1804,9 @@ uint64_t flint::to_argument_mpoly(PHEAD WORD *out, const bool with_arghead, } // Create the inverse of var_map, so we don't have to search it for each symbol written - var_map_t var_map_inv; - for ( auto x: var_map ) { + vector var_map_inv; + var_map_inv.resize(var_map.size()); + for ( auto x : var_map ) { var_map_inv[x.second] = x.first; } @@ -2012,8 +2020,9 @@ uint64_t flint::to_argument_poly(PHEAD WORD *out, const bool with_arghead, } // Create the inverse of var_map, so we don't have to search it for each symbol written - var_map_t var_map_inv; - for ( auto x: var_map ) { + vector var_map_inv; + var_map_inv.resize(var_map.size()); + for ( auto x : var_map ) { var_map_inv[x.second] = x.first; } diff --git a/sources/flintinterface.h b/sources/flintinterface.h index 88386b0f..4f868669 100644 --- a/sources/flintinterface.h +++ b/sources/flintinterface.h @@ -65,6 +65,7 @@ extern "C" { // The bits of std that are needed: using std::cout; using std::endl; +using std::fill; using std::map; using std::swap; using std::string; diff --git a/sources/normal.c b/sources/normal.c index a435944b..2c4e50c7 100644 --- a/sources/normal.c +++ b/sources/normal.c @@ -5208,10 +5208,12 @@ int SymbolNormalize(WORD *term) while ( t < tstop ) { /* Step 1: collect symbols */ if ( *t == SYMBOL && t < tstop ) { for ( i = 2; i < t[1]; i += 2 ) { + const WORD sym = t[i]; + const WORD pow = t[i+1]; bb = buffer+2; while ( bb < b ) { - if ( bb[0] == t[i] ) { /* add powers */ - bb[1] += t[i+1]; + if ( bb[0] == sym ) { /* add powers */ + bb[1] += pow; if ( bb[1] > MAXPOWER || bb[1] < -MAXPOWER ) { MLOCK(ErrorMessageLock); MesPrint("Power in SymbolNormalize out of range"); @@ -5226,18 +5228,18 @@ int SymbolNormalize(WORD *term) } goto Nexti; } - else if ( bb[0] > t[i] ) { /* insert it */ + else if ( bb[0] > sym ) { /* insert it */ m = b; while ( m > bb ) { m[1] = m[-1]; m[0] = m[-2]; m -= 2; } b += 2; - bb[0] = t[i]; - bb[1] = t[i+1]; + bb[0] = sym; + bb[1] = pow; goto Nexti; } bb += 2; } if ( bb >= b ) { /* add it to the end */ - *b++ = t[i]; *b++ = t[i+1]; + *b++ = sym; *b++ = pow; } Nexti:; } diff --git a/sources/sort.c b/sources/sort.c index 13c5d20c..734ca1b8 100644 --- a/sources/sort.c +++ b/sources/sort.c @@ -2803,31 +2803,38 @@ WORD Compare1(PHEAD WORD *term1, WORD *term2, WORD level) WORD CompareSymbols(PHEAD WORD *term1, WORD *term2, WORD par) { - int sum1, sum2; WORD *t1, *t2, *tt1, *tt2; - int low, high; DUMMYUSE(par); - if ( AR.SortType == SORTLOWFIRST ) { low = 1; high = -1; } - else { low = -1; high = 1; } - t1 = term1 + 1; tt1 = term1+*term1; tt1 -= ABS(tt1[-1]); t1 += 2; - t2 = term2 + 1; tt2 = term2+*term2; tt2 -= ABS(tt2[-1]); t2 += 2; - if ( AN.polysortflag > 0 ) { - sum1 = 0; sum2 = 0; - while ( t1 < tt1 ) { sum1 += t1[1]; t1 += 2; } - while ( t2 < tt2 ) { sum2 += t2[1]; t2 += 2; } - if ( sum1 < sum2 ) return(low); - if ( sum1 > sum2 ) return(high); - t1 = term1+3; t2 = term2 + 3; - } + const int low = AR.SortType == SORTLOWFIRST ? 1 : -1; + const int high = - low; + + t1 = term1 + 3; tt1 = term1+*term1; tt1 -= ABS(tt1[-1]); + t2 = term2 + 3; tt2 = term2+*term2; tt2 -= ABS(tt2[-1]); + +// Currently, FORM never sets polysortflag != 0, so disable this code. +// if ( AN.polysortflag > 0 ) { +// WORD sum1, sum2; +// sum1 = 0; sum2 = 0; +// while ( t1 < tt1 ) { sum1 += t1[1]; t1 += 2; } +// while ( t2 < tt2 ) { sum2 += t2[1]; t2 += 2; } +// if ( sum1 < sum2 ) return(low); +// if ( sum1 > sum2 ) return(high); +// t1 = term1+3; t2 = term2 + 3; +// } + while ( t1 < tt1 && t2 < tt2 ) { - if ( *t1 > *t2 ) return(low); - if ( *t1 < *t2 ) return(high); - if ( t1[1] < t2[1] ) return(low); - if ( t1[1] > t2[1] ) return(high); + const WORD s1 = *t1; + const WORD s2 = *t2; + if ( s1 != s2 ) { return ( s1 > s2 ) ? low : high ; } + const WORD p1 = t1[1]; + const WORD p2 = t2[1]; + if ( p1 != p2 ) { return ( p1 < p2 ) ? low : high ; } t1 += 2; t2 += 2; } + if ( t1 < tt1 ) return(high); if ( t2 < tt2 ) return(low); + return(0); } From 41798e16f7511a321e6619fdd479ab23138f3e01 Mon Sep 17 00:00:00 2001 From: jodavies Date: Tue, 26 May 2026 22:18:02 +0100 Subject: [PATCH 2/2] perf: flint: use FORM lexicographic symbol order for polyratfun This means we can rely on the sorted result from FLINT to be in the required order, so we can avoid the unnecessary additional sort into FORM order after computation. The result is also more consistent, in that the denominator always has a positive leading coefficient in the final result, which was not the case previously. Introduce "On OldPRFSign;" switch to force the old ordering, in case the user requires this for any reason. --- check/fixes.frm | 2 ++ doc/manual/statements.tex | 9 +++++++ sources/compcomm.c | 1 + sources/flintinterface.cc | 55 +++++++++++++++++++++------------------ sources/flintinterface.h | 18 +++++++------ sources/flintwrap.cc | 24 +++++++++-------- sources/setfile.c | 3 +++ sources/startup.c | 1 + sources/structs.h | 1 + 9 files changed, 70 insertions(+), 44 deletions(-) diff --git a/check/fixes.frm b/check/fixes.frm index 14676cac..07ca8db7 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -1295,6 +1295,8 @@ assert succeeded? assert result("F") =~ expr("1") *--#] Issue126 : *--#[ Issue128 : +* The result check here requires the old prf sign convention: +On oldprfsign; * Rational arithmetic giving pi_ CF rat; PolyRatFun rat; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index e0316ae2..55c27e83 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -3825,6 +3825,9 @@ \section{off} statement~\ref{substafactarg}\index{factarg} to the new mode of version 4 or later in which expressions in the argument of the mentioned function are completely factored over the rationals. The default is off.} + +\leftvitem{3.5cm}{oldprfsign\index{off!oldprfsign}} +\rightvitem{13cm}{\label{staoffoldprfsign} See \ref{staonoldprfsign}.} \leftvitem{3.5cm}{parallel\index{off!parallel}} \rightvitem{13cm}{Disallows the running of the program in parallel mode @@ -4044,6 +4047,12 @@ \section{on} version 4. This is a compatibility mode to allow oldprograms that rely on a specific working of the FactArg statement to still run. The default is off.} + +\leftvitem{3.5cm}{oldprfsign\index{on!oldprfsign}} +\rightvitem{13cm}{\label{staonoldprfsign} Forces the numerator/denominator +sign convention of PolyRatFun~\ref{substapolyratfun} of \FORM\ versions prior +to 5.1, when using FLINT for polynomial arithmetic. Enabling this leads to a +loss of performance in multivariate cases.} \leftvitem{3.5cm}{parallel\index{on!parallel}} \rightvitem{13cm}{Allows the running of the program in parallel mode unless diff --git a/sources/compcomm.c b/sources/compcomm.c index 07c7746d..ac38ead5 100644 --- a/sources/compcomm.c +++ b/sources/compcomm.c @@ -135,6 +135,7 @@ static KEYWORDV onoffoptions[] = { ,{"oldfactarg", &(AC.OldFactArgFlag), 1, 0} ,{"memdebugflag", &(AC.MemDebugFlag), 1, 0} ,{"oldgcd", &(AC.OldGCDflag), 1, 0} + ,{"oldprfsign", &(AC.OldPRFSignFlag), 1, 0} ,{"innertest", &(AC.InnerTest), 1, 0} ,{"wtimestats", &(AC.WTimeStatsFlag), 1, 0} ,{"sortreallocate", &(AC.SortReallocateFlag), 1, 0} diff --git a/sources/flintinterface.cc b/sources/flintinterface.cc index fc193751..afe6aa98 100644 --- a/sources/flintinterface.cc +++ b/sources/flintinterface.cc @@ -89,7 +89,7 @@ void flint::cleanup_master(void) { #[ flint::divmod_mpoly : */ WORD* flint::divmod_mpoly(PHEAD const WORD *a, const WORD *b, const bool return_rem, - const WORD must_fit_term, const var_map_t &var_map) { + const WORD must_fit_term, const var_map_t &var_map, const bool sort_vars) { flint::mpoly_ctx ctx(var_map.size()); flint::mpoly pa(ctx.d), pb(ctx.d), denpa(ctx.d), denpb(ctx.d); @@ -133,10 +133,10 @@ WORD* flint::divmod_mpoly(PHEAD const WORD *a, const WORD *b, const bool return_ const uint64_t prev_size = 0; const uint64_t out_size = return_rem ? (uint64_t)flint::to_argument_mpoly(BHEAD NULL, with_arghead, must_fit_term, write, prev_size, - rem.d, var_map, ctx.d, scale.d) + rem.d, var_map, ctx.d, sort_vars, scale.d) : (uint64_t)flint::to_argument_mpoly(BHEAD NULL, with_arghead, must_fit_term, write, prev_size, - div.d, var_map, ctx.d, scale.d) + div.d, var_map, ctx.d, sort_vars, scale.d) ; WORD* res = (WORD *)Malloc1(sizeof(WORD)*out_size, "flint::divrem_mpoly"); @@ -145,11 +145,11 @@ WORD* flint::divmod_mpoly(PHEAD const WORD *a, const WORD *b, const bool return_ write = true; if ( return_rem ) { (uint64_t)flint::to_argument_mpoly(BHEAD res, with_arghead, must_fit_term, write, prev_size, - rem.d, var_map, ctx.d, scale.d); + rem.d, var_map, ctx.d, sort_vars, scale.d); } else { (uint64_t)flint::to_argument_mpoly(BHEAD res, with_arghead, must_fit_term, write, prev_size, - div.d, var_map, ctx.d, scale.d); + div.d, var_map, ctx.d, sort_vars, scale.d); } return res; @@ -233,7 +233,7 @@ WORD* flint::divmod_poly(PHEAD const WORD *a, const WORD *b, const bool return_r #[ flint::factorize_mpoly : */ WORD* flint::factorize_mpoly(PHEAD const WORD *argin, WORD *argout, const bool with_arghead, - const bool is_fun_arg, const var_map_t &var_map) { + const bool is_fun_arg, const var_map_t &var_map, const bool sort_vars) { flint::mpoly_ctx ctx(var_map.size()); flint::mpoly arg(ctx.d), den(ctx.d), base(ctx.d); @@ -322,7 +322,7 @@ WORD* flint::factorize_mpoly(PHEAD const WORD *argin, WORD *argout, const bool w const bool write = false; for ( int64_t j = 0; j < exponent; j++ ) { output_size += (uint64_t)flint::to_argument_mpoly(BHEAD NULL, with_arghead, - is_fun_arg, write, 0, base.d, var_map, ctx.d); + is_fun_arg, write, 0, base.d, var_map, ctx.d, sort_vars); } } } @@ -369,7 +369,7 @@ WORD* flint::factorize_mpoly(PHEAD const WORD *argin, WORD *argout, const bool w const bool write = true; for ( int64_t j = 0; j < exponent; j++ ) { argout += flint::to_argument_mpoly(BHEAD argout, with_arghead, is_fun_arg, write, - argout-old_argout, base.d, var_map, ctx.d); + argout-old_argout, base.d, var_map, ctx.d, sort_vars); } } // Final trailing zero to denote the end of the factors. @@ -915,7 +915,7 @@ void flint::fmpz_set_form(fmpz_t z, UWORD *a, WORD na) { // If must_fit_term, this should be a TermMalloc buffer. Otherwise Malloc1 the buffer. // For multi-variate cases. WORD* flint::gcd_mpoly(PHEAD const WORD *a, const WORD *b, const WORD must_fit_term, - const var_map_t &var_map) { + const var_map_t &var_map, const bool sort_vars) { flint::mpoly_ctx ctx(var_map.size()); flint::mpoly pa(ctx.d), pb(ctx.d), denpa(ctx.d), denpb(ctx.d), gcd(ctx.d); @@ -990,7 +990,7 @@ WORD* flint::gcd_mpoly(PHEAD const WORD *a, const WORD *b, const WORD must_fit_t const bool write = false; const uint64_t prev_size = 0; const uint64_t gcd_size = (uint64_t)flint::to_argument_mpoly(BHEAD NULL, - with_arghead, must_fit_term, write, prev_size, gcd.d, var_map, ctx.d); + with_arghead, must_fit_term, write, prev_size, gcd.d, var_map, ctx.d, sort_vars); res = (WORD *)Malloc1(sizeof(WORD)*gcd_size, "flint::gcd_mpoly"); } @@ -999,7 +999,7 @@ WORD* flint::gcd_mpoly(PHEAD const WORD *a, const WORD *b, const WORD must_fit_t const bool write = true; const uint64_t prev_size = 0; flint::to_argument_mpoly(BHEAD res, with_arghead, must_fit_term, write, prev_size, gcd.d, - var_map, ctx.d); + var_map, ctx.d, sort_vars); return res; } @@ -1290,7 +1290,8 @@ WORD* flint::inverse_poly(PHEAD const WORD *a, const WORD *b, const var_map_t &v */ // Return a pointer to a buffer containing the product of the 0-terminated term lists at a and b. // For multi-variate cases. -WORD* flint::mul_mpoly(PHEAD const WORD *a, const WORD *b, const var_map_t &var_map) { +WORD* flint::mul_mpoly(PHEAD const WORD *a, const WORD *b, const var_map_t &var_map, + const bool sort_vars) { flint::mpoly_ctx ctx(var_map.size()); flint::mpoly pa(ctx.d), pb(ctx.d), denpa(ctx.d), denpb(ctx.d); @@ -1327,12 +1328,12 @@ WORD* flint::mul_mpoly(PHEAD const WORD *a, const WORD *b, const var_map_t &var_ const bool must_fit_term = false; const uint64_t prev_size = 0; const uint64_t mul_size = (uint64_t)flint::to_argument_mpoly(BHEAD NULL, - with_arghead, must_fit_term, write, prev_size, pa.d, var_map, ctx.d, den.d); + with_arghead, must_fit_term, write, prev_size, pa.d, var_map, ctx.d, sort_vars, den.d); res = (WORD*)Malloc1(sizeof(WORD)*mul_size, "flint::mul_mpoly"); write = true; flint::to_argument_mpoly(BHEAD res, with_arghead, must_fit_term, write, prev_size, pa.d, - var_map, ctx.d, den.d); + var_map, ctx.d, sort_vars, den.d); return res; } @@ -1394,7 +1395,7 @@ WORD* flint::mul_poly(PHEAD const WORD *a, const WORD *b, const var_map_t &var_m */ // Add the multi-variate FORM rational polynomials at t1 and t2. The result is written at out. void flint::ratfun_add_mpoly(PHEAD const WORD *t1, const WORD *t2, WORD *out, - const var_map_t &var_map) { + const var_map_t &var_map, const bool sort_vars) { flint::mpoly_ctx ctx(var_map.size()); flint::mpoly gcd(ctx.d), num1(ctx.d), den1(ctx.d), num2(ctx.d), den2(ctx.d); @@ -1433,9 +1434,9 @@ void flint::ratfun_add_mpoly(PHEAD const WORD *t1, const WORD *t2, WORD *out, const bool write = true; // prev_size + 4, to account for final term size and coeff of "1/1" out += flint::to_argument_mpoly(BHEAD out, with_arghead, must_fit_term, write, out-args_size+4, - num1.d, var_map, ctx.d); + num1.d, var_map, ctx.d, sort_vars); out += flint::to_argument_mpoly(BHEAD out, with_arghead, must_fit_term, write, out-args_size+4, - den1.d, var_map, ctx.d); + den1.d, var_map, ctx.d, sort_vars); *args_size = out - args_size + 1; // The +1 is to include the function ID AT.WorkPointer = out; @@ -1498,7 +1499,8 @@ void flint::ratfun_add_poly(PHEAD const WORD *t1, const WORD *t2, WORD *out, */ // Multiply and simplify occurrences of the multi-variate FORM rational polynomials found in term. // The final term is written in place, with the rational polynomial at the end. -void flint::ratfun_normalize_mpoly(PHEAD WORD *term, const var_map_t &var_map) { +void flint::ratfun_normalize_mpoly(PHEAD WORD *term, const var_map_t &var_map, + const bool sort_vars) { // The length of the coefficient const WORD ncoeff = (term + *term)[-1]; @@ -1555,9 +1557,9 @@ void flint::ratfun_normalize_mpoly(PHEAD WORD *term, const var_map_t &var_map) { const bool must_fit_term = true; const bool write = true; out += flint::to_argument_mpoly(BHEAD out, with_arghead, must_fit_term, write, out-term_size, - num1.d, var_map, ctx.d); + num1.d, var_map, ctx.d, sort_vars); out += flint::to_argument_mpoly(BHEAD out, with_arghead, must_fit_term, write, out-term_size, - den1.d, var_map, ctx.d); + den1.d, var_map, ctx.d, sort_vars); *args_size = out - args_size + 1; // The +1 is to include the function ID @@ -1786,7 +1788,8 @@ void flint::ratfun_read_poly(const WORD *a, fmpz_poly_t num, fmpz_poly_t den) { #define IFW(x) { if ( write ) {x;} } uint64_t flint::to_argument_mpoly(PHEAD WORD *out, const bool with_arghead, const bool must_fit_term, const bool write, const uint64_t prev_size, const fmpz_mpoly_t poly, - const var_map_t &var_map, const fmpz_mpoly_ctx_t ctx, const fmpz_t denscale) { + const var_map_t &var_map, const fmpz_mpoly_ctx_t ctx, const bool sort_vars, + const fmpz_t denscale) { // out is modified later, keep the pointer at entry const WORD* out_entry = out; @@ -1964,8 +1967,10 @@ uint64_t flint::to_argument_mpoly(PHEAD WORD *out, const bool with_arghead, if ( with_arghead ) { IFW(*arg_size = out - arg_size); - if ( write ) { - // Sort into form highfirst ordering + if ( write && sort_vars ) { + // Sort into form highfirst ordering, if we have potentially re-ordered the variables by + // degree, in flint::get_variables. Otherwise, we can rely on FLINT's sorting with + // ORD_LEX and the variables ordered in FORM's lexicographic order. flint::form_sort(BHEAD (WORD*)(out_entry)); } } @@ -1983,13 +1988,13 @@ uint64_t flint::to_argument_mpoly(PHEAD WORD *out, const bool with_arghead, // If no denscale argument is supplied, just set it to 1 and call the usual function uint64_t flint::to_argument_mpoly(PHEAD WORD *out, const bool with_arghead, const bool must_fit_term, const bool write, const uint64_t prev_size, const fmpz_mpoly_t poly, - const var_map_t &var_map, const fmpz_mpoly_ctx_t ctx) { + const var_map_t &var_map, const fmpz_mpoly_ctx_t ctx, const bool sort_vars) { flint::fmpz tmp; fmpz_set_ui(tmp.d, 1); uint64_t ret = flint::to_argument_mpoly(BHEAD out, with_arghead, must_fit_term, write, - prev_size, poly, var_map, ctx, tmp.d); + prev_size, poly, var_map, ctx, sort_vars, tmp.d); return ret; } diff --git a/sources/flintinterface.h b/sources/flintinterface.h index 4f868669..a3a70b98 100644 --- a/sources/flintinterface.h +++ b/sources/flintinterface.h @@ -133,10 +133,12 @@ namespace flint { void cleanup(void); void cleanup_master(void); - WORD* divmod_mpoly(PHEAD const WORD *, const WORD *, const bool, const WORD, const var_map_t &); + WORD* divmod_mpoly(PHEAD const WORD *, const WORD *, const bool, const WORD, const var_map_t &, + const bool); WORD* divmod_poly(PHEAD const WORD *, const WORD *, const bool, const WORD, const var_map_t &); - WORD* factorize_mpoly(PHEAD const WORD *, WORD *, const bool, const bool, const var_map_t &); + WORD* factorize_mpoly(PHEAD const WORD *, WORD *, const bool, const bool, const var_map_t &, + const bool); WORD* factorize_poly(PHEAD const WORD *, WORD *, const bool, const bool, const var_map_t &); void form_sort(PHEAD WORD *); @@ -148,20 +150,20 @@ namespace flint { WORD fmpz_get_form(fmpz_t, WORD *); void fmpz_set_form(fmpz_t, UWORD *, WORD); - WORD* gcd_mpoly(PHEAD const WORD *, const WORD *, const WORD, const var_map_t &); + WORD* gcd_mpoly(PHEAD const WORD *, const WORD *, const WORD, const var_map_t &, const bool); WORD* gcd_poly(PHEAD const WORD *, const WORD *, const WORD, const var_map_t &); var_map_t get_variables(const vector &, const bool, const bool); WORD* inverse_poly(PHEAD const WORD *, const WORD *, const var_map_t &); - WORD* mul_mpoly(PHEAD const WORD *, const WORD *, const var_map_t &); + WORD* mul_mpoly(PHEAD const WORD *, const WORD *, const var_map_t &, const bool); WORD* mul_poly(PHEAD const WORD *, const WORD *, const var_map_t &); - void ratfun_add_mpoly(PHEAD const WORD *, const WORD *, WORD *, const var_map_t &); + void ratfun_add_mpoly(PHEAD const WORD *, const WORD *, WORD *, const var_map_t &, const bool); void ratfun_add_poly(PHEAD const WORD *, const WORD *, WORD *, const var_map_t &); - void ratfun_normalize_mpoly(PHEAD WORD *, const var_map_t &); + void ratfun_normalize_mpoly(PHEAD WORD *, const var_map_t &, const bool); void ratfun_normalize_poly(PHEAD WORD *, const var_map_t &); void ratfun_read_mpoly(const WORD *, fmpz_mpoly_t, fmpz_mpoly_t, const var_map_t &, @@ -169,9 +171,9 @@ namespace flint { void ratfun_read_poly(const WORD *, fmpz_poly_t, fmpz_poly_t); uint64_t to_argument_mpoly(PHEAD WORD *, const bool, const bool, const bool, const uint64_t, - const fmpz_mpoly_t, const var_map_t &, const fmpz_mpoly_ctx_t); + const fmpz_mpoly_t, const var_map_t &, const fmpz_mpoly_ctx_t, const bool); uint64_t to_argument_mpoly(PHEAD WORD *, const bool, const bool, const bool, const uint64_t, - const fmpz_mpoly_t, const var_map_t &, const fmpz_mpoly_ctx_t, const fmpz_t); + const fmpz_mpoly_t, const var_map_t &, const fmpz_mpoly_ctx_t, const bool, const fmpz_t); uint64_t to_argument_poly(PHEAD WORD *, const bool, const bool, const bool, const uint64_t, const fmpz_poly_t, const var_map_t &); uint64_t to_argument_poly(PHEAD WORD *, const bool, const bool, const bool, const uint64_t, diff --git a/sources/flintwrap.cc b/sources/flintwrap.cc index 83d97530..43937941 100644 --- a/sources/flintwrap.cc +++ b/sources/flintwrap.cc @@ -66,7 +66,7 @@ WORD* flint_div(PHEAD WORD *a, WORD *b, const WORD must_fit_term) { const bool return_rem = false; if ( var_map.size() > 1 ) { - return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map); + return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map, sort_vars); } else { return flint::divmod_poly(BHEAD a, b, return_rem, must_fit_term, var_map); @@ -85,7 +85,7 @@ int flint_factorize_argument(PHEAD WORD *argin, WORD *argout) { const bool is_fun_arg = true; if ( var_map.size() > 1 ) { - flint::factorize_mpoly(BHEAD argin, argout, with_arghead, is_fun_arg, var_map); + flint::factorize_mpoly(BHEAD argin, argout, with_arghead, is_fun_arg, var_map, sort_vars); } else { flint::factorize_poly(BHEAD argin, argout, with_arghead, is_fun_arg, var_map); @@ -106,7 +106,7 @@ WORD* flint_factorize_dollar(PHEAD WORD *argin) { const bool is_fun_arg = false; if ( var_map.size() > 1 ) { - return flint::factorize_mpoly(BHEAD argin, NULL, with_arghead, is_fun_arg, var_map); + return flint::factorize_mpoly(BHEAD argin, NULL, with_arghead, is_fun_arg, var_map, sort_vars); } else { return flint::factorize_poly(BHEAD argin, NULL, with_arghead, is_fun_arg, var_map); @@ -127,7 +127,7 @@ WORD* flint_gcd(PHEAD WORD *a, WORD *b, const WORD must_fit_term) { const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars); if ( var_map.size() > 1 ) { - return flint::gcd_mpoly(BHEAD a, b, must_fit_term, var_map); + return flint::gcd_mpoly(BHEAD a, b, must_fit_term, var_map, sort_vars); } else { return flint::gcd_poly(BHEAD a, b, must_fit_term, var_map); @@ -164,10 +164,12 @@ WORD* flint_mul(PHEAD WORD *a, WORD *b) { e.reserve(2); e.push_back(a); e.push_back(b); - const flint::var_map_t var_map = flint::get_variables(e, false, false); + const bool with_arghead = false; + const bool sort_vars = false; + const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars); if ( var_map.size() > 1 ) { - return flint::mul_mpoly(BHEAD a, b, var_map); + return flint::mul_mpoly(BHEAD a, b, var_map, sort_vars); } else { return flint::mul_poly(BHEAD a, b, var_map); @@ -200,11 +202,11 @@ WORD* flint_ratfun_add(PHEAD WORD *t1, WORD *t2) { NEXTARG(t); } const bool with_arghead = true; - const bool sort_vars = true; + const bool sort_vars = AC.OldPRFSignFlag ? true : false; const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars); if ( var_map.size() > 1 ) { - flint::ratfun_add_mpoly(BHEAD t1, t2, oldworkpointer, var_map); + flint::ratfun_add_mpoly(BHEAD t1, t2, oldworkpointer, var_map, sort_vars); } else { flint::ratfun_add_poly(BHEAD t1, t2, oldworkpointer, var_map); @@ -266,11 +268,11 @@ int flint_ratfun_normalize(PHEAD WORD *term) { } } const bool with_arghead = true; - const bool sort_vars = true; + const bool sort_vars = AC.OldPRFSignFlag ? true : false; const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars); if ( var_map.size() > 1 ) { - flint::ratfun_normalize_mpoly(BHEAD term, var_map); + flint::ratfun_normalize_mpoly(BHEAD term, var_map, sort_vars); } else { flint::ratfun_normalize_poly(BHEAD term, var_map); @@ -301,7 +303,7 @@ WORD* flint_rem(PHEAD WORD *a, WORD *b, const WORD must_fit_term) { const bool return_rem = true; if ( var_map.size() > 1 ) { - return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map); + return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map, sort_vars); } else { return flint::divmod_poly(BHEAD a, b, return_rem, must_fit_term, var_map); diff --git a/sources/setfile.c b/sources/setfile.c index 33bd3dbe..d15bb654 100644 --- a/sources/setfile.c +++ b/sources/setfile.c @@ -89,6 +89,7 @@ SETUPPARAMETERS setupparameters[] = ,{(UBYTE *)"oldgcd", ONOFFVALUE, 0, (LONG)1} ,{(UBYTE *)"oldorder", ONOFFVALUE, 0, (LONG)0} ,{(UBYTE *)"oldparallelstatistics", ONOFFVALUE, 0, (LONG)0} + ,{(UBYTE *)"oldprfsign", ONOFFVALUE, 0, (LONG)0} ,{(UBYTE *)"parentheses", NUMERICALVALUE, 0, (LONG)MAXPARLEVEL} ,{(UBYTE *)"path", PATHVALUE, 0, (LONG)curdirp} ,{(UBYTE *)"procedureextension", STRINGVALUE, 0, (LONG)procedureextension} @@ -708,6 +709,8 @@ int AllocSetups(void) AC.OldFactArgFlag = AM.gOldFactArgFlag = AM.ggOldFactArgFlag = sp->value; sp = GetSetupPar((UBYTE *)"oldgcd"); AC.OldGCDflag = AM.gOldGCDflag = AM.ggOldGCDflag = sp->value; + sp = GetSetupPar((UBYTE *)"oldprfsign"); + AC.OldPRFSignFlag = sp->value; sp = GetSetupPar((UBYTE *)"wtimestats"); if ( sp->value == 2 ) sp->value = AM.ggWTimeStatsFlag; AC.WTimeStatsFlag = AM.gWTimeStatsFlag = AM.ggWTimeStatsFlag = sp->value; diff --git a/sources/startup.c b/sources/startup.c index ffa414aa..6f85902d 100644 --- a/sources/startup.c +++ b/sources/startup.c @@ -1341,6 +1341,7 @@ void StartVariables(void) AC.OldParallelStats = AM.gOldParallelStats = AM.ggOldParallelStats = 0; AC.OldFactArgFlag = AM.gOldFactArgFlag = AM.ggOldFactArgFlag = NEWFACTARG; AC.OldGCDflag = AM.gOldGCDflag = AM.ggOldGCDflag = 1; + AC.OldPRFSignFlag = 0; AC.WTimeStatsFlag = AM.gWTimeStatsFlag = AM.ggWTimeStatsFlag = 0; AM.gcNumDollars = AP.DollarList.num; AC.SizeCommuteInSet = AM.gSizeCommuteInSet = 0; diff --git a/sources/structs.h b/sources/structs.h index 36787109..db06d2b4 100644 --- a/sources/structs.h +++ b/sources/structs.h @@ -1843,6 +1843,7 @@ struct C_const { int OldFactArgFlag; int MemDebugFlag; /* Only used when MALLOCDEBUG in tools.c */ int OldGCDflag; + int OldPRFSignFlag; int WTimeStatsFlag; int SortReallocateFlag; /* Controls reallocation of large+small buffer at module end. 0 : Off