# solvingTransformations.frink

``` // These transformations try to solve simple equations and teach Frink to // solve basic algebraic equations for the specified variable. // //  For example, enter: //    solve[3(x+y) === 10, x] // // (Right now this requires the triple-equals sign because Frink currently //  requires that the left-hand-side of an assignment operator //  ( = ) can actually be meaningfully assigned to, which may be // a constraint that needs to get loosened for temporary values. // This creates a named list of transformations called "solving" that we // can apply by name later. transformations solving {    // Change sqrt[x] into a power.    sqrt[_x] <-> _x^(1/2)    // Move the variable we're solving for to the left side of the equation    // if it's only on the right side of the equation.    solve[_left === _right, _x] :: (freeOf[_left, _x] AND expressionContains[_right, _x])  <-> solve[_right === _left, _x]    // Bailout condition    solve[_x === _z, _x] :: freeOf[_z, _x]  <-> _x === _z    // Quadratic equations     solve[(_a:1) _x^2 + (_b:1) _x === _c, _x] :: freeOf[_c, _x] <-> [ solve[_x === (-_b + (_b^2 - 4 _a (-_c))^(1/2)) / (2 _a), _x], solve[_x === (-_b - (_b^2 - 4 _a (-_c))^(1/2)) / (2 _a), _x] ]    // Quadratic equation kludge.    // Distributing something like (2x + 3p)(3x + 1) gives a result like    // (6 x^2 + 9 p x + 2 x + 3p) which is a quadratic equation but has two    // terms of x.  This handles that common case in an inelegant way.    // TODO:  Find a better solution for this and remove it.    solve[(_a:1) _x^2 + (_b1:1) _x + _b2 _x === _c, _x] :: freeOf[_c, _x] <-> [ solve[_x === (-(_b1 + _b2) + ((_b1 + _b2)^2 - 4 _a (-_c))^(1/2)) / (2 _a), _x],solve[_x === (-(_b1 + _b2) - ((_b1 + _b2)^2 - 4 _a (-_c))^(1/2)) / (2 _a), _x] ]    // If both sides have an x, divide out x terms from right. //   solve[_a === (_c:1) _x^(_b:1), _x] :: expressionContains[_a, _x] <-> solve[_a / _x^_b === _c, _x]    // First move additive terms    // Move all x-containing terms to left    solve[_a === _c, _x] :: (expressionContains[_a, _x] && expressionContains[_c, _x]) <-> solve[_a - _c === 0, _x]    // Move all non-x-containing terms to right.     solve[_a + _b === _c, _x] :: (freeOf[_a,_x] AND expressionContains[_b, _x]) <-> solve[_b === _c - _a, _x]    // Then move multiplicative terms.    solve[_a * _b === _c, _x] :: (freeOf[_a,_x] AND expressionContains[_b, _x]) <-> solve[_b === _c / _a, _x]    // Flip inverse exponents.    solve[_a^_k is isNegative === _b, _c] :: expressionContains[_a, _c] <-> solve[_a^-_k === _b^-1, _c]    // Solve for two terms containing c    solve[_a _c + (_b:1) _c === _d, _c] :: freeOf[_a, _c] && freeOf[_b, _c] && freeOf[_d,_c] <->  solve[_c === _d / (_a + _b), _c]    // Solve for negative and positive exponents on same side.    solve[(_c1:1) _a^_k is isNegative + (_c2:1) _a^(_j:1) === _b, _c] :: expressionContains[_a, _c] && freeOf[_c1, _c] && freeOf[_c2, _c] <-> solve[_c1 + _c2 _a^(_j-_k) === _b _a^-_k, _c]    // Very general negative and positive exponents on same side.    solve[(_a:1) _x^_b is isNegative + _c === _d, _x] :: expressionContains[_c, _x] <-> solve[_a + _c _x^-_b === _d _x^-_b, _x]    // Help the solver to factor an expression.    solve[(_a:1) _x^_b + _c _x^_b === _d, _x] <-> solve[_x^_b === _d / (_a + _c), _x]    // x in numerator and denominator (denominator has additive term.)    solve[(_b:1) _x / ((_a:1) _x + _y) === _z, _x] :: freeOf[_b, _x] && freeOf[_a, _x] && freeOf[_y, _x]  <-> solve[_x === _z (_a _x + _y) / _b, _x]    // x in denominator of complicated fraction and outside fraction.    solve[(_a:1) _x + (_b:1) / _d === _e, _x] :: expressionContains[_d, _x] <-> solve[_a _x _d + _b === _e _d, _x]    // Solve for squared terms.    // Results are a list of two different solutions.    solve[_a^_k is isPositive === _b, _c] :: expressionContains[_a, _c] AND (_k mod 2 == 0) <-> [ solve[_a^(_k/2) === _b^(1/2),_c] , solve[_a^(_k/2) === -_b^(1/2), _c ] ]    // a x +  b (d+ (c x)^(1/2)) === z //   solve[(_a:1) _x + (_b:1) ((_d:0) + ((_c:1) _x)^(1/2)) === _z, _x] :: freeOf[_a, _x] and freeOf[_b,_x] and freeOf[_c, _x] and freeOf[_d, _x] and freeOf[_z, _x] <-> [ solve[sqrt[-4 _a _b^3 _c _d + 4 _a _b^2 _c _z + _b^4 _c^2] - 2 _a _b _d + 2 _a _z + _b^2 _c, _x], solve[-sqrt[-4 _a _b^3 _c _d + 4 _a _b^2 _c _z + _b^4 _c^2] - 2 _a _b _d + 2 _a _z + _b^2 _c, _x] ]    // Force grouping of terms together.  Note that this is the inverse of the    // distributive transform below and could cause loops.    solve[(_a:1) _x + (_b:1) _x + (_c:0), _x] <-> solve[_x (_a + _b) + _c, _x]        // a x^(1/2) + b x== d    //   solve[((_a:1) _x^(1/2)) + (_b:1) _x  === _d, _x] :: freeOf[_a, _x] and freeOf[_b,_x] and freeOf[_d, _x] <-> [ solve[_x === (_a sqrt[_a^2 + 4 _b _d] + _a^2 + 2 _b _d)/(2 _b^2), _x], solve[_x === (-_a sqrt[_a^2 + 4 _b _d] + _a^2 + 2 _b _d)/(2 _b^2), _x]]    // General solving help when a term includes x + x^(1/2) terms.    // Shift the x^(1/2) term to one side of the equals sign and square both    // sides.  This generally lets it be solved by the quadratic equation.    solve[_a + (_d:1) _b^(1/2) === _c, _x] :: expressionContains[_a, _x] and expressionContains[_b, _x] and freeOf[_c, _x] and freeOf[_d, _x]   <-> solve[(_a - _c)^2 === _d^2 _b, _x]    // General solving help when a term includes x *  x^(1/2) terms.    // Shift the x^(1/2) term to one side of the equals sign and square both    // sides.    solve[_a _b^(1/2) + (_d:0) === _c, _x] :: expressionContains[_a, _x] and expressionContains[_b, _x] and freeOf[_c, _x]   <-> solve[_b _a^2 === (_c-_d)^2, _x]    // General solving help when a term includes x *  x^(-1/2) terms.    // Shift the x^(-1/2) term to one side of the equals sign and square both    // sides.    solve[_a _b^(-1/2) + (_d:0) === _c, _x] :: expressionContains[_a, _x] and expressionContains[_b, _x] and freeOf[_c, _x]   <-> solve[_b === a^2 / (_c-_d)^2, _x]    // General solving help when a term contains a x + b (c + d x)^2 terms.    // Expand out (c + d x) which usually allows the equation to be solved    // with the quadratic equation.    // TODO:  Generalize this for cubed terms, etc    solve[(_a:1) + (_b:1) (_c + (_d:1) _x)^2 === _f, _x] :: expressionContains[_a, _x] and freeOf[_c, _x] and freeOf[_f, _x] <-> solve[_a + _b (_c^2 + 2 (_c _d _x) + _d^2 _x^2) === _f, _x]        // a x (b + c x^2)^(-1/2) == d //   solve[(_a:1) _x (_b + (_c:1) _x^2)^(-1/2) === _d, _x]  <-> [solve[_x === i _b^(1/2) _d / (_c _d^2 - _a^2)^(1/2), _x], solve[_x === -i _b^(1/2) _d / (_c _d^2 - _a^2)^(1/2), _x]]    // _a + (_b + _x)^2 == d  with a containing x.  Multiply out the parens.    solve[_a + (_b + (_c:1) _x)^2 === _d, _x] :: expressionContains[_a, _x] <-> solve[_a + _b^2 + 2 _b _c _x + _c^2 _x^2 === _d, _x]    // Factor out 3 terms.  TODO:  Generalize this!    solve[(_a:1) _x + _b _x + _c _x === _d, _x] <-> solve[(_a + _b + _c) _x === _d, _x]        // Solve for powers of 3, 6, 9, etc.    solve[_a^_k is isPositive === _b, _c] :: expressionContains[_a, _c] AND (_k mod 3 == 0) <-> [ solve[_a^(_k/3) === _b^(1/3),_c] , solve[_a^(_k/3) === -((-1)^(1./3)) _b^(1/3), _c ], solve[_a^(_k/3) === ((-1)^(2./3)) _b^(1/3), _c ] ]        // Solve for rational exponents    solve[_a^_k is isRational === _b, _c] :: expressionContains[_a, _c] <->  solve[_a === _b^(1/_k),_c]        // Gah!  Cubic equations!    // See http://en.wikipedia.org/wiki/Cubic_function#General_formula_of_roots    // TODO:  Find a way to store repeated temporary parts of results into variables.    // TODO:  Handle cases where b or c or both are 0!    solve[(_a:1) _x^3 + (_b:1) _x^2 + (_c:1) _x === _d, _x] :: freeOf[_d, _x] <-> [x === -_b/(3 _a) - (2^(1/3) (-729 _a^4 _b^2 + 2187 _a^5 _c))/(2187 _a^3 (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3)) + (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3)/(3 2^(1/3) _a^3) && _a != 0,     (x === -_b/(3 _a) + ((1 + i sqrt) (-729 _a^4 _b^2 + 2187 _a^5 _c))/(2187 2^(2/3) _a^3 (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3)) - ((1 - i sqrt) (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3))/(6 2^(1/3) _a^3) && _a != 0),    (x === -_b/(3 _a) + ((1 - i sqrt) (-729 _a^4 _b^2 + 2187 _a^5 _c))/(2187 2^(2/3) _a^3 (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3)) - ((1 + i sqrt) (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt sqrt[-(_a^14 _b^2 _c^2) + 4 _a^15 _c^3 + 4 _a^14 _b^3 _d - 18 _a^15 _b _c _d + 27 _a^16 _d^2])^(1/3))/(6 2^(1/3) _a^3) && _a != 0),    (x === (-_c - sqrt[_c^2 - 4 _b _d])/(2 _b) && _a === 0 && _b != 0),    (x === (-_c + sqrt[_c^2 - 4 _b _d])/(2 _b) && _a === 0 && _b != 0),    (x === -(_d/_c) && _b === 0 && _a === 0 && _c != 0)]        // Replace floating-point approximation to zero with integer 0.    0. <-> 0        // Some simplifying rules that actually aren't appropriate if you're    // tracking units.  These are not really valid because 0 feet != 0 days    // and 0 feet + 0 is not units-correct.    // TODO:  FIX THIS!   We need a pattern that matches units with magnitude    // of zero.    0 _x <-> 0 //   0 + _x <-> _x    1 _x <-> _x    ln[e] <-> 1    ln <-> 0    log <-> 1    log <-> 0    log[_a, _b] <-> ln[_a] / ln[_b]    // This transforms rules in terms of log base 10 into equations of    // natural log.  This makes a lot of different types of equations more    // readily solved by already-existing rules:  for example, LambertW rules,    // (see powerTransformations.frink)    // and eliminates the need to rewrite all of these rules in multiple forms.    log[_a] <-> ln[_a] / ln    // Simplifying rule    e^ln[_x] <-> _x        // Simplifying rule    e^(_a ln[_b]) <-> _b^_a    // Simplifying rule    ln[_a ^ _b] <-> _b ln[_a]    // Simplifying rule    log[_a ^ _b] <-> _b log[_a]    // Exponentiate out parts.    (_a _b)^_c <-> _a^_c _b^_c         // Distribute (to often clarify and simplify)    // (Note: this is often disadvantageous when using    // interval arguments as intervals are subdistributive and the result    // may be wider.)    _a (_c + _d) <-> _a _c + _a _d    // Combine coefficients of x;    // This may cause loops with the above expression. //   _a _x + _b _x + (_c:0) <-> (_a + _b) _x + _c //   (_a + _b)^_k :: isInteger[_k] AND _k >= 2  <->  (_a^2 + 2 _a _b + _b^2)(_a + _b)^(_k-2) } "solvingTransformations.frink included ok!" ```

This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 18376 days, 23 hours, 57 minutes ago.