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