/** This contains sloppy and non-rigorous solvers for equations containing trigonometric equations. It is only intended for real-valued arguments and will not find all solutions. It is used as a starting point only. THINK ABOUT: Will it be better to transform functions to be in terms of sin and cos when possible? (Especially sec, csc, cot, etc., but maybe also tan and hyperbolic functions?) This will greatly reduce the number of solvers that we have to write. TODO: Maybe implement some more simplifiers from here: https://en.wikipedia.org/wiki/Inverse_trigonometric_functions */ transformations solveTrigonometric { // Trig solvers solve[sin[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arcsin[_y], _theta] solve[cos[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arccos[_y], _theta] solve[tan[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arctan[_y], _theta] // Inverse trig solvers solve[arcsin[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === sin[_y], _theta] solve[arccos[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === cos[_y], _theta] solve[arctan[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === tan[_y], _theta] solve[arctan[_y, _x1] === _a, _x] :: expressionContains[_x1, _x] <-> solve[_x1 === - i _y (i sin[2 _a] + cos[2 _a] - 1) / (i sin[2 _a] + cos[2 _a] + 1), _x] solve[arctan[_y1, _x] === _a, _y] :: expressionContains[_y1, _y] <-> solve[_y1 === i _x (i sin[2 _a] + cos[2 _a] + 1) / (i sin[2 _a] + cos[2 _a] - 1), _y] // Hyperbolic trig function solvers solve[sinh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arcsinh[_y], _theta] solve[cosh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arccosh[_y], _theta] solve[tanh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === arctanh[_y], _theta] // Inverse hyperbolic trig function solvers solve[arcsinh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === sinh[_y], _theta] solve[arccosh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === cosh[_y], _theta] solve[arctanh[_a] === _y, _theta] :: expressionContains[_a, _theta] <-> solve[_a === tanh[_y], _theta] // Function and its inverse sin[arcsin[_x]] <-> _x cos[arccos[_x]] <-> _x tan[arctan[_x]] <-> _x arcsin[sin[_x]] <-> _x arccos[cos[_x]] <-> _x arctan[tan[_x]] <-> _x sinh[arcsinh[_x]] <-> _x cosh[arccosh[_x]] <-> _x tanh[arctanh[_x]] <-> _x arcsinh[sinh[_x]] <-> _x arccosh[cosh[_x]] <-> _x arctanh[tanh[_x]] <-> _x // Simplifying functions // See: https://en.wikipedia.org/wiki/Inverse_trigonometric_functions cos[arcsin[_x]] <-> sqrt[1 - _x^2] tan[arcsin[_x]] <-> _x / sqrt[1 - _x^2] sin[arccos[_x]] <-> sqrt[1 - _x^2] tan[arccos[_x]] <-> sqrt[1 - _x^2] / _x sin[arctan[_x]] <-> _x / sqrt[1 + _x^2] cos[arctan[_x]] <-> 1 / sqrt[1 + _x^2] // Turn csc, sec, cot into expressions in terms of sin, cos, tan. // This lets us write many fewer solving rules! // Should tan (and tanh) be turned into sin[x]/cos[x] and sinh[x]/cosh[x]? // Or should sin[x]/cos[x] be turned into tan[x]? The latter seems to // make solving certain equations easier. And we now do that below. sec[_x] <-> 1 / cos[_x] csc[_x] <-> 1 / sin[_x] cot[_x] <-> 1 / tan[_x] arcsec[_x] <-> arccos[1 / _x] arccsc[_x] <-> arcsin[1 / _x] arccot[_x] <-> arctan[1 / _x] sech[_x] <-> 1 / cosh[_x] csch[_x] <-> 1 / sinh[_x] coth[_x] <-> 1 / tanh[_x] arcsech[_x] <-> arccosh[1 / _x] arccsch[_x] <-> arcsinh[1 / _x] arccoth[_x] <-> arctanh[1 / _x] // Simplify terms that have both sin and cos terms // And sinh and cosh terms // by casting them in terms of tan and tanh respectively. (_c:1) sin[_x] / cos[_x] <-> _c tan[_x] (_c:1) cos[_x] / sin[_x] <-> _c / tan[_x] (_c:1) sinh[_x] / cosh[_x] <-> _c tanh[_x] (_c:1) cosh[_x] / sinh[_x] <-> _c / tanh[_x] // This is a generalization of // // sin[x]^2 + cos[x]^2 = 1 // // If there is a sin[x]^2 term (multiplied by something) plus a // cos[x]^2 term (multiplied by something), // // it turns the cos[x]^2 term into // 1 - sin[x]^2 // // And then solves the rest. (_a:1) cos[_x]^2 + (_b:1) sin[_x]^2 + (_c:0) <-> _a (1 - sin[_x]^2) + (_b sin[_x]^2) + _c // Some special values. These make Taylor series around 0 work much better sin[0] <-> 0 cos[0] <-> 1 tan[0] <-> 0 sinh[0] <-> 0 cosh[0] <-> 1 tanh[0] <-> 0 arcsin[0] <-> 0 arccos[0] <-> pi/2 arctan[0] <-> 0 arcsinh[0] <-> 0 arccosh[0] <-> i pi/2 arctanh[0] <-> 0 // These make Taylor series around pi work better. TODO: Extend and // generalize this to ratios of pi. When using these in a function like // TaylorSeries.frink, you may have to wrap pi in a noEval[pi] initially. cos[pi] <-> -1 sin[pi] <-> 0 }