functionUtils.frink

View or download functionUtils.frink in plain text format


/** This class contains functions for working with parts of a function, or
    transforming functions, like taking their derivatives.

    See functionUtilsTest.frink for an example of its usage.
*/


/** This returns the body of a function as an expression.
    The argument passed in can be a named function (a FunctionDescriptor) or
    an anonymous function (Function) 
*/

functionBody[f] :=
{
   func = undef
   if type[f] == "FunctionDescriptor"
      func = getChild[f,1]  // Child 1 is Function
   else
      if type[f] == "Function"
         func = f

   return getChild[func,1]
}


/** This returns an array of function argument names as strings. */
functionArguments[f] :=
{
   func = undef
   if type[f] == "FunctionDescriptor"
      func = getChild[f,1]  // Child 1 is Function
   else
      if type[f] == "Function"
         func = f

   args = getChild[func, 0]   // This is an array of FunctionArguments
   retval = new array      
   for arg = args      
      retval.push[getChild[arg, 0]]  // Argument name as string
   
   return retval
}


/** This returns an array of function arguments as Symbols. */
functionArgumentsAsSymbols[f] :=
{
   retval = new array
   for arg = functionArguments[f]
      retval.push[constructExpression["Symbol", [arg]]]

   return retval
}


/** Create a symbol with the name of the given string. */
makeSymbol[s] :=
{
   if type[s] == "Symbol"
      return s
   else
      return constructExpression["Symbol", [s]]
}


/** Create a derivative expression of the specified function.  It currently
    assumes that the function only has one argument.

    This will create a function call expression of the form:
    D[expr, symbol]

    Which can then be passed to transformExpression[]
    (once you have loaded a file like derivatives.frink) to actually
    symbolically evaluate the derivative.  At the moment, we don't do that in
    this library so as not to create a dependency on a file that may change.

    This, of course, will not behave properly if the function body is not
    simple and directly differentiable.
*/

makeDerivative[f] :=
{
   makeDerivativeFunction[functionBody[f], functionArgumentsAsSymbols[f]@0]
}


/** Create a Derivative function of the specified expression and symbol to
    take the derivative with respect to.  This will create a function call
    expression of the form:
    D[expr, symbol]

    Which can then be passed to transformExpression[]
    (once you have loaded a file like derivatives.frink) to actually
    symbolically evaluate the derivative.  At the moment, we don't do that in
    this library so as not to create a dependency on a file that may change.

    REMINDER:  You may need to wrap expr or symbol in a noEval[] block if
    passing in a literal expression
*/

makeDerivativeFunction[expr, symbol] :=
{
   if type[symbol] == "String"
      symbol = makeSymbol[symbol]

   return constructExpression["Function", ["D", expr, symbol]]
}

/** Create a integral expression of the specified function.  It currently
    assumes that the function only has one argument.

    This will create a function call expression of the form:
    D[expr, symbol]

    Which can then be passed to transformExpression[]
    (once you have loaded a file like integrals.frink) to actually
    symbolically evaluate the integral.  At the moment, we don't do that in
    this library so as not to create a dependency on a file that may change.

    This, of course, will not behave properly if the function body is not
    simple and directly differentiable.
*/

makeIntegral[f] :=
{
   makeIntegralFunction[functionBody[f], functionArgumentsAsSymbols[f]@0]
}


/** Create an Integral function of the specified expression and symbol to
    take the derivative with respect to.  This will create a function of the
    form:
    Integrate[expr, symbol]

    Which can then be passed to transformExpression[]
    once you have loaded a file like integrals.frink

    REMINDER:  You may need to wrap expr or symbol in a noEval[] block if
    passing in a literal expression
*/

makeIntegralFunction[expr, symbol] :=
{
   if type[symbol] == "String"
      symbol = makeSymbol[symbol]

   return constructExpression["Function", ["Integrate", expr, symbol]]
}


/** Make a solve function with the specified left and right hand side and
    variable to solve for.

    In other words, this makes something that looks like:
    solve[left === right, x]

    Which can then be passed to transformExpression[]
    once you have loaded a file like solvingTransformations.frink

    REMINDER:  You may need to wrap each argument into a noEval[] block if
    passing in a literal expression
*/

makeSolve[left, right, variable] :=
{
   // Create the === part
   solve = constructExpression["Solve", [left, right]]
   return constructExpression["Function",
                              ["solve", solve, makeSymbol[variable]]]
}


/*
    Make a solve function with the specified equation (in either the form
    left = right  or the (better) left === right, and the variable to solve
    for.

    In other words, this makes something that looks like:
    solve[left === right, x]

    Which can then be passed to transformExpression[]
    once you have loaded a file like solvingTransformations.frink

    REMINDER:  You may need to wrap each argument into a noEval[] block if
    passing in a literal expression
*/

makeSolve[equation, variable] :=
{
   // Turn any assignments "=" into solve "==="
   if type[equation] == "Assignment"
      equation = substituteExpression[equation,
                                      noEval[_a  =  _b], // Note use of pattern
                                      noEval[_a === _b]]

   return constructExpression["Function",
                              ["solve", equation, makeSymbol[variable]]]
}


View or download functionUtils.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 17649 days, 5 hours, 36 minutes ago.