Skip to content

Simplify() does not handle complex trigonometrical statements well #557

Closed

Description

@Julpe

I am using the latest release 1.3.0 for my .NET project.

Calling .Simplify() on Entitys which contain complex trigonometrical statements such as
(sin(2*theta)*csc(theta))^2/4-cos(2*theta)-sin(theta)^2
or
(cos(2*theta)*sin(theta)^6*(-1)+cos(theta)*sin(theta)^5*sin(2*theta)-sin(2*theta)^2*sin(theta)^4/4)/sin(theta)^8-1+(sin(2*theta)*csc(theta))^2/4-cos(2*theta)-sin(theta)^2
are not simplified to 0 (as i am expecting).

Activity

  1. added this to the 1.4 milestone on Jan 4, 2022
  2. Rafael-SOWNet commented on Aug 5, 2026

    @Rafael-SOWNet
    Member

    Re-measured on master. The first expression is answered; the second is not.

    simplify((sin(2*t)*csc(t))^2/4 - cos(2*t) - sin(t)^2)
    =>  0 provided not sin(t) = 0
    

    That is the right answer rather than a partial one: csc(t) is undefined where sin(t) = 0, so the identity holds everywhere the input is defined and the condition records exactly where it is not. An unconditional 0 would be claiming something false at t = 0.

    The longer one does not reach 0:

    simplify((cos(2*t)*sin(t)^6*(-1) + cos(t)*sin(t)^5*sin(2*t) - sin(2*t)^2*sin(t)^4/4)/sin(t)^8
             - 1 + (sin(2*t)*csc(t))^2/4 - cos(2*t) - sin(t)^2)
    =>  -cos(2*t)/sin(t)^2 - (cos(2*t) + 1) + cos(t)*sin(2*t)/sin(t)^3 - sin(t)^2
        + (sin(2*t)^2*sin(t)^4 - (sin(2*t)*sin(t))^2)/(4*sin(t)^6)
    

    Note the last term: sin(2t)^2*sin(t)^4 - (sin(2t)*sin(t))^2 is visibly zero, and it is left standing. So this is not really a trigonometric gap -- it is that a difference of two products which are the same product up to how they associate does not cancel, and here it sits over a denominator so nothing collects it. That is the multivariate polynomial cancellation in #55 rather than a missing trig identity.

    Leaving open for the second case, with the cause recorded above so whoever picks it up starts from the right place.

  3. Rafael-SOWNet commented on Aug 5, 2026

    @Rafael-SOWNet
    Member

    Measured against master at 5f1a003, and the two expressions in this report are now in different places.

    The first is answered:

    (sin(2*theta)*csc(theta))^2/4 - cos(2*theta) - sin(theta)^2
        =>  0 provided not sin(theta) = 0
    

    The condition is right rather than a shortfall — a cosecant is undefined where the sine vanishes, and 0 alone would claim a value at a point the expression does not reach.

    The second is not, and what is missing is now a single identified thing. It reduces as far as

    1 / sin(theta) ^ 2 - (1 + cotan(theta) ^ 2)
    

    which is a difference of two equal things left in two notations. Everything else the expression needs is already in the library: the multiple-angle expansion opens sin(2*theta), and the rational cancellation over sines and cosines works.

    What is left is #725 — the Pythagorean identity is matched as a pattern, so the two parts have to be adjacent in the tree. Written on its own each half reduces (1 + cotan(t)^2 is csc(t)^2, and csc(t)^2 - 1/sin(t)^2 is 0), but in a sum of three terms the sorting separates the pair before the rules are tried. #726 fixes the arrangements that are adjacent; reaching the rest wants the identity stated over the gathered terms of a sum, which is a larger change and is recorded there as a skipped test carrying the diagnosis rather than claimed.

    Both of the reporter's expressions are pinned in PythagoreanIdentityTest: the first as a passing assertion, the second as that skipped record. Leaving this issue open for the second.

  4. Rafael-SOWNet commented on Aug 5, 2026

    @Rafael-SOWNet
    Member

    Both of your expressions now simplify to 0. Fixed in #732 (with #726 and the double-angle work before it), merged to master.

    (sin(2*t)*csc(t))^2/4 - cos(2*t) - sin(t)^2                    =>  0 provided not sin(t) = 0
    (cos(2*t)*sin(t)^6*(-1) + cos(t)*sin(t)^5*sin(2*t)
     - sin(2*t)^2*sin(t)^4/4)/sin(t)^8 - 1
     + (sin(2*t)*csc(t))^2/4 - cos(2*t) - sin(t)^2                 =>  0 provided not sin(t) = 0
    

    The condition is correct rather than a hedge: your expressions contain csc(t) and a denominator of sin(t)^8, so they are undefined where sin(t) = 0 and 0 everywhere else.

    Why the second took longer than the first. Three separate things were missing, and only the last was about your second expression specifically:

    1. Nothing opened a symbolic double angle. sin(2t) and cos(2t) were only ever written out for numeric multiples of pi, so cos(2t) - (1 - 2sin(t)^2) did not reduce to zero either. Fixed first, and that settles your first expression.
    2. The Pythagorean identity was one syntactic pattern -- an adjacent sum of the two squares -- so 1 - sin^2, 1 + tan^2, sec^2 - tan^2 and the rest of the same fact were each unrecognised. That is The other two Pythagorean identities are not known #725, fixed in Know the Pythagorean identity in more than one arrangement (#725) #726.
    3. The opened form was judged before it could pay off. Opening a multiple angle is offered to the simplifier as a candidate rather than taken, because written out sin(4x) is longer than it started and a complexity metric decides. That judgement is right; what was wrong is the form it was asked to judge. The opened form was handed to the trigonometric rules only -- enough for an expression that is already one term. Your second expression is a quotient, and it cancels only once its terms are over a common denominator; the passes that build one run earlier, while the angles are still shut. So the metric saw the opened form with none of its payoff collected and rightly rejected it as the longer of the two.

    The last one is easy to see in isolation -- the same number, and only the shut form failed:

    (sin(t)^6 - (2*sin(t)*cos(t))^2*sin(t)^4/4)/sin(t)^8 - 1   =>  0     // already worked
    (sin(t)^6 - sin(2*t)^2*sin(t)^4/4)/sin(t)^8 - 1            =>  ...   // not reduced
    

    The opened form is now simplified in full, and expanded, before being offered -- which is what Expand() and Factorize() already got. Multiple angles that do not cancel keep their compact form: sin(4x), cos(6x) and sin(3x) are unchanged and sin(2x)*cos(2x) still collapses to sin(4x)/2.

    Tests in DoubleAngleOverSineTest.cs pinning both of your expressions and the pieces they are built from. Full suite green, 117-problem corpus unchanged.

  5. added theissue type on Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions