@@ -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 + =
540+             n, d =  handle_rational_polynomials (arg, wrt; fraction_cancel_fn )
541+             num * =
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