@@ -442,7 +442,8 @@ Transform the system `sys` with `transformation` and return a
442
442
`PolynomialTransformationResult`, or a `NotPolynomialError` if the system cannot
443
443
be transformed.
444
444
"""
445
- function transform_system (sys:: NonlinearSystem , transformation:: PolynomialTransformation )
445
+ function transform_system (sys:: NonlinearSystem , transformation:: PolynomialTransformation ;
446
+ fraction_cancel_fn = simplify_fractions)
446
447
subrules = transformation. substitution_rules
447
448
dvs = unknowns (sys)
448
449
eqs = full_equations (sys)
@@ -463,7 +464,7 @@ function transform_system(sys::NonlinearSystem, transformation::PolynomialTransf
463
464
return NotPolynomialError (
464
465
VariablesAsPolyAndNonPoly (dvs[poly_and_nonpoly]), eqs, polydata)
465
466
end
466
- num, den = handle_rational_polynomials (t, new_dvs)
467
+ num, den = handle_rational_polynomials (t, new_dvs; fraction_cancel_fn )
467
468
# make factors different elements, otherwise the nonzero factors artificially
468
469
# inflate the error of the zero factor.
469
470
if iscall (den) && operation (den) == *
@@ -492,43 +493,67 @@ $(TYPEDSIGNATURES)
492
493
Given a `x`, a polynomial in variables in `wrt` which may contain rational functions,
493
494
express `x` as a single rational function with polynomial `num` and denominator `den`.
494
495
Return `(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.
495
503
"""
496
- function handle_rational_polynomials (x, wrt)
504
+ function handle_rational_polynomials (x, wrt; fraction_cancel_fn = simplify_fractions )
497
505
x = unwrap (x)
498
506
symbolic_type (x) == NotSymbolic () && return x, 1
499
507
iscall (x) || return x, 1
500
508
contains_variable (x, wrt) || return x, 1
501
509
any (isequal (x), wrt) && return x, 1
502
510
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)
507
511
op = operation (x)
508
512
args = arguments (x)
509
513
510
514
if op == /
511
515
# numerator and denominator are trivial
512
516
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 == - )
517
521
num = 0
518
522
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
524
539
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
527
542
den *= d
528
543
end
529
544
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
531
555
end
556
+
532
557
# if the denominator isn't a polynomial in `wrt`, better to not include it
533
558
# to reduce the size of the gcd polynomial
534
559
if ! contains_variable (den, wrt)
0 commit comments