Download or view 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).
For functions defined in Java, there will be no child 1 and this will
return undef.
*/
functionBody[f] :=
{
func = undef
if type[f] == "FunctionDescriptor" // A function with a name. Child 0 is name
func = getChild[f,1] // Child 1 is Function
else
if type[f] == "Function"
func = f
// This returns the actual body of the function. For functions defined
// in Java, there will be no child 1.
if childCount[func] >= 2
return getChild[func,1]
else
return undef
}
/** This returns the name of a function as a string, if it has one, otherwise
returns undef.
The argument passed in can be a named function (a FunctionDescriptor) or
an anonymous function (Function)
*/
functionName[f] :=
{
if type[f] == "FunctionDescriptor" // A function with a name.
return getChild[f,0] // Child 0 is name
else
return undef
}
/** 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[makeSymbol[arg]]
return retval
}
/** This returns the number of function arguments as an integer. */
argumentCount[f] :=
{
func = undef
if type[f] == "FunctionDescriptor"
func = getChild[f,1] // Child 1 is Function
else
if type[f] == "Function"
func = f
return length[getChild[func, 0]] // This is an array of FunctionArguments
}
/** Create a symbol with the name of the given string. */
makeSymbol[s] :=
{
if type[s] == "Symbol"
return s
else
return constructExpression["Symbol", [s]]
}
/** Create an array of symbols from an array of arguments. */
makeSymbols[list] :=
{
retval = new array
for arg = list
retval.push[makeSymbol[arg]]
return retval
}
/** 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, times=1] :=
{
body = functionBody[f]
if body != undef
makeDerivativeFunction[body, functionArgumentsAsSymbols[f]@0, times]
else
{
// This function was defined in Java probably. It may not have argument
// names.
argSym = makeSymbol["arg1"]
funcCall = constructExpression["FunctionCall", [functionName[f], argSym]]
return constructExpression["FunctionCall", ["D", funcCall, argSym, times]]
}
}
/** 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, times=1] :=
{
symbol = makeSymbol[symbol]
return constructExpression["FunctionCall", ["D", expr, symbol, times]]
}
/** 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:
Integrate[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 integrable.
*/
makeIntegral[f] :=
{
body = functionBody[f]
if body != undef
makeIntegralFunction[body, functionArgumentsAsSymbols[f]@0]
else
{
// This function was defined in Java probably. It may not have argument
// names.
argSym = makeSymbol["arg1"]
funcCall = constructExpression["FunctionCall", [functionName[f], argSym]]
return constructExpression["FunctionCall", ["Integrate", funcCall, argSym]]
}
}
/** 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["FunctionCall", ["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["FunctionCall",
["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["FunctionCall",
["solve", equation, makeSymbol[variable]]]
}
/** Makes an anonymous function given a list of arguments
(which can be specified as either string names or Symbols.) and a body.
REMINDER: You may need to wrap each argument into a noEval[] block if
passing in a literal expression.
*/
makeAnonymousFunction[args, body] :=
{
args = makeSymbols[args]
return ConstructExpression["Function", [args, body]]
}
Download or view 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 20217 days, 15 hours, 13 minutes ago.