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 17590 days, 6 hours, 39 minutes ago.