http://mathling.com/core/functions library module
http://mathling.com/core/functions
Functions that we need to perform analytical operations on, e.g.
arithmetic ops, derivative(), etc.
A unifying API for things like polynomials, complex polynomials, polynomial
quotients, etc.
Provides for polymorphism over a certain class of functions in the same way
that geo/euclidean provides polymorphism over a class of geometric objects.
Kinds of functions supported:
constants (core/complex)
real polynomials over x, sin(x), and cos(x) (types/polynomial)
complex polynomials over x, sin(x), and cos(x) (types/cpolynomial)
adhoc functions with certain operators determined by function keys (limited)
Note: limitations on some quotient operators right now
Copyright© Mary Holstege 2022-2025
CC-BY (https://creativecommons.org/licenses/by/4.0/)
Status: Bleeding edge
Function Index
add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-minus($f1 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-pow($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)adhoc-times($f1 as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)antiderivative($f as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)antiderivative-times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)definite-integral($f as map(xs:string,item()*), $a as xs:double, $b as xs:double) as xs:doublederivative($f as map(xs:string,item()*)) as map(xs:string,item()*)derivative-add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)derivative-multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-pow($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)derivative-times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)describe($f as map(xs:string,item()*)) as xs:stringdivide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)function($f as map(xs:string,item()*)) as function(xs:double) as xs:doublelog($f1 as map(xs:string,item()*)) as map(xs:string,item()*)minus($f as map(xs:string,item()*)) as map(xs:string,item()*)multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)order($f as map(xs:string,item()*)) as xs:integerpow($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)value($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*)zfunction($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*)zfunctionv($f as map(xs:string,item()*)) as function(xs:double*) as xs:double*zvalue($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*)zvaluev($f as map(xs:string,item()*), $z as xs:double*) as xs:double*
Imports
http://mathling.com/type/polynomial/quotientimport module namespace quotient="http://mathling.com/type/polynomial/quotient"
at "../types/quotient.xqy"http://mathling.com/core/utilitiesimport module namespace util="http://mathling.com/core/utilities"
at "../core/utilities.xqy"http://mathling.com/type/polynomialimport module namespace poly="http://mathling.com/type/polynomial"
at "../types/polynomial.xqy"http://mathling.com/core/compleximport module namespace z="http://mathling.com/core/complex"
at "../core/complex.xqy"http://mathling.com/core/complex/vectorimport module namespace zv="http://mathling.com/core/complex/vector"
at "../core/vcomplex.xqy"http://mathling.com/type/adhoc-functionimport module namespace adhoc="http://mathling.com/type/adhoc-function"
at "../types/adhoc-function.xqy"http://mathling.com/core/configimport module namespace config="http://mathling.com/core/config"
at "../core/config.xqy"http://mathling.com/type/polynomial/compleximport module namespace zpoly="http://mathling.com/type/polynomial/complex"
at "../types/cpolynomial.xqy"http://mathling.com/core/errorsimport module namespace errors="http://mathling.com/core/errors"
at "../core/errors.xqy"
Functions
Function: value
declare function value($f as map(xs:string,item()*),
$x as xs:double) as map(xs:string,item()*)
declare function value($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*)
value()
The value of f(x) for a real-valued x. Returns a complex value:
use z:as-real() if you need to.
Params
- f as map(xs:string,item()*): an object representing a certain kind of function
- x as xs:double: double value
Returns
- map(xs:string,item()*): : complex value f(x)
declare function this:value(
$f as map(xs:string,item()*),
$x as xs:double
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f
else if ($kind="polynomial") then poly:value($f, $x)=>z:as-complex()
else if ($kind="complex-polynomial") then zpoly:value($f, $x)
else if ($kind="polynomial-quotient") then (
this:value(quotient:u($f), $x)=>z:divide( this:value(quotient:v($f), $x) )
) else if ($f("value") instance of function(*)) then (
$f("value")($f, $x)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: zvalue
declare function zvalue($f as map(xs:string,item()*),
$z as map(xs:string,item()*)) as map(xs:string,item()*)
declare function zvalue($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*)
zvalue()
The value of f(z) for a complex value z
Params
- f as map(xs:string,item()*): an object representing a certain kind of function
- z as map(xs:string,item()*): complex value
Returns
- map(xs:string,item()*): : a complex value f(z)
declare function this:zvalue(
$f as map(xs:string,item()*),
$z as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f
else if ($kind="polynomial") then poly:zvalue($f, $z)
else if ($kind="complex-polynomial") then zpoly:zvalue($f, $z)
else if ($kind="polynomial-quotient") then (
this:zvalue(quotient:u($f), $z)=>z:divide( this:zvalue(quotient:v($f), $z) )
) else if ($f("zvalue") instance of function(*)) then (
$f("zvalue")($f, $z)
) else if ($f("zvaluev") instance of function(*)) then (
$f("zvaluev")($f, z:as-vector($z))=>z:vector()
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: zvaluev
declare function zvaluev($f as map(xs:string,item()*),
$z as xs:double*) as xs:double*
declare function zvaluev($f as map(xs:string,item()*), $z as xs:double*) as xs:double*
zvaluev()
The value of f(z) for a complex value z vector
Params
- f as map(xs:string,item()*): an object representing a certain kind of function
- z as xs:double*: complex value vector
Returns
- xs:double*: : a complex value f(z) vector
declare function this:zvaluev(
$f as map(xs:string,item()*),
$z as xs:double*
) as xs:double*
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f=>z:as-vector()
else if ($kind="polynomial") then poly:zvaluev($f, $z)
else if ($kind="complex-polynomial") then zpoly:zvaluev($f, $z)
else if ($kind="polynomial-quotient") then (
this:zvaluev(quotient:u($f), $z)=>zv:divide( this:zvaluev(quotient:v($f), $z) )
) else if ($f("zvaluev") instance of function(*)) then (
$f("zvaluev")($f, $z)
) else if ($f("zvalue") instance of function(*)) then (
$f("zvalue")($f, z:vector($z))=>z:as-vector()
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: derivative
declare function derivative($f as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative($f as map(xs:string,item()*)) as map(xs:string,item()*)
derivative()
Compute the derivative of the function.
Params
- f as map(xs:string,item()*): an object representing a certain kind of function
Returns
- map(xs:string,item()*): : an object representing the function that is the derivative of f
declare function this:derivative(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then (
z:as-complex(0)
) else if ($kind="polynomial") then (
poly:derivative($f)
) else if ($kind="complex-polynomial") then (
zpoly:derivative($f)
) else if ($kind="polynomial-quotient") then (
(: d(u/v) = (v du - u dv) / v² :)
let $u := quotient:u($f)
let $v := quotient:v($f)
let $du := this:derivative($u)
let $dv := this:derivative($v)
return (
quotient:quotient(
(this:multiply($v, $du)=>this:sub( this:multiply($u, $dv) )),
this:multiply($v, $v)
)
)
) else if ($f("derivative") instance of function(*)) then (
$f("derivative")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: antiderivative
declare function antiderivative($f as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative($f as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative()
Compute the anti-derivative of the function.
Params
- f as map(xs:string,item()*): an object representing a certain kind of function
Returns
- map(xs:string,item()*): : an object representing the function that is the anti-derivative of f
declare function this:antiderivative(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then (
if (z:eq($f, 0)) then $f else zpoly:polynomial( ($f, z:as-complex(0)) )
) else if ($kind="polynomial") then (
poly:antiderivative($f)
) else if ($kind="complex-polynomial") then (
zpoly:antiderivative($f)
) else if ($kind="polynomial-quotient") then (
(: Not easy:
: ∫u'/v = u/v + ∫(uv'/v²) so
: ∫u/v = (∫u)/v + ∫((∫u)v'/v²)
: Which in theory we could keep going on until the right hand bit gets
: down to a v' that is 0, but skip this for now
:)
errors:error("UTIL-NOTIMPLEMENTED", ("anti-derivative", $f))
) else if ($f("antiderivative") instance of function(*)) then (
$f("antiderivative")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: definite-integral
declare function definite-integral($f as map(xs:string,item()*),
$a as xs:double,
$b as xs:double) as xs:double
declare function definite-integral($f as map(xs:string,item()*), $a as xs:double, $b as xs:double) as xs:double
definite-integral()
Definite integral of a function (exact)
Note: if the result includes an imaginary part, this will raise
an error.
Params
- f as map(xs:string,item()*): the function
- a as xs:double: start of range of integration
- b as xs:double: end of range of integration
Returns
- xs:double
declare function this:definite-integral(
$f as map(xs:string,item()*),
$a as xs:double,
$b as xs:double
) as xs:double
{
let $anti := this:antiderivative($f)
return ($anti=>this:value($b)=>z:sub( $anti=>this:value($a) ) )=>z:as-real()
}
Function: describe
declare function describe($f as map(xs:string,item()*)) as xs:string
declare function describe($f as map(xs:string,item()*)) as xs:string
describe()
Describe the function
Params
- f as map(xs:string,item()*): the function
Returns
- xs:string
declare function this:describe(
$f as map(xs:string,item()*)
) as xs:string
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:quote($f)
else if ($kind="polynomial") then poly:describe($f)
else if ($kind="complex-polynomial") then zpoly:describe($f)
else if ($kind="polynomial-quotient") then (
"("||this:describe(quotient:u($f))||")/("||this:describe(quotient:v($f))||")"
) else if ($f("describe") instance of function(*)) then (
$f("describe")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: function
declare function function($f as map(xs:string,item()*)) as function(xs:double) as xs:double
declare function function($f as map(xs:string,item()*)) as function(xs:double) as xs:double
function()
Return a function that takes values of the function, e.g. for curve plotting
Params
- f as map(xs:string,item()*): the function
Returns
- function(xs:double)asxs:double
declare function this:function(
$f as map(xs:string,item()*)
) as function(xs:double) as xs:double
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as xs:double) as xs:double {
z:as-real($f)
}
else if ($kind="polynomial") then poly:function($f)
else if ($kind="complex-polynomial") then zpoly:function($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:function(quotient:u($f))
let $vf := this:function(quotient:v($f))
return (
function($v as xs:double) as xs:double {
$uf($v) div $vf($v)
}
)
) else if ($f("function") instance of function(*)) then (
$f("function")($f)
) else if ($f("value") instance of function(*)) then (
function ($v as xs:double) as xs:double {
$f("value")($f, $v)
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: zfunction
declare function zfunction($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*)
declare function zfunction($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*)
zfunction()
Return a function over complex values that takes values of the function, e.g. for
curve plotting
Params
- f as map(xs:string,item()*): the function
Returns
- function(map(xs:string,item()*))asmap(xs:string,item()*)
declare function this:zfunction(
$f as map(xs:string,item()*)
) as function(map(xs:string,item()*)) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f
}
else if ($kind="polynomial") then poly:zfunction($f)
else if ($kind="complex-polynomial") then zpoly:zfunction($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:zfunction(quotient:u($f))
let $vf := this:zfunction(quotient:v($f))
return (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$uf($v)=>z:divide( $vf($v) )
}
)
) else if ($f("zfunction") instance of function(*)) then (
$f("zfunction")($f)
) else if ($f("zvalue") instance of function(*)) then (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f("zvalue")($f, $v)
}
) else if ($f("zvaluev") instance of function(*)) then (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f("zvaluev")($f, z:as-vector($v))=>z:vector()
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: zfunctionv
declare function zfunctionv($f as map(xs:string,item()*)) as function(xs:double*) as xs:double*
declare function zfunctionv($f as map(xs:string,item()*)) as function(xs:double*) as xs:double*
zfunctionv()
Return a function over complex values (vector form) that takes values of the function,
e.g. for curve plotting
Params
- f as map(xs:string,item()*): the function
Returns
- function(xs:double*)asxs:double*
declare function this:zfunctionv(
$f as map(xs:string,item()*)
) as function(xs:double*) as xs:double*
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as xs:double*) as xs:double* {
z:as-vector($f)
}
else if ($kind="polynomial") then poly:zfunctionv($f)
else if ($kind="complex-polynomial") then zpoly:zfunctionv($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:zfunctionv(quotient:u($f))
let $vf := this:zfunctionv(quotient:v($f))
return (
function($v as xs:double*) as xs:double* {
$uf($v)=>zv:divide( $vf($v) )
}
)
) else if ($f("zfunctionv") instance of function(*)) then (
$f("zfunctionv")($f)
) else if ($f("zfunction") instance of function(*)) then (
let $zf := $f("zfunction")($f)
return (
function ($v as xs:double*) as xs:double* {
$zf(z:vector($v))=>z:as-vector()
}
)
) else if ($f("zvaluev") instance of function(*)) then (
function($v as xs:double*) as xs:double* {
$f("zvaluev")($f, $v)
}
) else if ($f("zvalue") instance of function(*)) then (
function($v as xs:double*) as xs:double* {
$f("zvalue")($f, z:vector($v))=>z:as-vector()
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: add
declare function add($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
add()
Add two functions
Params
- f1 as map(xs:string,item()*): one function
- f2 as map(xs:string,item()*): another function
Returns
- map(xs:string,item()*): object representing f1+f2
declare function this:add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:add($f2) else this:add($f2, $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
zpoly:as-polynomial($f1)=>zpoly:add( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:add($f2)
else this:adhoc-add($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:add( $f2 )
else this:adhoc-add($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add($f2, $f1)
) else (
this:adhoc-add($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
$f1=>zpoly:add( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:add( zpoly:as-polynomial($f2) )
else this:adhoc-add($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:add($f2)
else this:adhoc-add($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add($f2, $f1)
) else (
this:adhoc-add($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c + a = (b + ac) / c :)
quotient:quotient(
this:add( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
quotient:quotient(
this:add( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b + c/d = (ad + cb) / (bd) :)
return (
quotient:quotient(
this:add( this:multiply($u1, $v2), this:multiply($u2, $v1) ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-add($f1, $f2)
)
) else (
this:adhoc-add($f1, $f2)
)
)
}
Function: sub
declare function sub($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
sub()
Subtract two functions
Params
- f1 as map(xs:string,item()*): one function
- f2 as map(xs:string,item()*): another function
Returns
- map(xs:string,item()*): object representing f1-f2
declare function this:sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:sub($f2) else this:add(this:minus($f2), $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
zpoly:as-polynomial($f1)=>zpoly:sub( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:sub($f2)
else this:adhoc-sub($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:sub( $f2 )
else this:adhoc-sub($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add(this:minus($f2), $f1)
) else (
this:adhoc-sub($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
$f1=>zpoly:sub( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:sub( zpoly:as-polynomial($f2) )
else this:adhoc-sub($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:sub($f2)
else this:adhoc-sub($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add(this:minus($f2), $f1)
) else (
this:adhoc-sub($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c - a = (b - ac) / c :)
quotient:quotient(
this:sub( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
(: b/c - a = (b + ac) / c :)
quotient:quotient(
this:sub( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b - c/d = (ad - cb) / (bd) :)
return (
quotient:quotient(
this:sub( this:multiply($u1, $v2), this:multiply($u2, $v1) ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-sub($f1, $f2)
)
) else (
this:adhoc-sub($f1, $f2)
)
)
}
Function: multiply
declare function multiply($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
multiply()
Multiply two functions
Params
- f1 as map(xs:string,item()*): one function
- f2 as map(xs:string,item()*): another function
Returns
- map(xs:string,item()*): object representing f1 * f2
declare function this:multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:multiply($f2) else this:multiply($f2, $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(z:as-real($f2))
else zpoly:as-polynomial($f1)=>zpoly:multiply( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:multiply($f2)
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (poly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:multiply( $f2 )
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:multiply($f2, $f1)
) else (
this:adhoc-multiply($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(z:as-real($f2))
else $f1=>zpoly:multiply( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:multiply( zpoly:as-polynomial($f2) )
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:multiply($f2)
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:multiply($f2, $f1)
) else (
this:adhoc-multiply($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c * a = ba / c :)
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b * c/d = (ac) / (bd) :)
return (
quotient:quotient(
this:multiply( $u1, $u1 ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-multiply($f1, $f2)
)
) else (
this:adhoc-multiply($f1, $f2)
)
)
}
Function: divide
declare function divide($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
divide()
Divide two functions
Params
- f1 as map(xs:string,item()*): one function
- f2 as map(xs:string,item()*): another function
Returns
- map(xs:string,item()*): object representing f1/f2
declare function this:divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex")
then $f1=>z:divide($f2)
else this:multiply(z:reciprocal($f2), $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(1 div z:as-real($f2))
else zpoly:as-polynomial($f1)=>zpoly:ztimes( z:reciprocal($f2) )
) else if ($kind2="polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="complex-polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
(: a / (b/c) = ac / b :)
quotient:quotient(
this:multiply($f1, quotient:v($f2)),
quotient:u($f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(1 div z:as-real($f2))
else $f1=>zpoly:ztimes( z:reciprocal($f2) )
) else if ($kind2="polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="complex-polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
(: a / (b/c) = ac / b :)
quotient:quotient(
this:multiply($f1, quotient:v($f2)),
quotient:u($f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), z:reciprocal($f2)),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: (b/c) / a = b / ca :)
quotient:quotient(
quotient:u($f1),
this:multiply(quotient:v($f1), $f2)
)
) else if ($kind2="complex-polynomial") then (
(: (b/c) / a = b / ca :)
quotient:quotient(
quotient:u($f1),
this:multiply(quotient:v($f1), $f2)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b / c/d = a/b * d/c = ad/bc :)
return (
quotient:quotient(
this:multiply( $u1, $v2),
this:multiply( $v1, $u2 )
)
)
) else (
this:adhoc-divide($f1, $f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
}
Function: pow
declare function pow($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function pow($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
pow()
Raise one function to another
Params
- f1 as map(xs:string,item()*): one function
- f2 as map(xs:string,item()*): another function
Returns
- map(xs:string,item()*): object representing f1^f2
declare function this:pow(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
this:adhoc-pow($f1, $f2)
}
Function: log
declare function log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)
log()
Log of a function
Params
- f1 as map(xs:string,item()*): one function
Returns
- map(xs:string,item()*): object representing log(f1)
declare function this:log(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
this:adhoc-log($f1)
}
Function: times
declare function times($f as map(xs:string,item()*),
$k as xs:double) as map(xs:string,item()*)
declare function times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)
times()
Multiply function by constant
Params
- f as map(xs:string,item()*): the function
- k as xs:double: constant
Returns
- map(xs:string,item()*): object representing k*f
declare function this:times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:times($f, $k)
else if ($kind="polynomial") then poly:times($f, $k)
else if ($kind="complex-polynomial") then zpoly:times($f, $k)
else if ($kind="polynomial-quotient") then (
quotient:quotient(
this:times(quotient:u($f), $k),
quotient:v($f)
)
) else (
this:adhoc-times($f, $k)
)
)
}
Function: minus
declare function minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
declare function minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
minus()
Negate the function
Params
- f as map(xs:string,item()*): the function
Returns
- map(xs:string,item()*): object representing -f
declare function this:minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:minus($f)
else if ($kind="polynomial") then poly:times($f, -1)
else if ($kind="complex-polynomial") then zpoly:times($f, -1)
else if ($kind="polynomial-quotient") then (
quotient:quotient(
this:minus(quotient:u($f)),
quotient:v($f)
)
) else (
this:adhoc-minus($f)
)
)
}
Function: order
declare function order($f as map(xs:string,item()*)) as xs:integer
declare function order($f as map(xs:string,item()*)) as xs:integer
order()
Order of the function. Raises an error for ad hoc functions with no
defined order.
Params
- f as map(xs:string,item()*): the function
Returns
- xs:integer: polynomial order of the function (if there is a defined order)
declare function this:order(
$f as map(xs:string,item()*)
) as xs:integer
{
let $kind := util:kind($f) return (
if ($kind="complex") then 0
else if ($kind="polynomial") then poly:order($f)
else if ($kind="complex-polynomial") then zpoly:order($f)
else if ($kind="polynomial-quotient") then (
abs(this:order(quotient:u($f)) - this:order(quotient:v($f)))
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
}
Function: derivative-add
declare function derivative-add($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-add()
Return a function object representing the derivative of the sum of two
functions, suitable for using with adhoc:set-derivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing d(f1+f2)
declare function this:derivative-add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f + g) = df + dg :)
this:adhoc-add(this:derivative($f1), this:derivative($f2))
}
Function: derivative-sub
declare function derivative-sub($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-sub()
Return a function object representing the derivative of the difference of two
functions, suitable for using with adhoc:set-derivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing d(f1-f2)
declare function this:derivative-sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f - g) = df - dg :)
this:adhoc-sub(this:derivative($f1), this:derivative($f2))
}
Function: derivative-multiply
declare function derivative-multiply($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-multiply()
Return a function object representing the derivative of the product of two
functions, suitable for using with adhoc:set-derivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing d(f1*f2)
declare function this:derivative-multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f * g) = f*dg + g*df :)
this:adhoc-add(
this:adhoc-multiply($f1, this:derivative($f2)),
this:adhoc-multiply($f2, this:derivative($f1))
)
}
Function: derivative-divide
declare function derivative-divide($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-divide()
Return a function object representing the derivative of the quotient of two
functions, suitable for using with adhoc:set-derivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing d(f1/f2)
declare function this:derivative-divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f / g) = (df*g + dg*f)/g*g :)
this:adhoc-sub(
this:adhoc-multiply(this:derivative($f1), $f2),
this:adhoc-multiply(this:derivative($f2), $f1)
)=>this:adhoc-divide(
this:adhoc-multiply($f2, $f2)
)
}
Function: derivative-pow
declare function derivative-pow($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-pow($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-pow()
Return a function object representing the derivative of the raising of
one function to the other, suitable for using with adhoc:set-derivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing d(f1^f2)
declare function this:derivative-pow(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f^g) = (f^g)(df (g/f) + dg ln(f) ) :)
this:adhoc-multiply(
this:adhoc-pow($f1, $f2),
this:adhoc-add(
this:adhoc-multiply(
this:derivative($f1),
this:adhoc-divide($f2, $f1)
),
this:adhoc-multiply(
this:derivative($f2),
this:adhoc-log($f1)
)
)
)
}
Function: derivative-log
declare function derivative-log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-log($f1 as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-log()
Return a function object representing the derivative of taking the
log of a function.
Params
- f1 as map(xs:string,item()*): function object for first function
Returns
- map(xs:string,item()*): object representing d(log(f1))
declare function this:derivative-log(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(log(f)) = d(f)/f :)
this:adhoc-divide( this:derivative($f1), $f1 )
}
Function: derivative-times
declare function derivative-times($f as map(xs:string,item()*),
$k as xs:double) as map(xs:string,item()*)
declare function derivative-times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)
derivative-times()
Return a function object representing the derivative of the scaling of
a function by a constant, suitable for using with adhoc:set-derivative().
Params
- f as map(xs:string,item()*): function object for function
- k as xs:double: constant
Returns
- map(xs:string,item()*): object representing d(k*f)
declare function this:derivative-times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
(: d(k*f) = k*df :)
this:adhoc-times(this:derivative($f), $k)
}
Function: derivative-minus
declare function derivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
declare function derivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
derivative-minus()
Return a function object representing the derivative of the negation of
a function, suitable for using with adhoc:set-derivative().
Params
- f as map(xs:string,item()*): function object for function
Returns
- map(xs:string,item()*): object representing d(-f)
declare function this:derivative-minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(-f) = -df :)
this:adhoc-minus(this:derivative($f))
}
Function: antiderivative-add
declare function antiderivative-add($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative-add($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative-add()
Return a function object representing the antiderivative of the sum of two
functions, suitable for using with adhoc:set-antiderivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing ∫(f1+f2)
declare function this:antiderivative-add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f + g) = ∫f + ∫g :)
this:adhoc-add(this:antiderivative($f1), this:antiderivative($f2))
}
Function: antiderivative-sub
declare function antiderivative-sub($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative-sub($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative-sub()
Return a function object representing the antiderivative of the difference
of two functions, suitable for using with adhoc:set-antiderivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing ∫(f1-f2)
declare function this:antiderivative-sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f - g) = ∫f - ∫g :)
this:adhoc-sub(this:antiderivative($f1), this:antiderivative($f2))
}
Function: antiderivative-multiply
declare function antiderivative-multiply($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative-multiply($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative-multiply()
Return a function object representing the antiderivative of the product of two
functions, suitable for using with adhoc:set-antiderivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing ∫(f1*f2)
declare function this:antiderivative-multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f * g) = f*∫g - ∫(df*∫g) :)
this:adhoc-sub(
this:adhoc-multiply($f1, this:antiderivative($f2)),
this:antiderivative(
this:adhoc-multiply(
this:derivative($f1),
this:antiderivative($f2)
)
)
)
}
Function: antiderivative-divide
declare function antiderivative-divide($f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative-divide($f1 as map(xs:string,item()*), $f2 as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative-divide()
Return a function object representing the antiderivative of the quotient
of two functions, suitable for using with adhoc:set-antiderivative().
Params
- f1 as map(xs:string,item()*): function object for first function
- f2 as map(xs:string,item()*): function object for second function
Returns
- map(xs:string,item()*): object representing ∫(f1/f2)
declare function this:antiderivative-divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f / g) = f / g + ∫[(f*dg) / (g*g)] :)
this:adhoc-add(
this:adhoc-divide($f1, $f2),
this:antiderivative(
this:adhoc-divide(
this:adhoc-multiply($f1, this:derivative($f2)),
this:adhoc-multiply($f2, $f2)
)
)
)
}
Function: antiderivative-times
declare function antiderivative-times($f as map(xs:string,item()*),
$k as xs:double) as map(xs:string,item()*)
declare function antiderivative-times($f as map(xs:string,item()*), $k as xs:double) as map(xs:string,item()*)
antiderivative-times()
Return a function object representing the antiderivative of the scaling of
a function by a constant, suitable for using with adhoc:set-antiderivative().
Params
- f as map(xs:string,item()*): function object
- k as xs:double: constant
Returns
- map(xs:string,item()*): object representing ∫(k*f)
declare function this:antiderivative-times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
(: ∫(k*f) = k*∫f :)
this:adhoc-times(this:antiderivative($f), $k)
}
Function: antiderivative-minus
declare function antiderivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
declare function antiderivative-minus($f as map(xs:string,item()*)) as map(xs:string,item()*)
antiderivative-minus()
Return a function object representing the antiderivative of the negation of
a function, suitable for using with adhoc:set-antiderivative().
Params
- f as map(xs:string,item()*): function object
Returns
- map(xs:string,item()*): object representing ∫(-f)
declare function this:antiderivative-minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(-f) = -∫f :)
this:adhoc-minus(this:antiderivative($f))
}
Original Source Code
xquery version "3.1";
(:~
: Functions that we need to perform analytical operations on, e.g.
: arithmetic ops, derivative(), etc.
: A unifying API for things like polynomials, complex polynomials, polynomial
: quotients, etc.
:
: Provides for polymorphism over a certain class of functions in the same way
: that geo/euclidean provides polymorphism over a class of geometric objects.
:
: Kinds of functions supported:
: constants (core/complex)
: real polynomials over x, sin(x), and cos(x) (types/polynomial)
: complex polynomials over x, sin(x), and cos(x) (types/cpolynomial)
: adhoc functions with certain operators determined by function keys (limited)
:
: Note: limitations on some quotient operators right now
:
: Copyright© Mary Holstege 2022-2025
: CC-BY (https://creativecommons.org/licenses/by/4.0/)
: @since April 2023
: @custom:Status Bleeding edge
:)
module namespace this="http://mathling.com/core/functions";
import module namespace config="http://mathling.com/core/config"
at "../core/config.xqy";
import module namespace errors="http://mathling.com/core/errors"
at "../core/errors.xqy";
import module namespace util="http://mathling.com/core/utilities"
at "../core/utilities.xqy";
import module namespace z="http://mathling.com/core/complex"
at "../core/complex.xqy";
import module namespace zv="http://mathling.com/core/complex/vector"
at "../core/vcomplex.xqy";
import module namespace poly="http://mathling.com/type/polynomial"
at "../types/polynomial.xqy";
import module namespace zpoly="http://mathling.com/type/polynomial/complex"
at "../types/cpolynomial.xqy";
import module namespace quotient="http://mathling.com/type/polynomial/quotient"
at "../types/quotient.xqy";
import module namespace adhoc="http://mathling.com/type/adhoc-function"
at "../types/adhoc-function.xqy";
declare namespace map="http://www.w3.org/2005/xpath-functions/map";
declare namespace math="http://www.w3.org/2005/xpath-functions/math";
(:~
: value()
: The value of f(x) for a real-valued x. Returns a complex value:
: use z:as-real() if you need to.
:
: @param $f: an object representing a certain kind of function
: @param $x: double value
: @return: complex value f(x)
:)
declare function this:value(
$f as map(xs:string,item()*),
$x as xs:double
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f
else if ($kind="polynomial") then poly:value($f, $x)=>z:as-complex()
else if ($kind="complex-polynomial") then zpoly:value($f, $x)
else if ($kind="polynomial-quotient") then (
this:value(quotient:u($f), $x)=>z:divide( this:value(quotient:v($f), $x) )
) else if ($f("value") instance of function(*)) then (
$f("value")($f, $x)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: zvalue()
: The value of f(z) for a complex value z
:
: @param $f: an object representing a certain kind of function
: @param $z: complex value
: @return: a complex value f(z)
:)
declare function this:zvalue(
$f as map(xs:string,item()*),
$z as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f
else if ($kind="polynomial") then poly:zvalue($f, $z)
else if ($kind="complex-polynomial") then zpoly:zvalue($f, $z)
else if ($kind="polynomial-quotient") then (
this:zvalue(quotient:u($f), $z)=>z:divide( this:zvalue(quotient:v($f), $z) )
) else if ($f("zvalue") instance of function(*)) then (
$f("zvalue")($f, $z)
) else if ($f("zvaluev") instance of function(*)) then (
$f("zvaluev")($f, z:as-vector($z))=>z:vector()
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: zvaluev()
: The value of f(z) for a complex value z vector
:
: @param $f: an object representing a certain kind of function
: @param $z: complex value vector
: @return: a complex value f(z) vector
:)
declare function this:zvaluev(
$f as map(xs:string,item()*),
$z as xs:double*
) as xs:double*
{
let $kind := util:kind($f) return (
if ($kind="complex") then $f=>z:as-vector()
else if ($kind="polynomial") then poly:zvaluev($f, $z)
else if ($kind="complex-polynomial") then zpoly:zvaluev($f, $z)
else if ($kind="polynomial-quotient") then (
this:zvaluev(quotient:u($f), $z)=>zv:divide( this:zvaluev(quotient:v($f), $z) )
) else if ($f("zvaluev") instance of function(*)) then (
$f("zvaluev")($f, $z)
) else if ($f("zvalue") instance of function(*)) then (
$f("zvalue")($f, z:vector($z))=>z:as-vector()
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: derivative()
: Compute the derivative of the function.
:
: @param $f: an object representing a certain kind of function
: @return: an object representing the function that is the derivative of f
:)
declare function this:derivative(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then (
z:as-complex(0)
) else if ($kind="polynomial") then (
poly:derivative($f)
) else if ($kind="complex-polynomial") then (
zpoly:derivative($f)
) else if ($kind="polynomial-quotient") then (
(: d(u/v) = (v du - u dv) / v² :)
let $u := quotient:u($f)
let $v := quotient:v($f)
let $du := this:derivative($u)
let $dv := this:derivative($v)
return (
quotient:quotient(
(this:multiply($v, $du)=>this:sub( this:multiply($u, $dv) )),
this:multiply($v, $v)
)
)
) else if ($f("derivative") instance of function(*)) then (
$f("derivative")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: antiderivative()
: Compute the anti-derivative of the function.
:
: @param $f: an object representing a certain kind of function
: @return: an object representing the function that is the anti-derivative of f
:)
declare function this:antiderivative(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then (
if (z:eq($f, 0)) then $f else zpoly:polynomial( ($f, z:as-complex(0)) )
) else if ($kind="polynomial") then (
poly:antiderivative($f)
) else if ($kind="complex-polynomial") then (
zpoly:antiderivative($f)
) else if ($kind="polynomial-quotient") then (
(: Not easy:
: ∫u'/v = u/v + ∫(uv'/v²) so
: ∫u/v = (∫u)/v + ∫((∫u)v'/v²)
: Which in theory we could keep going on until the right hand bit gets
: down to a v' that is 0, but skip this for now
:)
errors:error("UTIL-NOTIMPLEMENTED", ("anti-derivative", $f))
) else if ($f("antiderivative") instance of function(*)) then (
$f("antiderivative")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: definite-integral()
: Definite integral of a function (exact)
: Note: if the result includes an imaginary part, this will raise
: an error.
:
: @param $f: the function
: @param $a: start of range of integration
: @param $b: end of range of integration
:)
declare function this:definite-integral(
$f as map(xs:string,item()*),
$a as xs:double,
$b as xs:double
) as xs:double
{
let $anti := this:antiderivative($f)
return ($anti=>this:value($b)=>z:sub( $anti=>this:value($a) ) )=>z:as-real()
};
(:~
: describe()
: Describe the function
:
: @param $f: the function
:)
declare function this:describe(
$f as map(xs:string,item()*)
) as xs:string
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:quote($f)
else if ($kind="polynomial") then poly:describe($f)
else if ($kind="complex-polynomial") then zpoly:describe($f)
else if ($kind="polynomial-quotient") then (
"("||this:describe(quotient:u($f))||")/("||this:describe(quotient:v($f))||")"
) else if ($f("describe") instance of function(*)) then (
$f("describe")($f)
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: function()
: Return a function that takes values of the function, e.g. for curve plotting
:
: @param $f: the function
:)
declare function this:function(
$f as map(xs:string,item()*)
) as function(xs:double) as xs:double
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as xs:double) as xs:double {
z:as-real($f)
}
else if ($kind="polynomial") then poly:function($f)
else if ($kind="complex-polynomial") then zpoly:function($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:function(quotient:u($f))
let $vf := this:function(quotient:v($f))
return (
function($v as xs:double) as xs:double {
$uf($v) div $vf($v)
}
)
) else if ($f("function") instance of function(*)) then (
$f("function")($f)
) else if ($f("value") instance of function(*)) then (
function ($v as xs:double) as xs:double {
$f("value")($f, $v)
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: zfunction()
: Return a function over complex values that takes values of the function, e.g. for curve plotting
:
: @param $f: the function
:)
declare function this:zfunction(
$f as map(xs:string,item()*)
) as function(map(xs:string,item()*)) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f
}
else if ($kind="polynomial") then poly:zfunction($f)
else if ($kind="complex-polynomial") then zpoly:zfunction($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:zfunction(quotient:u($f))
let $vf := this:zfunction(quotient:v($f))
return (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$uf($v)=>z:divide( $vf($v) )
}
)
) else if ($f("zfunction") instance of function(*)) then (
$f("zfunction")($f)
) else if ($f("zvalue") instance of function(*)) then (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f("zvalue")($f, $v)
}
) else if ($f("zvaluev") instance of function(*)) then (
function($v as map(xs:string,item()*)) as map(xs:string,item()*) {
$f("zvaluev")($f, z:as-vector($v))=>z:vector()
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:~
: zfunctionv()
: Return a function over complex values (vector form) that takes values of the function, e.g. for curve plotting
:
: @param $f: the function
:)
declare function this:zfunctionv(
$f as map(xs:string,item()*)
) as function(xs:double*) as xs:double*
{
let $kind := util:kind($f) return (
if ($kind="complex") then
function($v as xs:double*) as xs:double* {
z:as-vector($f)
}
else if ($kind="polynomial") then poly:zfunctionv($f)
else if ($kind="complex-polynomial") then zpoly:zfunctionv($f)
else if ($kind="polynomial-quotient") then (
let $uf := this:zfunctionv(quotient:u($f))
let $vf := this:zfunctionv(quotient:v($f))
return (
function($v as xs:double*) as xs:double* {
$uf($v)=>zv:divide( $vf($v) )
}
)
) else if ($f("zfunctionv") instance of function(*)) then (
$f("zfunctionv")($f)
) else if ($f("zfunction") instance of function(*)) then (
let $zf := $f("zfunction")($f)
return (
function ($v as xs:double*) as xs:double* {
$zf(z:vector($v))=>z:as-vector()
}
)
) else if ($f("zvaluev") instance of function(*)) then (
function($v as xs:double*) as xs:double* {
$f("zvaluev")($f, $v)
}
) else if ($f("zvalue") instance of function(*)) then (
function($v as xs:double*) as xs:double* {
$f("zvalue")($f, z:vector($v))=>z:as-vector()
}
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
(:======================================================================
: Operations
:======================================================================:)
(:~
: add()
: Add two functions
:
: @param $f1: one function
: @param $f2: another function
: @return object representing f1+f2
:)
declare function this:add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:add($f2) else this:add($f2, $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
zpoly:as-polynomial($f1)=>zpoly:add( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:add($f2)
else this:adhoc-add($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:add( $f2 )
else this:adhoc-add($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add($f2, $f1)
) else (
this:adhoc-add($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
$f1=>zpoly:add( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:add( zpoly:as-polynomial($f2) )
else this:adhoc-add($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:add($f2)
else this:adhoc-add($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add($f2, $f1)
) else (
this:adhoc-add($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c + a = (b + ac) / c :)
quotient:quotient(
this:add( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
quotient:quotient(
this:add( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b + c/d = (ad + cb) / (bd) :)
return (
quotient:quotient(
this:add( this:multiply($u1, $v2), this:multiply($u2, $v1) ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-add($f1, $f2)
)
) else (
this:adhoc-add($f1, $f2)
)
)
};
(:~
: sub()
: Subtract two functions
:
: @param $f1: one function
: @param $f2: another function
: @return object representing f1-f2
:)
declare function this:sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:sub($f2) else this:add(this:minus($f2), $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
zpoly:as-polynomial($f1)=>zpoly:sub( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:sub($f2)
else this:adhoc-sub($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:sub( $f2 )
else this:adhoc-sub($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add(this:minus($f2), $f1)
) else (
this:adhoc-sub($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
$f1=>zpoly:sub( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:sub( zpoly:as-polynomial($f2) )
else this:adhoc-sub($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:sub($f2)
else this:adhoc-sub($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:add(this:minus($f2), $f1)
) else (
this:adhoc-sub($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c - a = (b - ac) / c :)
quotient:quotient(
this:sub( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
(: b/c - a = (b + ac) / c :)
quotient:quotient(
this:sub( quotient:u($f1), this:multiply($f2, quotient:v($f1)) ),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b - c/d = (ad - cb) / (bd) :)
return (
quotient:quotient(
this:sub( this:multiply($u1, $v2), this:multiply($u2, $v1) ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-sub($f1, $f2)
)
) else (
this:adhoc-sub($f1, $f2)
)
)
};
(:~
: multiply()
: Multiply two functions
:
: @param $f1: one function
: @param $f2: another function
: @return object representing f1 * f2
:)
declare function this:multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex") then $f1=>z:multiply($f2) else this:multiply($f2, $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(z:as-real($f2))
else zpoly:as-polynomial($f1)=>zpoly:multiply( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (poly:op($f1)=poly:op($f2))
then $f1=>poly:multiply($f2)
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (poly:op($f1)=zpoly:op($f2))
then zpoly:as-polynomial($f1)=>zpoly:multiply( $f2 )
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:multiply($f2, $f1)
) else (
this:adhoc-multiply($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(z:as-real($f2))
else $f1=>zpoly:multiply( zpoly:polynomial(($f2)) )
) else if ($kind2="polynomial") then (
if (zpoly:op($f1)=poly:op($f2))
then $f1=>zpoly:multiply( zpoly:as-polynomial($f2) )
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="complex-polynomial") then (
if (zpoly:op($f1)=zpoly:op($f2))
then $f1=>zpoly:multiply($f2)
else this:adhoc-multiply($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
this:multiply($f2, $f1)
) else (
this:adhoc-multiply($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: b/c * a = ba / c :)
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="complex-polynomial") then (
quotient:quotient(
this:multiply(quotient:u($f1), $f2),
quotient:v($f1)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b * c/d = (ac) / (bd) :)
return (
quotient:quotient(
this:multiply( $u1, $u1 ),
this:multiply( $v1, $v2 )
)
)
) else (
this:adhoc-multiply($f1, $f2)
)
) else (
this:adhoc-multiply($f1, $f2)
)
)
};
(:~
: divide()
: Divide two functions
:
: @param $f1: one function
: @param $f2: another function
: @return object representing f1/f2
:)
declare function this:divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind1 := util:kind($f1)
let $kind2 := util:kind($f2)
return (
if ($kind1="complex") then (
if ($kind2="complex")
then $f1=>z:divide($f2)
else this:multiply(z:reciprocal($f2), $f1)
)
else if ($kind1="polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(1 div z:as-real($f2))
else zpoly:as-polynomial($f1)=>zpoly:ztimes( z:reciprocal($f2) )
) else if ($kind2="polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="complex-polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
(: a / (b/c) = ac / b :)
quotient:quotient(
this:multiply($f1, quotient:v($f2)),
quotient:u($f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
else if ($kind1="complex-polynomial") then (
if ($kind2="complex") then (
if (z:is-real($f2))
then $f1=>this:times(1 div z:as-real($f2))
else $f1=>zpoly:ztimes( z:reciprocal($f2) )
) else if ($kind2="polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="complex-polynomial") then (
quotient:quotient($f1, $f2)
) else if ($kind2="polynomial-quotient") then (
(: a / (b/c) = ac / b :)
quotient:quotient(
this:multiply($f1, quotient:v($f2)),
quotient:u($f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
else if ($kind1="polynomial-quotient") then (
if ($kind2="complex") then (
quotient:quotient(
this:multiply(quotient:u($f1), z:reciprocal($f2)),
quotient:v($f1)
)
) else if ($kind2="polynomial") then (
(: (b/c) / a = b / ca :)
quotient:quotient(
quotient:u($f1),
this:multiply(quotient:v($f1), $f2)
)
) else if ($kind2="complex-polynomial") then (
(: (b/c) / a = b / ca :)
quotient:quotient(
quotient:u($f1),
this:multiply(quotient:v($f1), $f2)
)
) else if ($kind2="polynomial-quotient") then (
let $u1 := quotient:u($f1)
let $v1 := quotient:v($f1)
let $u2 := quotient:u($f2)
let $v2 := quotient:v($f2)
(: a/b / c/d = a/b * d/c = ad/bc :)
return (
quotient:quotient(
this:multiply( $u1, $v2),
this:multiply( $v1, $u2 )
)
)
) else (
this:adhoc-divide($f1, $f2)
)
) else (
this:adhoc-divide($f1, $f2)
)
)
};
(:~
: pow()
: Raise one function to another
:
: @param $f1: one function
: @param $f2: another function
: @return object representing f1^f2
:)
declare function this:pow(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
this:adhoc-pow($f1, $f2)
};
(:~
: log()
: Log of a function
:
: @param $f1: one function
: @return object representing log(f1)
:)
declare function this:log(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
this:adhoc-log($f1)
};
(:~
: times()
: Multiply function by constant
:
: @param $f: the function
: @param $k: constant
: @return object representing k*f
:)
declare function this:times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:times($f, $k)
else if ($kind="polynomial") then poly:times($f, $k)
else if ($kind="complex-polynomial") then zpoly:times($f, $k)
else if ($kind="polynomial-quotient") then (
quotient:quotient(
this:times(quotient:u($f), $k),
quotient:v($f)
)
) else (
this:adhoc-times($f, $k)
)
)
};
(:~
: minus()
: Negate the function
:
: @param $f: the function
: @return object representing -f
:)
declare function this:minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
let $kind := util:kind($f) return (
if ($kind="complex") then z:minus($f)
else if ($kind="polynomial") then poly:times($f, -1)
else if ($kind="complex-polynomial") then zpoly:times($f, -1)
else if ($kind="polynomial-quotient") then (
quotient:quotient(
this:minus(quotient:u($f)),
quotient:v($f)
)
) else (
this:adhoc-minus($f)
)
)
};
(:~
: order()
: Order of the function. Raises an error for ad hoc functions with no
: defined order.
:
: @param $f: the function
: @return polynomial order of the function (if there is a defined order)
:)
declare function this:order(
$f as map(xs:string,item()*)
) as xs:integer
{
let $kind := util:kind($f) return (
if ($kind="complex") then 0
else if ($kind="polynomial") then poly:order($f)
else if ($kind="complex-polynomial") then zpoly:order($f)
else if ($kind="polynomial-quotient") then (
abs(this:order(quotient:u($f)) - this:order(quotient:v($f)))
) else (
errors:error("UTIL-BADARGS", ("f", $f))
)
)
};
declare %private function this:adhoc-add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"("||this:describe($f1)||")+("||this:describe($f2)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
($f1=>this:value($x))=>z:add( $f2=>this:value($x) )
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
$f1=>this:zvalue($z)=>z:add( $f2=>this:zvalue($z) )
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
$f1=>this:zvaluev($z)=>zv:add( $f2=>this:zvaluev($z) )
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
this:function($f1)($x) + this:function($f2)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:add( this:zfunction($f2)($z) )
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-add($f1, $f2)
}
) else ()
)=>
adhoc:set-antiderivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("antiderivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("antiderivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:antiderivative-add($f1, $f2)
}
) else ()
)
};
declare %private function this:adhoc-sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"("||this:describe($f1)||")-("||this:describe($f2)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
($f1=>this:value($x))=>z:sub( $f2=>this:value($x) )
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
$f1=>this:zvalue($z)=>z:sub( $f2=>this:zvalue($z) )
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
$f1=>this:zvaluev($z)=>zv:sub( $f2=>this:zvaluev($z) )
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
this:function($f1)($x) - this:function($f2)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:sub( this:zfunction($f2)($z) )
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-sub($f1, $f2)
}
) else ()
)=>
adhoc:set-antiderivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("antiderivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("antiderivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:antiderivative-sub($f1, $f2)
}
) else ()
)
};
declare %private function this:adhoc-multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"("||this:describe($f1)||")*("||this:describe($f2)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
($f1=>this:value($x))=>z:multiply( $f2=>this:value($x) )
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
($f1=>this:zvalue($z))=>z:multiply( $f2=>this:zvalue($z) )
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
($f1=>this:zvaluev($z))=>zv:multiply( $f2=>this:zvaluev($z) )
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
this:function($f1)($x) * this:function($f2)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:multiply( this:zfunction($f2)($z) )
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-multiply($f1, $f2)
}
) else ()
)
};
declare %private function this:adhoc-divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"("||this:describe($f1)||")/("||this:describe($f2)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
($f1=>this:value($x))=>z:divide( $f2=>this:value($x) )
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
($f1=>this:zvalue($z))=>z:divide( $f2=>this:zvalue($z) )
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
($f1=>this:zvaluev($z))=>zv:divide( $f2=>this:zvaluev($z) )
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
this:function($f1)($x) div this:function($f2)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:divide( this:zfunction($f2)($z) )
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-divide($f1, $f2)
}
) else ()
)
};
declare %private function this:adhoc-pow(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"("||this:describe($f1)||")^("||this:describe($f2)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
($f1=>this:value($x))=>z:ppow( $f2=>this:value($x) )
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
($f1=>this:zvalue($z))=>z:ppow( $f2=>this:zvalue($z) )
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
($f1=>this:zvaluev($z))=>zv:ppow( $f2=>this:zvaluev($z) )
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
math:pow(this:function($f1)($x), this:function($f2)($x))
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:ppow( this:zfunction($f2)($z) )
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative"))) and
(not(util:kind($f2)="adhoc-function") or exists($f2("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-pow($f1, $f2)
}
) else ()
)
};
declare %private function this:adhoc-times(
$f1 as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
$k||"("||this:describe($f1)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
$f1=>this:value($x)=>z:times($k)
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
$f1=>this:zvalue($z)=>z:times($k)
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
$f1=>this:zvaluev($z)=>zv:times($k)
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
$k * this:function($f1)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:times($k)
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-times($f1, $k)
}
) else ()
)=>
adhoc:set-antiderivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("antiderivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:antiderivative-times($f1, $k)
}
) else ()
)
};
declare %private function this:adhoc-minus(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"-("||this:describe($f1)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
$f1=>this:value($x)=>z:minus()
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
$f1=>this:zvalue($z)=>z:minus()
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
$f1=>this:zvaluev($z)=>zv:minus()
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
-this:function($f1)($x)
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
(this:zfunction($f1)($z))=>z:minus()
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-minus($f1)
}
) else ()
)=>
adhoc:set-antiderivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("antiderivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:antiderivative-minus($f1)
}
) else ()
)
};
declare %private function this:adhoc-log(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
adhoc:adhoc-function(
function ($f as map(xs:string,item()*)) as xs:string {
"log("||this:describe($f1)||")"
}
)=>
adhoc:set-value(
function($f as map(xs:string,item()*), $x as xs:double) as map(xs:string,item()*) {
z:log($f1=>this:value($x))
}
)=>
adhoc:set-zvalue(
function($f as map(xs:string,item()*), $z as map(xs:string,item()*)) as map(xs:string,item()*) {
z:log($f1=>this:zvalue($z))
}
)=>
adhoc:set-zvaluev(
function($f as map(xs:string,item()*), $z as xs:double*) as xs:double* {
zv:log($f1=>this:zvaluev($z))
}
)=>
adhoc:set-function(
function($f as map(xs:string,item()*)) as function(xs:double) as xs:double {
function($x as xs:double) as xs:double {
math:log(this:function($f1)($x))
}
}
)=>
adhoc:set-zfunction(
function($f as map(xs:string,item()*)) as function(map(xs:string,item()*)) as map(xs:string,item()*) {
function($z as map(xs:string,item()*)) as map(xs:string,item()*) {
z:log(this:zfunction($f1)($z))
}
}
)=>
adhoc:set-derivative(
if (
(not(util:kind($f1)="adhoc-function") or exists($f1("derivative")))
) then (
function($f as map(xs:string,item()*)) as map(xs:string,item()*) {
this:derivative-log($f1)
}
) else ()
)
};
(:~
: derivative-add()
: Return a function object representing the derivative of the sum of two
: functions, suitable for using with adhoc:set-derivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing d(f1+f2)
:)
declare function this:derivative-add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f + g) = df + dg :)
this:adhoc-add(this:derivative($f1), this:derivative($f2))
};
(:~
: derivative-sub()
: Return a function object representing the derivative of the difference of two
: functions, suitable for using with adhoc:set-derivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing d(f1-f2)
:)
declare function this:derivative-sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f - g) = df - dg :)
this:adhoc-sub(this:derivative($f1), this:derivative($f2))
};
(:~
: derivative-multiply()
: Return a function object representing the derivative of the product of two
: functions, suitable for using with adhoc:set-derivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing d(f1*f2)
:)
declare function this:derivative-multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f * g) = f*dg + g*df :)
this:adhoc-add(
this:adhoc-multiply($f1, this:derivative($f2)),
this:adhoc-multiply($f2, this:derivative($f1))
)
};
(:~
: derivative-divide()
: Return a function object representing the derivative of the quotient of two
: functions, suitable for using with adhoc:set-derivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing d(f1/f2)
:)
declare function this:derivative-divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f / g) = (df*g + dg*f)/g*g :)
this:adhoc-sub(
this:adhoc-multiply(this:derivative($f1), $f2),
this:adhoc-multiply(this:derivative($f2), $f1)
)=>this:adhoc-divide(
this:adhoc-multiply($f2, $f2)
)
};
(:~
: derivative-pow()
: Return a function object representing the derivative of the raising of
: one function to the other, suitable for using with adhoc:set-derivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing d(f1^f2)
:)
declare function this:derivative-pow(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(f^g) = (f^g)(df (g/f) + dg ln(f) ) :)
this:adhoc-multiply(
this:adhoc-pow($f1, $f2),
this:adhoc-add(
this:adhoc-multiply(
this:derivative($f1),
this:adhoc-divide($f2, $f1)
),
this:adhoc-multiply(
this:derivative($f2),
this:adhoc-log($f1)
)
)
)
};
(:~
: derivative-log()
: Return a function object representing the derivative of taking the
: log of a function.
:
: @param $f1: function object for first function
: @return object representing d(log(f1))
:)
declare function this:derivative-log(
$f1 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(log(f)) = d(f)/f :)
this:adhoc-divide( this:derivative($f1), $f1 )
};
(:~
: derivative-times()
: Return a function object representing the derivative of the scaling of
: a function by a constant, suitable for using with adhoc:set-derivative().
:
: @param $f: function object for function
: @param $k: constant
: @return object representing d(k*f)
:)
declare function this:derivative-times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
(: d(k*f) = k*df :)
this:adhoc-times(this:derivative($f), $k)
};
(:~
: derivative-minus()
: Return a function object representing the derivative of the negation of
: a function, suitable for using with adhoc:set-derivative().
:
: @param $f: function object for function
: @return object representing d(-f)
:)
declare function this:derivative-minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: d(-f) = -df :)
this:adhoc-minus(this:derivative($f))
};
(:~
: antiderivative-add()
: Return a function object representing the antiderivative of the sum of two
: functions, suitable for using with adhoc:set-antiderivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing ∫(f1+f2)
:)
declare function this:antiderivative-add(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f + g) = ∫f + ∫g :)
this:adhoc-add(this:antiderivative($f1), this:antiderivative($f2))
};
(:~
: antiderivative-sub()
: Return a function object representing the antiderivative of the difference
: of two functions, suitable for using with adhoc:set-antiderivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing ∫(f1-f2)
:)
declare function this:antiderivative-sub(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f - g) = ∫f - ∫g :)
this:adhoc-sub(this:antiderivative($f1), this:antiderivative($f2))
};
(:~
: antiderivative-multiply()
: Return a function object representing the antiderivative of the product of two
: functions, suitable for using with adhoc:set-antiderivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing ∫(f1*f2)
:)
declare function this:antiderivative-multiply(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f * g) = f*∫g - ∫(df*∫g) :)
this:adhoc-sub(
this:adhoc-multiply($f1, this:antiderivative($f2)),
this:antiderivative(
this:adhoc-multiply(
this:derivative($f1),
this:antiderivative($f2)
)
)
)
};
(:~
: antiderivative-divide()
: Return a function object representing the antiderivative of the quotient
: of two functions, suitable for using with adhoc:set-antiderivative().
:
: @param $f1: function object for first function
: @param $f2: function object for second function
: @return object representing ∫(f1/f2)
:)
declare function this:antiderivative-divide(
$f1 as map(xs:string,item()*),
$f2 as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(f / g) = f / g + ∫[(f*dg) / (g*g)] :)
this:adhoc-add(
this:adhoc-divide($f1, $f2),
this:antiderivative(
this:adhoc-divide(
this:adhoc-multiply($f1, this:derivative($f2)),
this:adhoc-multiply($f2, $f2)
)
)
)
};
(:~
: antiderivative-times()
: Return a function object representing the antiderivative of the scaling of
: a function by a constant, suitable for using with adhoc:set-antiderivative().
:
: @param $f: function object
: @param $k: constant
: @return object representing ∫(k*f)
:)
declare function this:antiderivative-times(
$f as map(xs:string,item()*),
$k as xs:double
) as map(xs:string,item()*)
{
(: ∫(k*f) = k*∫f :)
this:adhoc-times(this:antiderivative($f), $k)
};
(:~
: antiderivative-minus()
: Return a function object representing the antiderivative of the negation of
: a function, suitable for using with adhoc:set-antiderivative().
:
: @param $f: function object
: @return object representing ∫(-f)
:)
declare function this:antiderivative-minus(
$f as map(xs:string,item()*)
) as map(xs:string,item()*)
{
(: ∫(-f) = -∫f :)
this:adhoc-minus(this:antiderivative($f))
};