asc-community / asc-community/AngouriMath

Nothing writes an expression as a single quotient: no together / ratsimp

Open
#1,239 0 comments 0 reactions 0 assignees View on GitHub
Proposal
Dominant language
C#
Stars
831
Forks
79
Avg merge
3h 23m
Merged PRs (30d)
309

Description

There is no operation that writes an expression as a **single quotient**. `Simplify` never combines a sum over a common denominator, at any level:

```
"1 + 2/(1+t^2)" Simplify -> 1 + 2 / (1 + t ^ 2)
"3 + 10*t/(t^2+1)" Simplify -> 3 + 10 * t / (t ^ 2 + 1)
"1/(t^2+1) + 1/(t+1)" Simplify -> 1 / (1 + t ^ 2) + 1 / (1 + t)
"a + b/c" Simplify -> a + b / c
```

`Simplify(5)` gives the same. `Transformation.Rewriting(RewriteRules.CollapseMultipleFractions)` does not do it either — that one moves nesting around without combining terms. `Transformation.Rationalization` is about clearing a surd from a denominator, which is a different job.

This is not a defect in `Simplify`. Putting a sum over a common denominator is a *choice* that makes some expressions worse, which is why other systems keep it as a separate operation — SymPy has `together()`, Maxima has `ratsimp`, Mathematica has `Together`. **We do not have it at all**, and that is the gap.

### Where it bites

It is the blocker for the rest of the half-angle substitution family added in #1238. That rewrite turns a rational function of sine and cosine into a rational function of `t = tan(x/2)`, and partial fractions answers the result — but only when the result is a single `Divf` of two polynomials. Where the rewrite leaves a sum with a fraction in it, nothing downstream can read it:

| integrand | rewrites to | outcome |
|---|---|---|
| `1/(1+cos(x))` | `1` | answered, `tan(x/2)` |
| `1/sin(x)` | `2/(1+t^2) / (2t/(1+t^2))`, which collapses | answered, `ln(tan(x/2))` |
| `1/(1-sin(x))` | `2/((t^2+1) * (1 + (-2)t/(t^2+1)))` | **declined** |
| `1/(1+cos(x)/2)` | `2/((t^2+1) * (1 + (2/(t^2+1) - 1)/2))` | **declined** |
| `1/(2cos(x)+3sin(x))` | same shape | **declined** |

Every declined row needs one step: distribute the outer factor into the bracket. `(t^2+1) * (1 + (-2)t/(t^2+1))` is `t^2 - 2t + 1`, and then partial fractions answers it immediately.

I checked by hand that the algebra is otherwise right — building the quotient manually gives `2/(1 + t^2 - 2t)` for the third row, which is `2/(t-1)^2` — so the substitution and the integrator are both fine and only the intermediate shape is in the way.

### What it would take

A transformation that writes an expression as `numerator / denominator` with a single division at the root: recursively, a sum of quotients becomes one quotient over the product of the denominators, and a product of quotients multiplies through. It wants to be an explicit operation rather than part of `Simplify`, for the reason every other system keeps it separate.

Beyond unblocking the above, it is independently useful — it is a thing users ask a CAS to do — and it would feed partial fractions generally, since that already wants its input in exactly this shape and currently just declines anything that is not.

Contributor guide

Open the contributing guide

Research direction

Start by locating Transformation.Rewriting, RewriteRules.CollapseMultipleFractions, Transformation.Rationalization, and the existing partial-fractions entry point; read how expression sums, products, and Divf are represented. Compare the listed examples, and consider the work complete when an explicit operation produces one root-level quotient and enables the declined half-angle rows to reach partial fractions.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.