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: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]
   
   // 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] <-> [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[3] 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[3] 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[3]) (-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[3] 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[3]) (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt[3] 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[3]) (-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[3] 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[3]) (-2 _a^6 _b^3 + 9 _a^7 _b _c - 27 _a^8 _d + 3 sqrt[3] 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[1] <-> 0
   log[10] <-> 1
   log[1] <-> 0
   log[_a, _b] <-> ln[_a] / ln[_b]

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


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 18234 days, 20 hours, 55 minutes ago.