@@ -632,6 +632,177 @@ static std::shared_ptr<SymbolicExpr> expand_power_integer(const std::shared_ptr<
632632 return distribute_multiply (base, rest);
633633}
634634
635+ // --- Trigonometric Simplifications ---
636+
637+ // Helper: matches c * pi or pi * c or pi
638+ // Returns pair {bool matched, Rational c}
639+ static std::pair<bool , Rational> match_pi_multiple (const std::shared_ptr<SymbolicExpr>& expr) {
640+ if (expr->type == SymbolicExpr::Type::Variable && (expr->identifier == " π" || expr->identifier == " pi" )) {
641+ return {true , Rational (1 )};
642+ }
643+
644+ if (expr->type == SymbolicExpr::Type::Multiply && expr->operands .size () == 2 ) {
645+ auto left = expr->operands [0 ];
646+ auto right = expr->operands [1 ];
647+
648+ bool left_is_pi = (left->type == SymbolicExpr::Type::Variable && (left->identifier == " π" || left->identifier == " pi" ));
649+ bool right_is_pi = (right->type == SymbolicExpr::Type::Variable && (right->identifier == " π" || right->identifier == " pi" ));
650+
651+ if (left_is_pi && right->is_number ()) return {true , right->convert_rational ()};
652+ if (right_is_pi && left->is_number ()) return {true , left->convert_rational ()};
653+ }
654+
655+ return {false , Rational (0 )};
656+ }
657+
658+ std::shared_ptr<SymbolicExpr> SymbolicExpr::simplify_sin () const {
659+ auto arg = operands[0 ]->simplify ();
660+
661+ // sin(0) = 0
662+ if (arg->is_number () && arg->convert_rational () == Rational (0 )) return SymbolicExpr::number (0 );
663+
664+ // sin(-x) = -sin(x)
665+ if (arg->type == SymbolicExpr::Type::Multiply && arg->operands .size () == 2 ) {
666+ if (arg->operands [0 ]->is_number () && arg->operands [0 ]->convert_rational () == Rational (-1 )) {
667+ // sin(-u) -> -sin(u)
668+ return SymbolicExpr::multiply (SymbolicExpr::number (-1 ), SymbolicExpr::sin (arg->operands [1 ]))->simplify ();
669+ }
670+ }
671+
672+ // Check for k * pi
673+ auto pi_match = match_pi_multiple (arg);
674+ if (pi_match.first ) {
675+ Rational k = pi_match.second ;
676+ // sin(n * pi) = 0 for integer n
677+ if (k.is_integer ()) return SymbolicExpr::number (0 );
678+
679+ // sin( (2n+1)/2 * pi ) = (-1)^n
680+ // k = n + 1/2 -> 2k = 2n + 1 an odd integer
681+ Rational two_k = k * Rational (2 );
682+ if (two_k.is_integer ()) {
683+ BigInt bk = two_k.get_numerator (); // This is 2k
684+ // Check if 2k is odd (not even)
685+ bool is_even = (bk._size == 0 ) || !(bk._data [0 ] & 1 );
686+ if (!is_even) {
687+ // n = (2k - 1) / 4 ?? No.
688+ // Let 2k = m (odd). k = m/2.
689+ // sin(m/2 * pi).
690+ // m = 1 (pi/2) -> 1
691+ // m = 3 (3pi/2) -> -1
692+ // m = 5 -> 1
693+ // Pattern: (m-1)/2 is even -> 1, odd -> -1 ?
694+ // m=1 -> 0 -> 1. m=3 -> 1 -> -1.
695+ // index = (m-1)/2. if index even -> 1.
696+
697+ // We need m % 4.
698+ // 1 % 4 = 1 -> 1
699+ // 3 % 4 = 3 -> -1
700+ // 5 % 4 = 1 -> 1
701+ // -1 % 4 = -1 -> 3 -> -1
702+
703+ BigInt m = bk;
704+ long long m_ll = 0 ;
705+ try { m_ll = std::stoll (m.to_string ()); } catch (...) { return SymbolicExpr::sin (arg); } // Too big
706+
707+ long long rem = m_ll % 4 ;
708+ if (rem < 0 ) rem += 4 ;
709+
710+ if (rem == 1 ) return SymbolicExpr::number (1 );
711+ if (rem == 3 ) return SymbolicExpr::number (-1 );
712+ }
713+ }
714+
715+ // Standard values: pi/6, pi/4, pi/3
716+ // sin(pi/6) = 1/2
717+ if (k == Rational (1 , 6 )) return SymbolicExpr::number (Rational (1 , 2 ));
718+ // sin(pi/4) = sqrt(2)/2
719+ if (k == Rational (1 , 4 )) {
720+ auto sq2 = SymbolicExpr::sqrt (SymbolicExpr::number (2 ));
721+ return SymbolicExpr::multiply (SymbolicExpr::number (Rational (1 , 2 )), sq2)->simplify ();
722+ }
723+ // sin(pi/3) = sqrt(3)/2
724+ if (k == Rational (1 , 3 )) {
725+ auto sq3 = SymbolicExpr::sqrt (SymbolicExpr::number (3 ));
726+ return SymbolicExpr::multiply (SymbolicExpr::number (Rational (1 , 2 )), sq3)->simplify ();
727+ }
728+ }
729+
730+ return SymbolicExpr::sin (arg);
731+ }
732+
733+ std::shared_ptr<SymbolicExpr> SymbolicExpr::simplify_cos () const {
734+ auto arg = operands[0 ]->simplify ();
735+
736+ // cos(0) = 1
737+ if (arg->is_number () && arg->convert_rational () == Rational (0 )) return SymbolicExpr::number (1 );
738+
739+ // cos(-x) = cos(x)
740+ if (arg->type == SymbolicExpr::Type::Multiply && arg->operands .size () == 2 ) {
741+ if (arg->operands [0 ]->is_number () && arg->operands [0 ]->convert_rational () == Rational (-1 )) {
742+ return SymbolicExpr::cos (arg->operands [1 ])->simplify ();
743+ }
744+ }
745+
746+ auto pi_match = match_pi_multiple (arg);
747+ if (pi_match.first ) {
748+ Rational k = pi_match.second ;
749+ // cos(pi) = -1, cos(2pi) = 1
750+ if (k.is_integer ()) {
751+ BigInt num = k.get_numerator ();
752+ bool num_even = (num._size == 0 || !(num._data [0 ] & 1 ));
753+ if (num_even) return SymbolicExpr::number (1 );
754+ else return SymbolicExpr::number (-1 );
755+ }
756+
757+ // cos(pi/2 + n*pi) = 0
758+ Rational two_k = k * Rational (2 );
759+ if (two_k.is_integer ()) {
760+ BigInt bk = two_k.get_numerator ();
761+ bool bk_even = (bk._size == 0 || !(bk._data [0 ] & 1 ));
762+ if (!bk_even) return SymbolicExpr::number (0 );
763+ }
764+
765+ // cos(pi/6) = sqrt(3)/2
766+ if (k == Rational (1 , 6 )) {
767+ auto sq3 = SymbolicExpr::sqrt (SymbolicExpr::number (3 ));
768+ return SymbolicExpr::multiply (SymbolicExpr::number (Rational (1 , 2 )), sq3)->simplify ();
769+ }
770+ // cos(pi/4) = sqrt(2)/2
771+ if (k == Rational (1 , 4 )) {
772+ auto sq2 = SymbolicExpr::sqrt (SymbolicExpr::number (2 ));
773+ return SymbolicExpr::multiply (SymbolicExpr::number (Rational (1 , 2 )), sq2)->simplify ();
774+ }
775+ // cos(pi/3) = 1/2
776+ if (k == Rational (1 , 3 )) {
777+ return SymbolicExpr::number (Rational (1 , 2 ));
778+ }
779+ }
780+
781+ return SymbolicExpr::cos (arg);
782+ }
783+
784+ std::shared_ptr<SymbolicExpr> SymbolicExpr::simplify_tan () const {
785+ auto arg = operands[0 ]->simplify ();
786+
787+ if (arg->is_number () && arg->convert_rational () == Rational (0 )) return SymbolicExpr::number (0 );
788+
789+ if (arg->type == SymbolicExpr::Type::Multiply && arg->operands .size () == 2 ) {
790+ if (arg->operands [0 ]->is_number () && arg->operands [0 ]->convert_rational () == Rational (-1 )) {
791+ return SymbolicExpr::multiply (SymbolicExpr::number (-1 ), SymbolicExpr::tan (arg->operands [1 ]))->simplify ();
792+ }
793+ }
794+
795+ // tan(pi/4) = 1
796+ auto pi_match = match_pi_multiple (arg);
797+ if (pi_match.first ) {
798+ Rational k = pi_match.second ;
799+ if (k == Rational (1 , 4 )) return SymbolicExpr::number (1 );
800+ if (k.is_integer ()) return SymbolicExpr::number (0 );
801+ }
802+
803+ return SymbolicExpr::tan (arg);
804+ }
805+
635806/*
636807std::shared_ptr<SymbolicExpr> SymbolicExpr::expand() const {
637808 // Moved to symbolic_poly.cpp
0 commit comments