@@ -442,7 +442,8 @@ Transform the system `sys` with `transformation` and return a
442442`PolynomialTransformationResult`, or a `NotPolynomialError` if the system cannot
443443be transformed.
444444"""
445- function transform_system (sys:: NonlinearSystem , transformation:: PolynomialTransformation )
445+ function transform_system (sys:: NonlinearSystem , transformation:: PolynomialTransformation ;
446+ fraction_cancel_fn = simplify_fractions)
446447 subrules = transformation. substitution_rules
447448 dvs = unknowns (sys)
448449 eqs = full_equations (sys)
@@ -463,7 +464,7 @@ function transform_system(sys::NonlinearSystem, transformation::PolynomialTransf
463464 return NotPolynomialError (
464465 VariablesAsPolyAndNonPoly (dvs[poly_and_nonpoly]), eqs, polydata)
465466 end
466- num, den = handle_rational_polynomials (t, new_dvs)
467+ num, den = handle_rational_polynomials (t, new_dvs; fraction_cancel_fn )
467468 # make factors different elements, otherwise the nonzero factors artificially
468469 # inflate the error of the zero factor.
469470 if iscall (den) && operation (den) == *
@@ -492,43 +493,67 @@ $(TYPEDSIGNATURES)
492493Given a `x`, a polynomial in variables in `wrt` which may contain rational functions,
493494express `x` as a single rational function with polynomial `num` and denominator `den`.
494495Return `(num, den)`.
496+
497+ Keyword arguments:
498+ - `fraction_cancel_fn`: A function which takes a fraction (`operation(expr) == /`) and returns
499+ a simplified symbolic quantity with common factors in the numerator and denominator are
500+ cancelled. Defaults to `SymbolicUtils.simplify_fractions`, but can be changed to
501+ `nothing` to improve performance on large polynomials at the cost of avoiding non-trivial
502+ cancellation.
495503"""
496- function handle_rational_polynomials (x, wrt)
504+ function handle_rational_polynomials (x, wrt; fraction_cancel_fn = simplify_fractions )
497505 x = unwrap (x)
498506 symbolic_type (x) == NotSymbolic () && return x, 1
499507 iscall (x) || return x, 1
500508 contains_variable (x, wrt) || return x, 1
501509 any (isequal (x), wrt) && return x, 1
502510
503- # simplify_fractions cancels out some common factors
504- # and expands (a / b)^c to a^c / b^c, so we only need
505- # to handle these cases
506- x = simplify_fractions (x)
507511 op = operation (x)
508512 args = arguments (x)
509513
510514 if op == /
511515 # numerator and denominator are trivial
512516 num, den = args
513- # but also search for rational functions in numerator
514- n, d = handle_rational_polynomials (num , wrt)
515- num, den = n, den * d
516- elseif op == +
517+ n1, d1 = handle_rational_polynomials (num, wrt; fraction_cancel_fn)
518+ n2, d2 = handle_rational_polynomials (den , wrt; fraction_cancel_fn )
519+ num, den = n1 * d2, d1 * n2
520+ elseif ( op == + ) || (op == - )
517521 num = 0
518522 den = 1
519-
520- # we don't need to do common denominator
521- # because we don't care about cases where denominator
522- # is zero. The expression is zero when all the numerators
523- # are zero.
523+ if op == -
524+ args[2 ] = - args[2 ]
525+ end
526+ for arg in args
527+ n, d = handle_rational_polynomials (arg, wrt; fraction_cancel_fn)
528+ num = num * d + n * den
529+ den *= d
530+ end
531+ elseif op == ^
532+ base, pow = args
533+ num, den = handle_rational_polynomials (base, wrt; fraction_cancel_fn)
534+ num ^= pow
535+ den ^= pow
536+ elseif op == *
537+ num = 1
538+ den = 1
524539 for arg in args
525- n, d = handle_rational_polynomials (arg, wrt)
526- num + = n
540+ n, d = handle_rational_polynomials (arg, wrt; fraction_cancel_fn )
541+ num * = n
527542 den *= d
528543 end
529544 else
530- return x, 1
545+ error (" Unhandled operation in `handle_rational_polynomials`. This should never happen. Please open an issue in ModelingToolkit.jl with an MWE." )
546+ end
547+
548+ if fraction_cancel_fn != = nothing
549+ expr = fraction_cancel_fn (num / den)
550+ if iscall (expr) && operation (expr) == /
551+ num, den = arguments (expr)
552+ else
553+ num, den = expr, 1
554+ end
531555 end
556+
532557 # if the denominator isn't a polynomial in `wrt`, better to not include it
533558 # to reduce the size of the gcd polynomial
534559 if ! contains_variable (den, wrt)
0 commit comments