solvingTransformations.frink

View or download solvingTransformations.frink in plain text format


// 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 double-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] ]


   // 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 + (_c:1) _x, _x] <-> solve[_x (_a + _c) + _b, _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]]

   // 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 cubed terms:
   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] <-> [ solve[_x === -_b/(3 _a) -
      1/(3 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) + ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3) -
      1/(3 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) - ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3), _x],
   
      solve[_x === -_b/(3 _a) +
         (1 + i (3)^(1/3))/(6 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) + ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3) +
         (1 - i (3)^(1/3))/(6 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) - ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3), _x],
   
      solve[_x === -_b/(3 _a) +
         (1 - i (3)^(1/3))/(6 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) + ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3) +
         (1 + i (3)^(1/3))/(6 _a) (1/2 (2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d) - ((2 _b^3 - 9 _a _b _c + 27 _a^2 (-_d))^2 - 4 (_b^2 - 3 _a _c)^3)^(1/2)))^(1/3), _x]]

   // 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.
   0 _x <-> 0

   
//   0 + _x <-> _x

   1 _x <-> _x

   ln[e] <-> 1

   e^ln[_x] <-> _x

   // 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

//   (_a + _b)^_k :: isInteger[_k] AND _k >= 2  <->  (_a^2 + 2 _a _b + _b^2)(_a + _b)^(_k-2)
}


"solvingTransformations.frink included ok!"


View or download solvingTransformations.frink in plain text format


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 17592 days, 15 hours, 20 minutes ago.