Together¶
Status: Stable
documented, exercised by the test suite and/or worked examples, with no known limitations recorded.
Description¶
Together[expr]
combines fractions over a common denominator, then cancels.
Notes
Option Extension -\> alpha runs the final cancellation over Q(alpha) so algebraic-coefficient simplifications fire (e.g. 1/(x-Sqrt\[2\]) + 1/(x+Sqrt\[2\]) collapses to (2 x)/(x^2 - 2) under Extension -\> Sqrt\[2\]). Default Extension -\> None combines and cancels over the rationals only.Examples (16)¶
Every input below was run against the current Mathilda build and its output recorded.
Basic examples (6)¶
In[1]:= Together[a/b + c/d]
Out[1]= (b c + a d)/(b d)
In[2]:= Together[x^2/(x^2 - 1) + x/(x^2 - 1)]
Out[2]= x/(-1 + x)
In[3]:= Together[1/x + 1/(x + 1) + 1/(x + 2) + 1/(x + 3)]
Out[3]= (6 + 22 x + 18 x^2 + 4 x^3)/(6 x + 11 x^2 + 6 x^3 + x^4)
In[4]:= Together[x^2/(x - y) - x y/(x - y)]
Out[4]= x
In[5]:= Together[y^(5/8)*(y^(19/8) - y^(73/24)/(y^(2/3) - 1/y^(1/3)))]
Out[5]= -y^3/(-1 + y)
In[6]:= Together[1/(x - k^(1/3)) + 1/(x + k^(1/3))]
Out[6]= -(2 x)/(k^(2/3) - x^2)
Options (1)¶
Applications (9)¶
Distinct denominators are multiplied
A common factor hidden across the denominators is cancelled
A telescoping sum collapses to 1
The exponential kernel is a generator of the rational function field
Combination over Q(Sqrt[2])
In[12]:= Together[1/(x - Sqrt[2]) + Sqrt[2]/(x^2 - 2), Extension -> Sqrt[2]]
Out[12]= (2 Sqrt[2] + x)/(-2 + x^2)
Logarithms stay opaque: Log[x^2] is not rewritten to 2 Log[x]
An unevaluated integral is an atom, never re-evaluated with a symbol inside
Threads over lists and equations
Inexact input is rationalised, combined and numericalised again
Options & behaviour¶
- Cube-and-higher-root towers (2026-07-04): a
Plusof fractions over radicalsPower[base, p/q]of any indexq ≥ 2whose radicand carries a free symbol (e.g.k^(1/3)) is combined over a common denominator via FLINT (flint_algebraic_field_together), with the radicals treated as free kernels — WL-faithful: radicals stay in the denominator, no rationalisation. This generalises the sqrt-only combiner to any index. The same path servesCancelsingle-fraction relation-dependent cancellations ((x^3-k)/(x-k^(1/3))) still go through the relation-aware GCD path.
Implementation notes¶
Algorithm. builtin_together is a FactorMemo-keyed memoisation wrapper around builtin_together_compute, so repeated Together[arg, opts] calls issued during one Simplify (which pushes a FactorMemo) hit the cache; standalone calls see no overhead. The compute routine puts everything over a common denominator and cancels.
Dispatch, FLINT build. builtin_together_compute first tries rat_canon_normalize(arg, RCM_TOGETHER) (src/poly/ratcanon.c) on exact, option-free input; MATHILDA_RATCANON=off turns this off. rat_canon_build replaces every kernel by a fresh indeterminate, giving one ordered generator tower. Transcendental kernels (Log, E^f, inverse trig) become free generators, and rt_expand_exp_sums first splits E^(a+b) so that commensurate exponentials share one fundamental. Algebraic generators (I, radicals, roots of unity) carry their minimal polynomial as a relation. rat_canon_reduce reduces num/den modulo those relations with flint_tower_reduce, maps back, and sign-normalises the result. It declines to the classical paths whenever a number-field common factor might be missed. Next come flint_cancel_fraction for algebraic extensions (including parametric Q(a, b)(Sqrt[k])) and then the plain-Q fmpz_mpoly_q fast path, both before the classical walker below. Since v0.434 two rules keep these paths value-preserving. Binding operators are opaque: poly_is_binding_operator marks unevaluated Integrate, D, Sum, Limit, Function, Hold*, Inactive[op][…] and similar heads as atoms, so the kernel substitution never descends into them and re-evaluates them with a symbol in place of the kernel. Logs are never expanded: Log[x^2] stays one generator rather than becoming 2 Log[x], which is false for x < 0.
The classical walker together_recursive recurses structurally. For a Plus[t_1, ..., t_n] it first togethers each summand, splits each into numerator/denominator via extract_num_den, computes the iterated PolynomialLCM of the denominators, then for each term forms lcm_den / den_i using cancel_exact_div_strict (exact polynomial division in Q[vars]) — a strict combine: if any quotient is not exact (a sign that PolynomialLCM was only valid in some algebraic-extension ring, e.g. multi-radical sums), it bails cleanly and leaves the Plus uncombined rather than risk the Power[Plus[...], -1]-inside-numerator GCD blowup. When all quotients are exact, it sums the rescaled numerators, multiplies by Power[lcm_den, -1], and runs cancel_recursive (PolynomialGCD-based cancellation) on the result. List/relational/logical heads thread through their args; other heads recurse and then cancel.
Crucially, together_recursive never expands Power[Plus[...], n] — extract_num_den only splits products, powers (pushing negative integer/rational exponents into the denominator), exponentials, complexes, and literal rationals; expansion is left to downstream poly-GCD with size gates. builtin_together_compute additionally handles Extension -> α (and Extension -> Automatic, which calls extension_autodetect): single-generator extensions route through together_recursive_ext over Q(α)[x]; multi-generator towers route through qa_cancel_with_tower, with nested-radical α prefiltered out and a "best generator" guided fallback (pick_best_tower_generator) gated on leaf count. A poly_find_radical_gen pass substitutes a radical generator to a fresh symbol, runs the no-extension path, and substitutes back. Inexact inputs are rationalised then re-numericalised (internal_rationalize_then_numericalize).
Data structures. Expr* trees; numerator/denominator pairs are plain Expr* out-parameters. Extension towers are QATower; exact division and LCM run on the multivariate-polynomial representation behind exact_poly_div / PolynomialLCM / PolynomialGCD. Numerator carries ATTR_LISTABLE.
Complexity / limits. Bounded by the polynomial GCD/LCM machinery on the combined fraction. The strict-quotient gate and the leaf-count gates are deliberate safeguards against multivariate-Euclid runaway on multi-radical / algebraic-extension inputs.
Protected,Listable.- Makes a sum of terms into a single rational function.
- Value-preserving on every kernel (2026-10-17). Transcendental kernels are
replaced by fresh generators only OUTSIDE variable-binding operators: an
unevaluated
Integrate/D/Sum/Product/Limit/Series, aFunction, anInactive[op][...]form or aHoldwrapper is an opaque atom (previouslyTogether[E^Cos[x] Integrate[E^-Cos[x], x]]returnedx, the generator having been substituted into the integrand and re-integrated).Log[...]arguments are never rewritten:Together[Log[x^2] + 1/x]is(1 + x Log[x^2])/x, not2 Log[x](false forx < 0), andLog[-w]is not split intoI Pi + Log[w]— matching Mathematica. The same holds forCancelandFactor. - Computes lowest common multiples (LCM) of denominators securely without unconditionally destroying pre-factored bases unnecessarily.
- Handles a single symbolic base appearing with rational fractional exponents (e.g.
y^(1/3),y^(2/3),y^(73/24)) by treating it as an algebraic generator: substitutesy -> g^mwheremis the LCM of denominators, runs the polynomial pipeline ing, then substitutes back. - Option
Extension -> alpha(Phase 0 of the Integrate plan) combines into a single fraction with the standard combiner, then runsCancel[..., Extension -> alpha]on the result so algebraic-coefficient cancellations fire. Effective on simple inputs like1/(x - Sqrt[2]) + 1/(x + Sqrt[2]), which collapses to(2 x)/(x^2 - 2). Inputs whose summands themselves carry algebraic-coefficient denominators are deferred to Phase 0.5 (which will plumbExtensionthroughPolynomialLCM/PolynomialQuotient/together_recursive). - Option
Extension -> Automaticwith polynomial radicands (Phase E, 2026-05-25): when the input contains exactly one distinct radicalSqrt[poly]orPower[poly, 1/q]whose radicand is a polynomial in free symbols (e.g.Sqrt[p+q],Power[1+x^2, 1/3]),qa_cancel_with_poly_radicalsubstitutes the radical with a fresh symbolS, runsTogether, reduces the numerator and denominator moduloS^q - polyviaPolynomialRemainder, optionally rationalises viaPolynomialExtendedGCD(when it shrinks the result), and substitutes back. Sample collapses:Together[1/(x - Sqrt[p+q]) + 1/(x + Sqrt[p+q]), Extension -> Automatic]returns(2 x)/(-p - q + x^2);Cancel[(x^2 - (p+q))/(x - Sqrt[p+q]), Extension -> Automatic]returnsSqrt[p+q] + x. Multi-radical inputs (Cardano-style conjugate pairs) are rejected; the deeper limitation is documented indocs/spec/changelog/2026-05-25.md. - Native
AlgebraicNumber-coefficient path. Same K(x) reduction asCancelabove, applied after combining the sum of fractions over a common denominator: a sum whose coefficients areAlgebraicNumber[θ, {..}]over one number field is combined and reduced natively over the antic number-field ring, value-equal to the generic path and fully reduced; declines on the multivariate case.
Attributes: Listable, Protected.
References¶
See also: Integrate, D, Sum, Product, Limit, Series, Function, Hold
- Geddes, Czapor & Labahn, "Algorithms for Computer Algebra" (1992), on rational function arithmetic and common denominators.
- von zur Gathen & Gerhard, "Modern Computer Algebra", on polynomial GCDs used in cancellation.
- Source:
src/rat.c - Specification:
docs/spec/builtins/algebra.md - Tests:
tests/test_cherry_dilog_exp.c - Tests:
tests/test_cherry_ei.c - Tests:
tests/test_cherry_polylog_exp.c - Tests:
tests/test_contfrac.c
Notes & additional examples¶
Notes¶
Together[expr]puts a sum of terms over a single common denominator and cancels the GCD of the result. It is the inverse ofApart. Unlike a full expansion, it does not multiply outPower[Plus, n]factors that it does not need to.- Kernels. Transcendental subexpressions (
Log[...],E^f, inverse trig) and algebraic constants (I, radicals) are treated as generators of the rational function field. Exponentials with commensurate exponents share one generator. Logarithms are left as they are, because rewritingLog[x^2]as2 Log[x]is false forx < 0. - Binding operators are atoms. Unevaluated
Integrate,D,Sum,Limit,Function,Hold*andInactive[op][...]are never looked inside. - Extension.
Extension -> α, a list, orAutomaticcombines over the number field. Plain algebraic constants are often handled without it. Listable,Protected. Symbolic only.- See also:
Cancel,Apart,Factor,Numerator,Denominator,Simplify.