http://mathling.com/core/array library module
http://mathling.com/core/array
2D array of numbers: similar functionality to matrix.xqy, but with
sequences of doubles. Similar to the relationship between point and vector.
This supports more matrix operations, such as transposition and inverse.
This is a row major ordering: note that the get() function, like those
for point matrices of various kinds puts the row first e.g. get(y,x)
which is, I admit a bit confusing.
Copyright© Mary Holstege 2021-2025
CC-BY (https://creativecommons.org/licenses/by/4.0/)
Status: Stable
Function Index
add($a1 as map(*), $a2 as map(*)) as map(*)adjoint($array as map(*)) as map(*)array($rows as xs:integer, $columns as xs:integer, $data as xs:double*) as map(*)array($data as array(array(*))) as map(*)as-array($array as map(*)) as array(array(*))blur($source as map(*), $radius as xs:integer) as map(*)cofactor-matrix($array as map(*)) as map(*)column($array as map(*), $column as xs:integer) as xs:double*columns($array as map(*)) as xs:integerdata($array as map(*)) as xs:double*data($array as map(*), $data as xs:double*) as map(*)decimal($array as map(*), $digits as xs:integer) as map(*)determinant($array as map(*)) as xs:doublediagonal($array as map(*)) as xs:double*floor($array as map(*)) as map(*)get($array as map(*), $row as xs:integer, $column as xs:integer) as xs:doublehorizontal-blur($source as map(*), $radius as xs:integer) as map(*)inverse($array as map(*)) as map(*)is-diagonal($array as map(*)) as xs:booleanis-identity($array as map(*)) as xs:booleanis-lower-triangular($array as map(*)) as xs:booleanis-singular($array as map(*)) as xs:booleanis-tridiagonal($array as map(*)) as xs:booleanis-upper-triangular($array as map(*)) as xs:booleanis-zero($array as map(*)) as xs:booleanmap($array as map(*), $f as function(xs:double) as xs:double) as map(*)multiply($a1 as map(*), $a2 as map(*)) as map(*)outer($a1 as map(*), $a2 as map(*)) as map(*)quote($array as map(*)) as xs:stringrow($array as map(*), $row as xs:integer) as xs:double*rows($array as map(*)) as xs:integersame($this as map(*), $other as map(*)) as xs:booleansnap($array as map(*)) as map(*)subtract($a1 as map(*), $a2 as map(*)) as map(*)times($array as map(*), $k as xs:double) as map(*)trace($array as map(*)) as xs:doubletranspose($array as map(*)) as map(*)vector($data as xs:double*) as map(*)vertical-blur($source as map(*), $radius as xs:integer) as map(*)
Imports
http://mathling.com/core/utilitiesimport module namespace util="http://mathling.com/core/utilities"
at "../core/utilities.xqy"http://mathling.com/core/configimport module namespace config="http://mathling.com/core/config"
at "../core/config.xqy"http://mathling.com/core/errorsimport module namespace errors="http://mathling.com/core/errors"
at "../core/errors.xqy"
Variables
Variable: $RESERVED as
Functions
Function: array
declare function array($rows as xs:integer,
$columns as xs:integer,
$data as xs:double*) as map(*)
declare function array($rows as xs:integer, $columns as xs:integer, $data as xs:double*) as map(*)
array()
Construct a new matrix
Params
- rows as xs:integer number of rows in matrix
- columns as xs:integer number of columns in matrix
- data as xs:double* data values (must be $rows X $columns)
Returns
- map(*): matrix
declare function this:array(
$rows as xs:integer,
$columns as xs:integer,
$data as xs:double*
) as map(*)
{
if ($rows * $columns ne count($data))
then errors:error("UTIL-BADARRAY", ($rows, $columns, count($data)))
else (
map {
"kind": "array",
"rows": $rows,
"columns": $columns,
"data": $data
}
)
}
Errors
UTIL-BADARRAY if number of data values doesn't match size
Function: array
declare function array($data as array(array(*))) as map(*)
declare function array($data as array(array(*))) as map(*)
Convert an array of arrays (rows of columns) into a new matrix
Params
- data as array(array(*)) data array; each row must have same number of columns
Returns
- map(*): matrix
declare function this:array(
$data as array(array(*))
) as map(*)
{
this:array(array:size($data), array:size($data(1)), array:flatten($data))
}
Errors
UTIL-BADARRAY if number of data values doesn't match size
Function: vector
declare function vector($data as xs:double*) as map(*)
declare function vector($data as xs:double*) as map(*)
vector()
Convert a sequence of values into a vector array, where each value is
in its own row.
Params
- data as xs:double*: sequence of values
Returns
- map(*): matrix
declare function this:vector(
$data as xs:double*
) as map(*)
{
this:array(count($data), 1, $data)
}
Function: as-array
declare function as-array($array as map(*)) as array(array(*))
declare function as-array($array as map(*)) as array(array(*))
as-array()
Convert to an XQuery 2D array (array of arrays). Generally a performance
move. Creates a row-major array: each entry is a row.
Params
- array as map(*) the array
Returns
- array(array(*)): an array of arrays, row-major
declare function this:as-array(
$array as map(*)
) as array(array(*))
{
array { for $i in 1 to this:rows($array) return array { this:row($array, $i) } }
}
Function: rows
declare function rows($array as map(*)) as xs:integer
declare function rows($array as map(*)) as xs:integer
rows()
Accessor for the number of rows in the array
Params
- array as map(*) the array
Returns
- xs:integer: number of rows in array
declare function this:rows($array as map(*)) as xs:integer
{
$array("rows")
}
Function: columns
declare function columns($array as map(*)) as xs:integer
declare function columns($array as map(*)) as xs:integer
columns()
Accessor for the number of rows in the array
Params
- array as map(*) the array
Returns
- xs:integer: number of rows in array
declare function this:columns($array as map(*)) as xs:integer
{
$array("columns")
}
Function: data
declare function data($array as map(*)) as xs:double*
declare function data($array as map(*)) as xs:double*
data()
Accessor for the data in the array
Params
- array as map(*) the array
Returns
- xs:double*: sequence of values (row major order)
declare function this:data($array as map(*)) as xs:double*
{
$array("data")
}
Function: data
declare function data($array as map(*), $data as xs:double*) as map(*)
declare function data($array as map(*), $data as xs:double*) as map(*)
data()
Settor for the data in the array
Params
- array as map(*) the array
- data as xs:double* the new data
Returns
- map(*): new matrix
declare function this:data($array as map(*), $data as xs:double*) as map(*)
{
if (this:rows($array) * this:columns($array) ne count($data))
then errors:error("UTIL-BADARRAY", (this:rows($array), this:columns($array), count($data)))
else (
$array=>map:put("data", $data)
)
}
Errors
UTIL-BADARRAY if number of data values doesn't match size
Function: get
declare function get($array as map(*),
$row as xs:integer,
$column as xs:integer) as xs:double
declare function get($array as map(*), $row as xs:integer, $column as xs:integer) as xs:double
get()
Get a specific data value
Params
- array as map(*): the array
- row as xs:integer: the row number
- column as xs:integer: the column number
Returns
- xs:double: data value array[row, column]
declare function this:get(
$array as map(*),
$row as xs:integer,
$column as xs:integer
) as xs:double
{
this:data($array)[($row - 1)*$array("columns") + $column]
}
Function: row
declare function row($array as map(*),
$row as xs:integer) as xs:double*
declare function row($array as map(*), $row as xs:integer) as xs:double*
row()
Return all the values from the given row
Params
- array as map(*): the array
- row as xs:integer: the row number
Returns
- xs:double*: values in row in column order
declare function this:row(
$array as map(*),
$row as xs:integer
) as xs:double*
{
if ($row lt 1 or $row gt $array("rows")) then () else
let $data := $array("data")
let $num-columns := $array("columns")
let $ixs :=
for $col in 1 to $num-columns
return ($row - 1)*$num-columns + $col
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
}
Function: column
declare function column($array as map(*),
$column as xs:integer) as xs:double*
declare function column($array as map(*), $column as xs:integer) as xs:double*
column()
Return all the values from the given column
Params
- array as map(*): the array
- column as xs:integer: the column number
Returns
- xs:double*: values in column in row order
declare function this:column(
$array as map(*),
$column as xs:integer
) as xs:double*
{
if ($column lt 1 or $column gt $array("columns")) then () else
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
let $ixs :=
for $row in 1 to $num-rows
return ($row - 1)*$num-columns + $column
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
}
Function: diagonal
declare function diagonal($array as map(*)) as xs:double*
declare function diagonal($array as map(*)) as xs:double*
diagonal()
Return all the values from the diagonal
Raises an error if the array is not square
Params
- array as map(*): the array
Returns
- xs:double*: values along main diagonal
declare function this:diagonal($array as map(*)) as xs:double*
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
let $ixs := for $i in 1 to $num-rows return ($i - 1)*$num-columns + $i
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
)
)
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Function: is-zero
declare function is-zero($array as map(*)) as xs:boolean
declare function is-zero($array as map(*)) as xs:boolean
is-zero()
Is this a zero array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a zero array
declare function this:is-zero($array as map(*)) as xs:boolean
{
every $v in $array("data") satisfies $v = 0
}
Function: is-diagonal
declare function is-diagonal($array as map(*)) as xs:boolean
declare function is-diagonal($array as map(*)) as xs:boolean
is-diagonal()
Is this a diagonal array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a diagonal array
declare function this:is-diagonal($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
if ($r = $c)
then not($v = 0)
else $v = 0
)
)
)
}
Function: is-identity
declare function is-identity($array as map(*)) as xs:boolean
declare function is-identity($array as map(*)) as xs:boolean
is-identity()
Is this a identity array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a identity array
declare function this:is-identity($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
if ($r = $c)
then $v = 1
else $v = 0
)
)
)
}
Function: is-tridiagonal
declare function is-tridiagonal($array as map(*)) as xs:boolean
declare function is-tridiagonal($array as map(*)) as xs:boolean
is-tridiagonal()
Is this a tridiagonal array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a tridiagonal array
declare function this:is-tridiagonal($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r = $c) or (
if ($r > $c) then (
$r - $c <= 1 or $v = 0
) else (
$c - $r <= 1 or $v = 0
)
)
)
)
)
}
Function: is-upper-triangular
declare function is-upper-triangular($array as map(*)) as xs:boolean
declare function is-upper-triangular($array as map(*)) as xs:boolean
is-upper-triangular()
Is this a upper-triangular array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a upper-triangular array
declare function this:is-upper-triangular($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r <= $c) or $v = 0
)
)
)
}
Function: is-lower-triangular
declare function is-lower-triangular($array as map(*)) as xs:boolean
declare function is-lower-triangular($array as map(*)) as xs:boolean
is-lower-triangular()
Is this a lower-triangular array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a lower-triangular array
declare function this:is-lower-triangular($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r >= $c) or $v = 0
)
)
)
}
Function: is-singular
declare function is-singular($array as map(*)) as xs:boolean
declare function is-singular($array as map(*)) as xs:boolean
is-singular()
Is this a singular array?
Params
- array as map(*): the array
Returns
- xs:boolean: true() is this is a singular array
declare function this:is-singular($array as map(*)) as xs:boolean
{
($array("rows") = $array("columns")) and (this:determinant($array) = 0)
}
Function: trace
declare function trace($array as map(*)) as xs:double
declare function trace($array as map(*)) as xs:double
trace()
Compute the trace of the array.
Raises an error if the array is not square
Params
- array as map(*): the array
Returns
- xs:double: trace of the array
declare function this:trace($array as map(*)) as xs:double
{
sum(this:diagonal($array))
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Function: determinant
declare function determinant($array as map(*)) as xs:double
declare function determinant($array as map(*)) as xs:double
determinant()
Compute the determinant of the array.
Raises an error if the array is not square
Params
- array as map(*): the array
Returns
- xs:double: determinant
declare function this:determinant($array as map(*)) as xs:double
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
switch($num-rows)
case 1 return $data
case 2 return $data[1]*$data[4] - $data[2]*$data[3]
case 3 return (
$data[1]*$data[5]*$data[9] + $data[2]*$data[6]*$data[7] + $data[3]*$data[4]*$data[8]
-$data[1]*$data[6]*$data[8] - $data[2]*$data[4]*$data[9] - $data[3]*$data[5]*$data[7]
)
default return (
sum(
for $i in 1 to $num-columns return (
math:pow(-1, 1 + $i) *
this:determinant(
this:array(
$num-rows - 1,
$num-columns - 1,
for $r in 1 to $num-rows
for $c in 1 to $num-columns
where $r != 1 and $c != $i
return $data[($r - 1)*$num-columns + $c]
)
)
)
)
)
)
)
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Function: transpose
declare function transpose($array as map(*)) as map(*)
declare function transpose($array as map(*)) as map(*)
transpose()
Transpose the array.
Params
- array as map(*): the array
Returns
- map(*): the array, transposed
declare function this:transpose($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
this:array(
$num-columns,
$num-rows,
for $c in 1 to $num-columns
for $r in 1 to $num-rows
return $data[($r - 1)*$num-columns + $c]
)
)
}
Function: cofactor-matrix
declare function cofactor-matrix($array as map(*)) as map(*)
declare function cofactor-matrix($array as map(*)) as map(*)
cofactor-matrix()
Compute the cofactor matrix for the array. Raises an error if it is not square.
Params
- array as map(*): the array
Returns
- map(*): matrix of cofactors
declare function this:cofactor-matrix($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else if ($num-rows = 1) then (
errors:error("UTIL-CANNOT", ("array:cofactor-matrix", $data))
) else (
this:array(
$num-rows,
$num-columns,
for $j in 1 to $num-rows
for $i in 1 to $num-columns
return (
math:pow(-1, $i + $j) *
this:determinant(
this:array(
$num-rows - 1,
$num-columns - 1,
for $r in 1 to $num-rows
for $c in 1 to $num-columns
where $r != $j and $c != $i
return $data[($r - 1)*$num-columns + $c]
)
)
)
)
)
)
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Errors
UTIL-CANNOT if matrix is only 1x1
Function: adjoint
declare function adjoint($array as map(*)) as map(*)
declare function adjoint($array as map(*)) as map(*)
adjoint()
Compute the adjoint of the array. Raises an error if it is not square.
Params
- array as map(*): the array
Returns
- map(*): adjoint matrix
declare function this:adjoint($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
this:transpose(this:cofactor-matrix($array))
)
)
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Function: inverse
declare function inverse($array as map(*)) as map(*)
declare function inverse($array as map(*)) as map(*)
inverse()
Compute the inverse of the array. Raises an error if it is not square.
Params
- array as map(*): the array
Returns
- map(*): array inverse
declare function this:inverse($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
let $det := this:determinant($array)
let $adj := this:adjoint($array)
return this:map($adj, function ($c as xs:double) as xs:double {$c div $det})
)
)
}
Errors
UTIL-MATRIXNOTSQUARE if matrix is not square
Function: times
declare function times($array as map(*), $k as xs:double) as map(*)
declare function times($array as map(*), $k as xs:double) as map(*)
times()
Scalar multiplication of an array by a constant.
Params
- array as map(*): the array
- k as xs:double: multiplier
Returns
- map(*): k*array
declare function this:times($array as map(*), $k as xs:double) as map(*)
{
this:map($array, function ($c as xs:double) { $c*$k })
}
Function: multiply
declare function multiply($a1 as map(*), $a2 as map(*)) as map(*)
declare function multiply($a1 as map(*), $a2 as map(*)) as map(*)
multiply()
Matrix multiplication.
Params
- a1 as map(*): one array
- a2 as map(*): another array
Returns
- map(*): a1*a2
declare function this:multiply($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:multiply", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns2,
for $r in 1 to $rows1
for $c in 1 to $columns2
let $row := this:row($a1, $r)
let $col := this:column($a2, $c)
return sum(for $d at $i in $row return $d * $col[$i])
)
)
)
}
Errors
UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
Function: add
declare function add($a1 as map(*), $a2 as map(*)) as map(*)
declare function add($a1 as map(*), $a2 as map(*)) as map(*)
add()
Matrix addition
Params
- a1 as map(*): one array
- a2 as map(*): another array
Returns
- map(*): a1+a2
declare function this:add($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:add", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d + $data2[$i]
)
)
)
}
Errors
UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
Function: subtract
declare function subtract($a1 as map(*), $a2 as map(*)) as map(*)
declare function subtract($a1 as map(*), $a2 as map(*)) as map(*)
subtract()
Matrix subtraction
Params
- a1 as map(*): one array
- a2 as map(*): another array
Returns
- map(*): a1-a2
declare function this:subtract($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:subtract", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d - $data2[$i]
)
)
)
}
Errors
UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
Function: outer
declare function outer($a1 as map(*), $a2 as map(*)) as map(*)
declare function outer($a1 as map(*), $a2 as map(*)) as map(*)
outer()
Matrix outer multiplication
Params
- a1 as map(*): one array
- a2 as map(*): another array
Returns
- map(*): array where each cell is corresponding a1[i,j]*a2[i,j]
declare function this:outer($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:outer", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d * $data2[$i]
)
)
)
}
Errors
UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
Function: map
declare function map($array as map(*), $f as function(xs:double) as xs:double) as map(*)
declare function map($array as map(*), $f as function(xs:double) as xs:double) as map(*)
map()
Run a function over every item in the array, return the new array, preserving properties.
Params
- array as map(*): the array
- f as function(xs:double)asxs:double: function to apply to all the data in the array
Returns
- map(*): new array
declare function this:map($array as map(*), $f as function(xs:double) as xs:double) as map(*)
{
util:merge-into(
$array,
map {"data": for-each(this:data($array), $f)}
)
}
Function: snap
declare function snap($array as map(*)) as map(*)
declare function snap($array as map(*)) as map(*)
snap()
Snap every value in the array to an integer. Returns an array with integer data values.
Preserves properties.
Params
- array as map(*): the array
Returns
- map(*): new array
declare function this:snap($array as map(*)) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function ($c as xs:double) as xs:integer {
fn:round($c) cast as xs:integer
}
)
}
)
}
Function: floor
declare function floor($array as map(*)) as map(*)
declare function floor($array as map(*)) as map(*)
floor()
Snap every value in the array to the floor of that value, as an integer.
Returns an array with integer data values. Preserves properties.
Params
- array as map(*): the array
Returns
- map(*): new array
declare function this:floor($array as map(*)) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function($c as xs:double) as xs:integer {
fn:floor($c) cast as xs:integer
}
)
}
)
}
Function: decimal
declare function decimal($array as map(*), $digits as xs:integer) as map(*)
declare function decimal($array as map(*), $digits as xs:integer) as map(*)
decimal()
Truncate the number of digits in every value in the array to the given number of
digits,
returning the new array. Preserves properties.
Params
- array as map(*): the array
- digits as xs:integer: number of digits to preserve
Returns
- map(*): new array
declare function this:decimal($array as map(*), $digits as xs:integer) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function($c as xs:double) as xs:double {
util:decimal($c, $digits)
}
)
}
)
}
Function: quote
declare function quote($array as map(*)) as xs:string
declare function quote($array as map(*)) as xs:string
quote()
Return a string representation of the array, suitable for debugging.
Params
- array as map(*): the array
Returns
- xs:string: string
declare function this:quote($array as map(*)) as xs:string
{
string-join((
"[",
for $row in 1 to this:rows($array)
return string-join(this:row($array,$row),","),
"]"
),"
")
}
Function: same
declare function same($this as map(*), $other as map(*)) as xs:boolean
declare function same($this as map(*), $other as map(*)) as xs:boolean
same()
Equality test for two arrays. Arrays are the same if they have the same dimensions
and data.
Auxiliary properties do not factor into this test.
Params
- this as map(*): one array
- other as map(*)
Returns
- xs:boolean: true if the arrays have the same data and sizes
declare function this:same($this as map(*), $other as map(*)) as xs:boolean
{
this:rows($this)=this:rows($other) and
this:columns($this)=this:columns($other) and
deep-equal(this:data($this), this:data($other))
}
Function: horizontal-blur
declare function horizontal-blur($source as map(*),
$radius as xs:integer) as map(*)
declare function horizontal-blur($source as map(*), $radius as xs:integer) as map(*)
horizontal-blur()
Quick horizontal blurring.
Params
- source as map(*) source array
- radius as xs:integer radius of blurring (i.e number of pixels distant)
Returns
- map(*): array with values subject to horizontal blurring
declare function this:horizontal-blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
let $rows := this:rows($source)
let $columns := this:columns($source)
let $data := this:data($source)
let $dest-data := (
for $y in 1 to this:rows($source)
let $total1 :=
sum(for $kx in -$radius to $radius return $data[($y - 1)*$columns + $kx])
let $totals :=
fold-left(2 to $columns, $total1,
function($totals as xs:double*, $x as xs:integer) {
$totals,
$totals[last()]
- ($data[($y - 1)*$columns + $x - $radius - 1],0)[1]
+ ($data[($y - 1)*$columns + $x + $radius],0)[1]
}
)
return (
for $x in 1 to $columns return $totals[$x] div ($radius * 2 + 1)
)
)
return this:array($rows, $columns, $dest-data)
}
Function: vertical-blur
declare function vertical-blur($source as map(*),
$radius as xs:integer) as map(*)
declare function vertical-blur($source as map(*), $radius as xs:integer) as map(*)
vertical-blur()
Quick horizontal blurring.
Params
- source as map(*) source array
- radius as xs:integer radius of blurring (i.e number of pixels distant)
Returns
- map(*): array with values subject to vertical blurring
declare function this:vertical-blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
this:horizontal-blur(this:transpose($source), $radius)=>this:transpose()
}
Function: blur
declare function blur($source as map(*),
$radius as xs:integer) as map(*)
declare function blur($source as map(*), $radius as xs:integer) as map(*)
blur()
Quicker approximation of a Gaussian blur.
Params
- source as map(*) source array
- radius as xs:integer radius of blurring (i.e number of pixels distant)
Returns
- map(*): array with values subject to Gaussian blurring
declare function this:blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
this:horizontal-blur($source,$radius)=>this:vertical-blur($radius)
}
Original Source Code
xquery version "3.1";
(:~
: 2D array of numbers: similar functionality to matrix.xqy, but with
: sequences of doubles. Similar to the relationship between point and vector.
: This supports more matrix operations, such as transposition and inverse.
: This is a row major ordering: note that the get() function, like those
: for point matrices of various kinds puts the row first e.g. get(y,x)
: which is, I admit a bit confusing.
:
: Copyright© Mary Holstege 2021-2025
: CC-BY (https://creativecommons.org/licenses/by/4.0/)
: @since December 2021
: @custom:Status Stable
:)
module namespace this="http://mathling.com/core/array";
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";
declare namespace array="http://www.w3.org/2005/xpath-functions/array";
declare namespace map="http://www.w3.org/2005/xpath-functions/map";
declare namespace math="http://www.w3.org/2005/xpath-functions/math";
declare variable $this:RESERVED := ("kind","rows","columns","data");
(:~
: array()
: Construct a new matrix
: @param $rows number of rows in matrix
: @param $columns number of columns in matrix
: @param $data data values (must be $rows X $columns)
: @return matrix
: @error UTIL-BADARRAY if number of data values doesn't match size
:)
declare function this:array(
$rows as xs:integer,
$columns as xs:integer,
$data as xs:double*
) as map(*)
{
if ($rows * $columns ne count($data))
then errors:error("UTIL-BADARRAY", ($rows, $columns, count($data)))
else (
map {
"kind": "array",
"rows": $rows,
"columns": $columns,
"data": $data
}
)
};
(:~
: Convert an array of arrays (rows of columns) into a new matrix
: @param $data data array; each row must have same number of columns
: @return matrix
: @error UTIL-BADARRAY if number of data values doesn't match size
:)
declare function this:array(
$data as array(array(*))
) as map(*)
{
this:array(array:size($data), array:size($data(1)), array:flatten($data))
};
(:~
: vector()
: Convert a sequence of values into a vector array, where each value is
: in its own row.
: @param $data: sequence of values
: @return matrix
:)
declare function this:vector(
$data as xs:double*
) as map(*)
{
this:array(count($data), 1, $data)
};
(:~
: as-array()
: Convert to an XQuery 2D array (array of arrays). Generally a performance
: move. Creates a row-major array: each entry is a row.
: @param $array the array
: @return an array of arrays, row-major
:)
declare function this:as-array(
$array as map(*)
) as array(array(*))
{
array { for $i in 1 to this:rows($array) return array { this:row($array, $i) } }
};
(:~
: rows()
: Accessor for the number of rows in the array
:
: @param $array the array
: @return number of rows in array
:)
declare function this:rows($array as map(*)) as xs:integer
{
$array("rows")
};
(:~
: columns()
: Accessor for the number of rows in the array
:
: @param $array the array
: @return number of rows in array
:)
declare function this:columns($array as map(*)) as xs:integer
{
$array("columns")
};
(:~
: data()
: Accessor for the data in the array
:
: @param $array the array
: @return sequence of values (row major order)
:)
declare function this:data($array as map(*)) as xs:double*
{
$array("data")
};
(:~
: data()
: Settor for the data in the array
:
: @param $array the array
: @param $data the new data
: @return new matrix
: @error UTIL-BADARRAY if number of data values doesn't match size
:)
declare function this:data($array as map(*), $data as xs:double*) as map(*)
{
if (this:rows($array) * this:columns($array) ne count($data))
then errors:error("UTIL-BADARRAY", (this:rows($array), this:columns($array), count($data)))
else (
$array=>map:put("data", $data)
)
};
(:~
: get()
: Get a specific data value
:
: @param $array: the array
: @param $row: the row number
: @param $column: the column number
: @return data value array[row, column]
:)
declare function this:get(
$array as map(*),
$row as xs:integer,
$column as xs:integer
) as xs:double
{
this:data($array)[($row - 1)*$array("columns") + $column]
};
(:~
: row()
: Return all the values from the given row
:
: @param $array: the array
: @param $row: the row number
: @return values in row in column order
:)
declare function this:row(
$array as map(*),
$row as xs:integer
) as xs:double*
{
if ($row lt 1 or $row gt $array("rows")) then () else
let $data := $array("data")
let $num-columns := $array("columns")
let $ixs :=
for $col in 1 to $num-columns
return ($row - 1)*$num-columns + $col
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
};
(:~
: column()
: Return all the values from the given column
:
: @param $array: the array
: @param $column: the column number
: @return values in column in row order
:)
declare function this:column(
$array as map(*),
$column as xs:integer
) as xs:double*
{
if ($column lt 1 or $column gt $array("columns")) then () else
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
let $ixs :=
for $row in 1 to $num-rows
return ($row - 1)*$num-columns + $column
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
};
(:~
: diagonal()
: Return all the values from the diagonal
: Raises an error if the array is not square
:
: @param $array: the array
: @return values along main diagonal
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
:)
declare function this:diagonal($array as map(*)) as xs:double*
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
let $ixs := for $i in 1 to $num-rows return ($i - 1)*$num-columns + $i
(: Following works because indexes unique and in order :)
return $data[position()=$ixs]
)
)
};
(:~
: is-zero()
: Is this a zero array?
:
: @param $array: the array
: @return true() is this is a zero array
:)
declare function this:is-zero($array as map(*)) as xs:boolean
{
every $v in $array("data") satisfies $v = 0
};
(:~
: is-diagonal()
: Is this a diagonal array?
:
: @param $array: the array
: @return true() is this is a diagonal array
:)
declare function this:is-diagonal($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
if ($r = $c)
then not($v = 0)
else $v = 0
)
)
)
};
(:~
: is-identity()
: Is this a identity array?
:
: @param $array: the array
: @return true() is this is a identity array
:)
declare function this:is-identity($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
if ($r = $c)
then $v = 1
else $v = 0
)
)
)
};
(:~
: is-tridiagonal()
: Is this a tridiagonal array?
:
: @param $array: the array
: @return true() is this is a tridiagonal array
:)
declare function this:is-tridiagonal($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r = $c) or (
if ($r > $c) then (
$r - $c <= 1 or $v = 0
) else (
$c - $r <= 1 or $v = 0
)
)
)
)
)
};
(:~
: is-upper-triangular()
: Is this a upper-triangular array?
:
: @param $array: the array
: @return true() is this is a upper-triangular array
:)
declare function this:is-upper-triangular($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r <= $c) or $v = 0
)
)
)
};
(:~
: is-lower-triangular()
: Is this a lower-triangular array?
:
: @param $array: the array
: @return true() is this is a lower-triangular array
:)
declare function this:is-lower-triangular($array as map(*)) as xs:boolean
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
util:every(
for $r in 1 to $num-rows
for $c in 1 to $num-columns
let $v := $data[($r - 1)*$num-columns + $c]
return (
($r >= $c) or $v = 0
)
)
)
};
(:~
: is-singular()
: Is this a singular array?
:
: @param $array: the array
: @return true() is this is a singular array
:)
declare function this:is-singular($array as map(*)) as xs:boolean
{
($array("rows") = $array("columns")) and (this:determinant($array) = 0)
};
(:~
: trace()
: Compute the trace of the array.
: Raises an error if the array is not square
:
: @param $array: the array
: @return trace of the array
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
:)
declare function this:trace($array as map(*)) as xs:double
{
sum(this:diagonal($array))
};
(:~
: determinant()
: Compute the determinant of the array.
: Raises an error if the array is not square
:
: @param $array: the array
: @return determinant
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
:)
declare function this:determinant($array as map(*)) as xs:double
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
switch($num-rows)
case 1 return $data
case 2 return $data[1]*$data[4] - $data[2]*$data[3]
case 3 return (
$data[1]*$data[5]*$data[9] + $data[2]*$data[6]*$data[7] + $data[3]*$data[4]*$data[8]
-$data[1]*$data[6]*$data[8] - $data[2]*$data[4]*$data[9] - $data[3]*$data[5]*$data[7]
)
default return (
sum(
for $i in 1 to $num-columns return (
math:pow(-1, 1 + $i) *
this:determinant(
this:array(
$num-rows - 1,
$num-columns - 1,
for $r in 1 to $num-rows
for $c in 1 to $num-columns
where $r != 1 and $c != $i
return $data[($r - 1)*$num-columns + $c]
)
)
)
)
)
)
)
};
(:~
: transpose()
: Transpose the array.
:
: @param $array: the array
: @return the array, transposed
:)
declare function this:transpose($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
this:array(
$num-columns,
$num-rows,
for $c in 1 to $num-columns
for $r in 1 to $num-rows
return $data[($r - 1)*$num-columns + $c]
)
)
};
(:~
: cofactor-matrix()
: Compute the cofactor matrix for the array. Raises an error if it is not square.
:
: @param $array: the array
: @return matrix of cofactors
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
: @error UTIL-CANNOT if matrix is only 1x1
:)
declare function this:cofactor-matrix($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else if ($num-rows = 1) then (
errors:error("UTIL-CANNOT", ("array:cofactor-matrix", $data))
) else (
this:array(
$num-rows,
$num-columns,
for $j in 1 to $num-rows
for $i in 1 to $num-columns
return (
math:pow(-1, $i + $j) *
this:determinant(
this:array(
$num-rows - 1,
$num-columns - 1,
for $r in 1 to $num-rows
for $c in 1 to $num-columns
where $r != $j and $c != $i
return $data[($r - 1)*$num-columns + $c]
)
)
)
)
)
)
};
(:~
: adjoint()
: Compute the adjoint of the array. Raises an error if it is not square.
:
: @param $array: the array
: @return adjoint matrix
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
:)
declare function this:adjoint($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
this:transpose(this:cofactor-matrix($array))
)
)
};
(:~
: inverse()
: Compute the inverse of the array. Raises an error if it is not square.
:
: @param $array: the array
: @return array inverse
: @error UTIL-MATRIXNOTSQUARE if matrix is not square
:)
declare function this:inverse($array as map(*)) as map(*)
{
let $data := $array("data")
let $num-rows := $array("rows")
let $num-columns := $array("columns")
return (
if ($num-rows != $num-columns) then (
errors:error("UTIL-MATRIXNOTSQUARE", ($num-rows,$num-columns))
) else (
let $det := this:determinant($array)
let $adj := this:adjoint($array)
return this:map($adj, function ($c as xs:double) as xs:double {$c div $det})
)
)
};
(:~
: times()
: Scalar multiplication of an array by a constant.
:
: @param $array: the array
: @param $k: multiplier
: @return k*array
:)
declare function this:times($array as map(*), $k as xs:double) as map(*)
{
this:map($array, function ($c as xs:double) { $c*$k })
};
(:~
: multiply()
: Matrix multiplication.
:
: @param $a1: one array
: @param $a2: another array
: @return a1*a2
: @error UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
:)
declare function this:multiply($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:multiply", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns2,
for $r in 1 to $rows1
for $c in 1 to $columns2
let $row := this:row($a1, $r)
let $col := this:column($a2, $c)
return sum(for $d at $i in $row return $d * $col[$i])
)
)
)
};
(:~
: add()
: Matrix addition
:
: @param $a1: one array
: @param $a2: another array
: @return a1+a2
: @error UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
:)
declare function this:add($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:add", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d + $data2[$i]
)
)
)
};
(:~
: subtract()
: Matrix subtraction
:
: @param $a1: one array
: @param $a2: another array
: @return a1-a2
: @error UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
:)
declare function this:subtract($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:subtract", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d - $data2[$i]
)
)
)
};
(:~
: outer()
: Matrix outer multiplication
:
: @param $a1: one array
: @param $a2: another array
: @return array where each cell is corresponding a1[i,j]*a2[i,j]
: @error UTIL-MATRIXNOTCOMPAT if the array sizes are incompatible
:)
declare function this:outer($a1 as map(*), $a2 as map(*)) as map(*)
{
if (this:columns($a1) != this:columns($a2) or this:rows($a1) != this:rows($a2)) then (
errors:error("UTIL-MATRIXNOTCOMPAT", ("array:outer", this:rows($a1), this:columns($a1), this:rows($a2), this:columns($a2)))
) else (
let $rows1 := this:rows($a1)
let $columns1 := this:columns($a1)
let $data1 := this:data($a1)
let $rows2 := this:rows($a2)
let $columns2 := this:columns($a2)
let $data2 := this:data($a2)
return (
this:array($rows1, $columns1,
for $d at $i in $data1 return $d * $data2[$i]
)
)
)
};
(:~
: map()
: Run a function over every item in the array, return the new array, preserving properties.
:
: @param $array: the array
: @param $f: function to apply to all the data in the array
: @return new array
:)
declare function this:map($array as map(*), $f as function(xs:double) as xs:double) as map(*)
{
util:merge-into(
$array,
map {"data": for-each(this:data($array), $f)}
)
};
(:~
: snap()
: Snap every value in the array to an integer. Returns an array with integer data values.
: Preserves properties.
:
: @param $array: the array
: @return new array
:)
declare function this:snap($array as map(*)) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function ($c as xs:double) as xs:integer {
fn:round($c) cast as xs:integer
}
)
}
)
};
(:~
: floor()
: Snap every value in the array to the floor of that value, as an integer.
: Returns an array with integer data values. Preserves properties.
:
: @param $array: the array
: @return new array
:)
declare function this:floor($array as map(*)) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function($c as xs:double) as xs:integer {
fn:floor($c) cast as xs:integer
}
)
}
)
};
(:~
: decimal()
: Truncate the number of digits in every value in the array to the given number of digits,
: returning the new array. Preserves properties.
:
: @param $array: the array
: @param $digits: number of digits to preserve
: @return new array
:)
declare function this:decimal($array as map(*), $digits as xs:integer) as map(*)
{
util:merge-into(
$array,
map {
"data":
for-each(this:data($array),
function($c as xs:double) as xs:double {
util:decimal($c, $digits)
}
)
}
)
};
(:~
: quote()
: Return a string representation of the array, suitable for debugging.
:
: @param $array: the array
: @return string
:)
declare function this:quote($array as map(*)) as xs:string
{
string-join((
"[",
for $row in 1 to this:rows($array)
return string-join(this:row($array,$row),","),
"]"
),"
")
};
(:~
: same()
: Equality test for two arrays. Arrays are the same if they have the same dimensions and data.
: Auxiliary properties do not factor into this test.
:
: @param $this: one array
: @param $that: another array
: @return true if the arrays have the same data and sizes
:)
declare function this:same($this as map(*), $other as map(*)) as xs:boolean
{
this:rows($this)=this:rows($other) and
this:columns($this)=this:columns($other) and
deep-equal(this:data($this), this:data($other))
};
(:~
: horizontal-blur()
: Quick horizontal blurring.
: @param $source source array
: @param $radius radius of blurring (i.e number of pixels distant)
: @return array with values subject to horizontal blurring
:)
declare function this:horizontal-blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
let $rows := this:rows($source)
let $columns := this:columns($source)
let $data := this:data($source)
let $dest-data := (
for $y in 1 to this:rows($source)
let $total1 :=
sum(for $kx in -$radius to $radius return $data[($y - 1)*$columns + $kx])
let $totals :=
fold-left(2 to $columns, $total1,
function($totals as xs:double*, $x as xs:integer) {
$totals,
$totals[last()]
- ($data[($y - 1)*$columns + $x - $radius - 1],0)[1]
+ ($data[($y - 1)*$columns + $x + $radius],0)[1]
}
)
return (
for $x in 1 to $columns return $totals[$x] div ($radius * 2 + 1)
)
)
return this:array($rows, $columns, $dest-data)
};
(:~
: vertical-blur()
: Quick horizontal blurring.
: @param $source source array
: @param $radius radius of blurring (i.e number of pixels distant)
: @return array with values subject to vertical blurring
:)
declare function this:vertical-blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
this:horizontal-blur(this:transpose($source), $radius)=>this:transpose()
};
(:~
: blur()
: Quicker approximation of a Gaussian blur.
: @param $source source array
: @param $radius radius of blurring (i.e number of pixels distant)
: @return array with values subject to Gaussian blurring
:)
declare function this:blur(
$source as map(*),
$radius as xs:integer
) as map(*)
{
this:horizontal-blur($source,$radius)=>this:vertical-blur($radius)
};