http://mathling.com/core/complex/vector library module
http://mathling.com/core/complex/vector
Complex numbers (vector implementation)
Copyright© Mary Holstege 2021-2023
CC-BY (https://creativecommons.org/licenses/by/4.0/)
Status: Stable
Imports
http://mathling.com/core/utilitiesimport module namespace util="http://mathling.com/core/utilities" at "../core/utilities.xqy"http://mathling.com/core/vector
import module namespace v="http://mathling.com/core/vector" at "../core/vector.xqy"http://mathling.com/core/config
import module namespace config="http://mathling.com/core/config" at "../core/config.xqy"http://mathling.com/core/errors
import module namespace errors="http://mathling.com/core/errors" at "../core/errors.xqy"http://mathling.com/geometric/point
import module namespace point="http://mathling.com/geometric/point" at "../geo/point.xqy"
Variables
Variable: $i as xs:double*
Variable: $one as xs:double*
Functions
Function: complex
declare function complex($real as xs:double,
$imaginary as xs:double) as xs:double*
declare function complex($real as xs:double, $imaginary as xs:double) as xs:double*
complex()
Construct a new complex number.
Params
- real as xs:double: the real part of the number
- imaginary as xs:double: the imaginary part of the number
Returns
- xs:double*: complex number
declare function this:complex( $real as xs:double, $imaginary as xs:double ) as xs:double* { ($real, $imaginary) }
Function: as-complex
declare function as-complex($real as xs:double) as xs:double*
declare function as-complex($real as xs:double) as xs:double*
as-complex()
Cast a real number to a complex.
Params
- real as xs:double: the real part of the number
Returns
- xs:double*: complex number
declare function this:as-complex( $real as xs:double ) as xs:double* { ($real, 0) }
Function: is-real
declare function is-real($z as xs:double*) as xs:boolean
declare function is-real($z as xs:double*) as xs:boolean
is-real()
Test whether the number has no imaginary part. (Within ε).
Params
- z as xs:double*: the complex number
Returns
- xs:boolean: true if complex number has only a real part
declare function this:is-real( $z as xs:double* ) as xs:boolean { abs(this:pi($z)) < $config:ε }
Function: as-real
declare function as-real($z as xs:double*) as xs:double
declare function as-real($z as xs:double*) as xs:double
as-real()
Cast a complex number to a double, if possible. Raises error if not.
Params
- z as xs:double*: the complex number
Returns
- xs:double: double
declare function this:as-real( $z as xs:double* ) as xs:double { if (this:is-real($z)) then this:pr($z) else errors:error("UTIL-CAST", ($z,'complex')) }
Errors
UTIL-CAST if there is an imaginary part
Function: complex-rφd
declare function complex-rφd($r as xs:double,
$φ as xs:double) as xs:double*
declare function complex-rφd($r as xs:double, $φ as xs:double) as xs:double*
complex-rφd()
Construct a new complex number using radius and phase angle
(polar repesentation re^iφ).
Params
- r as xs:double: modulus of complex number
- φ as xs:double: angle of complex number (degrees)
Returns
- xs:double*: complex number
declare function this:complex-rφd( $r as xs:double, $φ as xs:double ) as xs:double* { let $φR := util:radians($φ) return ($r * math:cos($φR), $r * math:sin($φR)) }
Function: complex-rφ
declare function complex-rφ($r as xs:double,
$φ as xs:double) as xs:double*
declare function complex-rφ($r as xs:double, $φ as xs:double) as xs:double*
complex-rφ()
Construct a new complex number using radius and phase angle
(polar repesentation re^iφ).
Params
- r as xs:double: modulus of complex number
- φ as xs:double: angle of complex number (radians)
Returns
- xs:double*: complex number
declare function this:complex-rφ( $r as xs:double, $φ as xs:double ) as xs:double* { ($r * math:cos($φ), $r * math:sin($φ)) }
Function: pr
declare function pr($z as xs:double*) as xs:double
declare function pr($z as xs:double*) as xs:double
pr()
Accessor for real part of the complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double: raw real part
declare function this:pr($z as xs:double*) as xs:double { v:px($z) }
Function: pi
declare function pi($z as xs:double*) as xs:double
declare function pi($z as xs:double*) as xs:double
pi()
Accessor for imaginary part of the complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double: raw imaginary part
declare function this:pi($z as xs:double*) as xs:double { v:py($z) }
Function: r
declare function r($z as xs:double*) as xs:integer
declare function r($z as xs:double*) as xs:integer
r()
Accessor for real part of the complex number, as integer.
Params
- z as xs:double*: the complex number
Returns
- xs:integer: real part, rounded
declare function this:r($z as xs:double*) as xs:integer { v:x($z) }
Function: i
declare function i($z as xs:double*) as xs:integer
declare function i($z as xs:double*) as xs:integer
i()
Accessor for imaginary part of the complex number, as integer.
Params
- z as xs:double*: the complex number
Returns
- xs:integer: imaginary part, rounded
declare function this:i($z as xs:double*) as xs:integer { v:y($z) }
Function: add
declare function add($z1 as xs:double*,
$z2 as xs:double*) as xs:double*
declare function add($z1 as xs:double*, $z2 as xs:double*) as xs:double*
add()
Add two complex numbers.
Params
- z1 as xs:double*: one complex number
- z2 as xs:double*: other complex number
Returns
- xs:double*: z1+z2
declare function this:add( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { $z1=>v:add($z2) }
Function: sum
declare function sum($zs as xs:double*) as xs:double*
declare function sum($zs as xs:double*) as xs:double*
sum()
Add several complex numbers in one go.
Params
- zs as xs:double*
Returns
- xs:double*
declare function this:sum( $zs as xs:double* ) as xs:double* { sum(for $i in 1 to count($zs) idiv 2 return $zs[2*$i - 1]), sum(for $i in 1 to count($zs) idiv 2 return $zs[2*$i]) }
Function: sub
declare function sub($z1 as xs:double*,
$z2 as xs:double*) as xs:double*
declare function sub($z1 as xs:double*, $z2 as xs:double*) as xs:double*
sub()
Subtract one complex numbers from another.
Params
- z1 as xs:double*: the first complex number
- z2 as xs:double*: the complex number to subtract from the first complex number
Returns
- xs:double*: z1-z2
declare function this:sub( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { $z1=>v:sub($z2) }
Function: minus
declare function minus($z as xs:double*) as xs:double*
declare function minus($z as xs:double*) as xs:double*
minus()
Negation
Params
- z as xs:double*1 the first complex number
Returns
- xs:double*: -z1
declare function this:minus( $z as xs:double* ) as xs:double* { $z=>this:times(-1) }
Function: multiply
declare function multiply($z1 as xs:double*,
$z2 as xs:double*) as xs:double*
declare function multiply($z1 as xs:double*, $z2 as xs:double*) as xs:double*
multiply()
Multiply two complex numbers.
Params
- z1 as xs:double*: one complex number
- z2 as xs:double*: other complex number
Returns
- xs:double*: z1*z2
declare function this:multiply( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { (: (a + bi)*(c + di) = (ac - bd) + (ad + bc)i :) ( this:pr($z1)*this:pr($z2) - this:pi($z1)*this:pi($z2), this:pr($z1)*this:pi($z2) + this:pi($z1)*this:pr($z2) ) }
Function: pow
declare function pow($z as xs:double*,
$pow as xs:integer) as xs:double*
declare function pow($z as xs:double*, $pow as xs:integer) as xs:double*
pow()
Raise a complex number to the given (positive integer) power.
A convenience function for repeated multiplication. For general powers use ppow()
Params
- z as xs:double*: the complex number
- pow as xs:integer: the power to raise it to
Returns
- xs:double*: z^pow
declare function this:pow( $z as xs:double*, $pow as xs:integer ) as xs:double* { if (this:pi($z)=0) then this:complex(math:pow(this:pr($z), $pow), 0) else switch ($pow) case 0 return $this:one case 1 return $z case 2 return $z=>this:multiply($z) case 3 return $z=>this:multiply($z)=>this:multiply($z) default return (: General: : a + ib = r(cosφ + isinφ) r² = a² + b², φ = atan(b/a) : (a + ib)^N = r^N(cos(Nφ) + isin(Nφ)) :) let $r := this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) let $φ := math:atan2(this:pi($z), this:pr($z)) let $r_N := math:pow($r,$pow) return this:complex($r_N*math:cos($pow*$φ), $r_N*math:sin($pow*$φ)) }
Function: ppow
declare function ppow($z as xs:double*,
$pow as xs:double*) as xs:double*
declare function ppow($z as xs:double*, $pow as xs:double*) as xs:double*
ppow()
Principle power for non-integer powers.
Params
- z as xs:double*: the complex number
- pow as xs:double*: the power to raise it to
Returns
- xs:double*: z^pow
declare function this:ppow( $z as xs:double*, $pow as xs:double* ) as xs:double* { (: a^b = e^(b log(a)) :) this:exp(this:log($z)=>this:multiply($pow)) }
Function: log
declare function log($z as xs:double*) as xs:double*
declare function log($z as xs:double*) as xs:double*
log()
Natural log of complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: log(z)
declare function this:log( $z as xs:double* ) as xs:double* { this:complex(math:log(this:modulus($z)), this:angle($z)=>util:radians()) }
Function: sqrt
declare function sqrt($z as xs:double*) as xs:double*
declare function sqrt($z as xs:double*) as xs:double*
sqrt()
Principal square root of complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: √z
declare function this:sqrt( $z as xs:double* ) as xs:double* { if (this:pi($z) = 0) then ( if (this:pr($z) >= 0) then this:complex(math:sqrt(this:pr($z)), 0) else this:complex(0, math:sqrt(-this:pr($z))) ) else ( let $r := this:modulus($z) return this:complex( math:sqrt(($r + this:pr($z)) div 2), util:sign(this:pi($z)) * math:sqrt(($r - this:pr($z)) div 2) ) ) }
Function: cbrt
declare function cbrt($z as xs:double*) as xs:double*
declare function cbrt($z as xs:double*) as xs:double*
cbrt()
Principal cubic root of a complex number. (Highest real part.)
Roots for n integer: for 0 ≤ k < n
z^(1/n) = r^(1/n)(cos((φ + 2kπ)/n) + i sin((φ + 2kπ)/n))
Params
- z as xs:double*: the complex number
Returns
- xs:double*: z^1/3
declare function this:cbrt( $z as xs:double* ) as xs:double* { if (this:pi($z) = 0) then ( if (this:pr($z) >= 0) then this:complex(util:cbrt(this:pr($z)), 0) else this:complex(-util:cbrt(-this:pr($z)), 0) ) else ( let $r := this:modulus($z) let $φ := this:angle($z)=>util:radians() let $rcbrt := util:cbrt($r) let $k := head(for $k in 0 to 2 order by math:cos(($φ + 2*$k*math:pi()) div 3) descending return $k) return ( this:complex( $rcbrt * math:cos(($φ + 2*$k*math:pi()) div 3), $rcbrt * math:sin(($φ + 2*$k*math:pi()) div 3) ) ) ) }
Function: sin
declare function sin($z as xs:double*) as xs:double*
declare function sin($z as xs:double*) as xs:double*
sin()
Sine of complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: sin(z)
declare function this:sin( $z as xs:double* ) as xs:double* { (: : sin(x + iy) = sin(x)cosh(y) + i cos(x)sinh(y) :) this:complex( math:sin(this:pr($z))*util:cosh(this:pi($z)), math:cos(this:pr($z))*util:sinh(this:pi($z)) ) }
Function: cos
declare function cos($z as xs:double*) as xs:double*
declare function cos($z as xs:double*) as xs:double*
cos()
Cosine of complex number.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: cos(z)
declare function this:cos( $z as xs:double* ) as xs:double* { (: : cos(x + iy) = cos(x)cosh(y) - i sin(x)sinh(y) :) this:complex( math:cos(this:pr($z))*util:cosh(this:pi($z)), -math:sin(this:pr($z))*util:sinh(this:pi($z)) ) }
Function: sinh
declare function sinh($z as xs:double*) as xs:double*
declare function sinh($z as xs:double*) as xs:double*
sinh()
Hyperbolic sine.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: sinh(z)
declare function this:sinh($z as xs:double*) as xs:double* { (: sinh(x + iy) = sinh(x)cos(y) + cosh(x)sin(y) :) this:complex( util:sinh(this:pr($z))*math:cos(this:pi($z)), util:cosh(this:pr($z))*math:sin(this:pi($z)) ) }
Function: cosh
declare function cosh($z as xs:double*) as xs:double*
declare function cosh($z as xs:double*) as xs:double*
cosh()
Hyperbolic cosine.
Params
- z as xs:double*: the complex number
Returns
- xs:double*: cosh(z)
declare function this:cosh($z as xs:double*) as xs:double* { (: cosh(x + iy) = cosh(x)cos(y) - sinh(x)sin(y) :) this:complex( util:cosh(this:pr($z))*math:cos(this:pi($z)), -util:sinh(this:pr($z))*math:sin(this:pi($z)) ) }
Function: asin
declare function asin($z as xs:double*) as xs:double*
declare function asin($z as xs:double*) as xs:double*
asin()
arcsin(z): -i ln(iz + √(1 - z²))
Params
- z as xs:double*: the complex number
Returns
- xs:double*: asin(z)
declare function this:asin( $z as xs:double* ) as xs:double* { this:log( this:multiply($this:i, $z)=>this:add( this:sqrt( $this:one=>this:sub( this:pow($z, 2) ) ) ) )=>this:multiply(this:minus($this:i)) }
Function: acos
declare function acos($z as xs:double*) as xs:double*
declare function acos($z as xs:double*) as xs:double*
acos()
arccos(z): (1/i) ln(z + √(z² - 1))
Params
- z as xs:double*: the complex number
Returns
- xs:double*: acos(z)
declare function this:acos( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:sub( $this:one ) ) ) )=>this:multiply( this:reciprocal($this:i) ) }
Function: asinh
declare function asinh($z as xs:double*) as xs:double*
declare function asinh($z as xs:double*) as xs:double*
asinh()
Inverse hyperbolic sine: asinh(z) = ln(z + √(z²+1))
Params
- z as xs:double*
Returns
- xs:double*
declare function this:asinh( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:add( $this:one ) ) ) ) }
Function: acosh
declare function acosh($z as xs:double*) as xs:double*
declare function acosh($z as xs:double*) as xs:double*
acosh()
Inverse hyperbolic cosine: acosh(z) = ln(z + √(z²-1))
Params
- z as xs:double*
Returns
- xs:double*
declare function this:acosh( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:sub( $this:one ) ) ) ) }
Function: exp
declare function exp($z as xs:double*) as xs:double*
declare function exp($z as xs:double*) as xs:double*
exp()
Exponential of z: e^z
Params
- z as xs:double*: the complex number
Returns
- xs:double*: e^z
declare function this:exp( $z as xs:double* ) as xs:double* { ( math:exp(this:pr($z)) * math:cos(this:pi($z)), math:exp(this:pr($z)) * math:sin(this:pi($z)) ) }
Function: times
declare function times($z as xs:double*,
$k as xs:double) as xs:double*
declare function times($z as xs:double*, $k as xs:double) as xs:double*
times()
Multiply a complex by a constant.
Params
- z as xs:double*: the complex number
- k as xs:double: the constant to multiply by
Returns
- xs:double*: k*z
declare function this:times( $z as xs:double*, $k as xs:double ) as xs:double* { $z=>v:times($k) }
Function: plus
declare function plus($z as xs:double*,
$k as xs:double) as xs:double*
declare function plus($z as xs:double*, $k as xs:double) as xs:double*
plus()
Add a constant to a complex number. (i.e. add complex number ($k, 0))
Params
- z as xs:double*: the complex number
- k as xs:double: the constant to add
Returns
- xs:double*: z+k
declare function this:plus( $z as xs:double*, $k as xs:double ) as xs:double* { $z=>this:add(this:complex($k, 0)) }
Function: divide
declare function divide($z1 as xs:double*,
$z2 as xs:double*) as xs:double*
declare function divide($z1 as xs:double*, $z2 as xs:double*) as xs:double*
divide()
Divide two complex numbers.
Params
- z1 as xs:double*: one complex number
- z2 as xs:double*: other complex number
Returns
- xs:double*: z1/z2
declare function this:divide( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { (: (a + bi)/(c + di) = ((ac + bd) + i(bc - ad))/(c² + d²) :) let $r2 := this:pr($z2)*this:pr($z2) + this:pi($z2)*this:pi($z2) return ( (this:pr($z1)*this:pr($z2) + this:pi($z1)*this:pi($z2)) div $r2, (this:pi($z1)*this:pr($z2) - this:pr($z1)*this:pi($z2)) div $r2 ) }
Function: divide-by-i
declare function divide-by-i($z as xs:double*) as xs:double*
declare function divide-by-i($z as xs:double*) as xs:double*
divide-by-i()
Divide complex numbers by i.
Params
- z as xs:double*
Returns
- xs:double*: z/i
declare function this:divide-by-i( $z as xs:double* ) as xs:double* { (: (a + bi)/(c + di) = ((ac + bd) + i(bc - ad))/(c² + d²) :) (: (a + bi)/(0 + 1i) = ((0a + b1) + i(b0 - a1))/(0² + 1²) = b - ai :) ( this:pi($z), -this:pr($z) ) }
Function: modulus
declare function modulus($z as xs:double*) as xs:double
declare function modulus($z as xs:double*) as xs:double
modulus()
Modulus of a complex number. Given z = re^iφ, the r.
Params
- z as xs:double*: the complex numbers
Returns
- xs:double: modulus
declare function this:modulus( $z as xs:double* ) as xs:double { math:sqrt(this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z)) }
Function: modsq
declare function modsq($z as xs:double*) as xs:double
declare function modsq($z as xs:double*) as xs:double
modsq()
Modulus of a complex number, squared. Given z = re^iφ, r². Used for cases
where we want to avoid a lot of square root calculations.
Params
- z as xs:double*: the complex number
Returns
- xs:double: modulus²
declare function this:modsq( $z as xs:double* ) as xs:double { this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) }
Function: angle
declare function angle($z as xs:double*) as xs:double
declare function angle($z as xs:double*) as xs:double
angle()
The angle of the complex number. Given z = re^iφ, the φ in degrees.
Params
- z as xs:double*: the complex numbers
Returns
- xs:double: phase angle, in degrees
declare function this:angle( $z as xs:double* ) as xs:double { math:atan2(this:pi($z), this:pr($z))=>util:degrees()=>util:remap-degrees() }
Function: normalize
declare function normalize($z as xs:double*) as xs:double*
declare function normalize($z as xs:double*) as xs:double*
normalize()
Normalize the complex number so modulus is 1.
Params
- z as xs:double*: the complex number to normalize
Returns
- xs:double*: complex number
declare function this:normalize($z as xs:double*) as xs:double* { let $l := this:modulus($z) return this:complex(this:pr($z) div $l, this:pi($z) div $l) }
Function: is-gauss-prime
declare function is-gauss-prime($z as xs:double*) as xs:boolean
declare function is-gauss-prime($z as xs:double*) as xs:boolean
is-gauss-prime()
Test whether complex number is gaussian prime; snaps to integral value.
Params
- z as xs:double*: complex number to test
Returns
- xs:boolean: true if z is Gaussian prime
declare function this:is-gauss-prime($z as xs:double*) as xs:boolean { let $a := this:r($z) let $b := this:i($z) return ( if ($a * $b != 0) then ( util:is-prime($a*$a + $b*$b) ) else ( let $c := abs($a + $b) return util:is-prime($c) and $c mod 4 = 3 ) ) }
Function: conjugate
declare function conjugate($z as xs:double*) as xs:double*
declare function conjugate($z as xs:double*) as xs:double*
conjugate()
Return the complex conjugate
Params
- z as xs:double*: complex number
Returns
- xs:double*: conj(z)
declare function this:conjugate($z as xs:double*) as xs:double* { this:complex(this:pr($z), -this:pi($z)) }
Function: reciprocal
declare function reciprocal($z as xs:double*) as xs:double*
declare function reciprocal($z as xs:double*) as xs:double*
reciprocal()
The reciprocal of z: 1 / z
Params
- z as xs:double*: complex number
Returns
- xs:double*: 1/z
declare function this:reciprocal($z as xs:double*) as xs:double* { let $r := this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) return this:complex(this:pr($z) div $r, -this:pi($z) div $r) }
Function: abs
declare function abs($z as xs:double*) as xs:double*
declare function abs($z as xs:double*) as xs:double*
abs()
The absolute value of z
Params
- z as xs:double*: complex number
Returns
- xs:double*: abs(z)
declare function this:abs($z as xs:double*) as xs:double* { this:complex(abs(this:pr($z)), abs(this:pi($z))) }
Function: quote
declare function quote($zs as xs:double*) as xs:string
declare function quote($zs as xs:double*) as xs:string
quote()
Return a string value of the complex numbers
Params
- zs as xs:double*: complex numbers
Returns
- xs:string: string
declare function this:quote($zs as xs:double*) as xs:string { string-join( let $chunks := for $z at $i in $zs return ( if ($i mod 2 = 0) then ( array {$zs[$i - 1], $z} ) else () ) for $chunk in $chunks let $z := $chunk?* return ( let $r := this:pr($z) let $i := this:pi($z) return if ($r = 0 and $i = 0) then "0" else if ($r = 0) then $i||"i" else if ($i = 0) then string($r) else if ($i < 0) then $r||$i||"i" else $r||"+"||$i||"i" ) , " " ) }
Function: unquote
declare function unquote($zs as xs:string) as xs:double*
declare function unquote($zs as xs:string) as xs:double*
unquote()
Parse a string value of a complex number to produce that complex number.
Number is of the form 33+12i
Params
- zs as xs:string: the string representation of the number
Returns
- xs:double*: complex number
declare function this:unquote($zs as xs:string) as xs:double* { (: Cases: : 2 : -2 : i : 3i : -3i : 2+3i : -2+3i : 2-3i : -2-3i : 2+ i : 2- i : -2+ i : -2- i :) let $z := number($zs) return if ($z = $z) then this:complex($z, 0) (: 2 | -2 :) else if ($zs = "i") then this:complex(0, 1) (: i :) else ( let $parts := analyze-string($zs, "[-+]?[0123456789.]+") return ( switch (count($parts/fn:match)) case 0 return if ($parts/fn:non-match=("i","+i")) then this:complex(0, 1) else if ($parts/fn:non-match="-i") then this:complex(0, -1) else errors:error("UTIL-BADCOMPLEX", $zs) case 1 return let $next := $parts/fn:match/following-sibling::fn:non-match[1] return if (empty($next)) then this:complex(number($parts/fn:match), 0) else if ($next="+i") then this:complex(number($parts/fn:match), 1) else if ($next="-i") then this:complex(number($parts/fn:match), -1) else this:complex(0, number($parts/fn:match)) case 2 return this:complex(number($parts/fn:match[1]), number($parts/fn:match[2])) default return errors:error("UTIL-BADCOMPLEX", $zs) ) ) }
Function: eq
declare function eq($z as xs:double*, $val as xs:double) as xs:boolean
declare function eq($z as xs:double*, $val as xs:double) as xs:boolean
eq()
Is the complex number equal to the double value? That is, does it have
no imaginary part and a real part equal to the value?
Params
- z as xs:double*: one complex number
- val as xs:double: a double value
Returns
- xs:boolean: real(z)=val and imaginary(z)=0 (within epsilon)
declare function this:eq($z as xs:double*, $val as xs:double) as xs:boolean { this:pr($z)=$val and this:is-real($z) }
Function: same
declare function same($z1 as xs:double*, $z2 as xs:double*) as xs:boolean
declare function same($z1 as xs:double*, $z2 as xs:double*) as xs:boolean
same()
Are the two complex numbers the same?
Params
- z1 as xs:double*: one complex number
- z2 as xs:double*: other complex number
Returns
- xs:boolean: z1=z2
declare function this:same($z1 as xs:double*, $z2 as xs:double*) as xs:boolean { this:pr($z1)=this:pr($z2) and this:pi($z1)=this:pi($z2) }
Function: decimal
declare function decimal($zs as xs:double*, $digits as xs:integer) as xs:double*
declare function decimal($zs as xs:double*, $digits as xs:integer) as xs:double*
decimal()
Cast the values to a values with the given number of digits.
Params
- zs as xs:double*: the complex numbers
- digits as xs:integer: how many digits to preserve
Returns
- xs:double*: complex numbers
declare function this:decimal($zs as xs:double*, $digits as xs:integer) as xs:double* { v:decimal($zs, $digits) }
Original Source Code
xquery version "3.1"; (:~ : Complex numbers (vector implementation) : : Copyright© Mary Holstege 2021-2023 : CC-BY (https://creativecommons.org/licenses/by/4.0/) : @since November 2022 : @custom:Status Stable :) module namespace this="http://mathling.com/core/complex/vector"; 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 v="http://mathling.com/core/vector" at "../core/vector.xqy"; import module namespace point="http://mathling.com/geometric/point" at "../geo/point.xqy"; 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:i as xs:double* := this:complex(0, 1); declare variable $this:one as xs:double* := this:complex(1, 0); (:~ : complex() : Construct a new complex number. : : @param $real: the real part of the number : @param $imaginary: the imaginary part of the number : @return complex number :) declare function this:complex( $real as xs:double, $imaginary as xs:double ) as xs:double* { ($real, $imaginary) }; (:~ : as-complex() : Cast a real number to a complex. : : @param $real: the real part of the number : @return complex number :) declare function this:as-complex( $real as xs:double ) as xs:double* { ($real, 0) }; (:~ : is-real() : Test whether the number has no imaginary part. (Within ε). : : @param $z: the complex number : @return true if complex number has only a real part :) declare function this:is-real( $z as xs:double* ) as xs:boolean { abs(this:pi($z)) < $config:ε }; (:~ : as-real() : Cast a complex number to a double, if possible. Raises error if not. : : @param $z: the complex number : @return double : @error UTIL-CAST if there is an imaginary part :) declare function this:as-real( $z as xs:double* ) as xs:double { if (this:is-real($z)) then this:pr($z) else errors:error("UTIL-CAST", ($z,'complex')) }; (:~ : complex-rφd() : Construct a new complex number using radius and phase angle : (polar repesentation re^iφ). : : @param $r: modulus of complex number : @param $φ: angle of complex number (degrees) : @return complex number :) declare function this:complex-rφd( $r as xs:double, $φ as xs:double ) as xs:double* { let $φR := util:radians($φ) return ($r * math:cos($φR), $r * math:sin($φR)) }; (:~ : complex-rφ() : Construct a new complex number using radius and phase angle : (polar repesentation re^iφ). : : @param $r: modulus of complex number : @param $φ: angle of complex number (radians) : @return complex number :) declare function this:complex-rφ( $r as xs:double, $φ as xs:double ) as xs:double* { ($r * math:cos($φ), $r * math:sin($φ)) }; (:~ : pr() : Accessor for real part of the complex number. : : @param $z: the complex number : @return raw real part :) declare function this:pr($z as xs:double*) as xs:double { v:px($z) }; (:~ : pi() : Accessor for imaginary part of the complex number. : : @param $z: the complex number : @return raw imaginary part :) declare function this:pi($z as xs:double*) as xs:double { v:py($z) }; (:~ : r() : Accessor for real part of the complex number, as integer. : : @param $z: the complex number : @return real part, rounded :) declare function this:r($z as xs:double*) as xs:integer { v:x($z) }; (:~ : i() : Accessor for imaginary part of the complex number, as integer. : : @param $z: the complex number : @return imaginary part, rounded :) declare function this:i($z as xs:double*) as xs:integer { v:y($z) }; (:~ : add() : Add two complex numbers. : : @param $z1: one complex number : @param $z2: other complex number : @return z1+z2 :) declare function this:add( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { $z1=>v:add($z2) }; (:~ : sum() : Add several complex numbers in one go. :) declare function this:sum( $zs as xs:double* ) as xs:double* { sum(for $i in 1 to count($zs) idiv 2 return $zs[2*$i - 1]), sum(for $i in 1 to count($zs) idiv 2 return $zs[2*$i]) }; (:~ : sub() : Subtract one complex numbers from another. : : @param $z1: the first complex number : @param $z2: the complex number to subtract from the first complex number : @return z1-z2 :) declare function this:sub( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { $z1=>v:sub($z2) }; (:~ : minus() : Negation : : @param $z1 the first complex number : @return -z1 :) declare function this:minus( $z as xs:double* ) as xs:double* { $z=>this:times(-1) }; (:~ : multiply() : Multiply two complex numbers. : : @param $z1: one complex number : @param $z2: other complex number : @return z1*z2 :) declare function this:multiply( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { (: (a + bi)*(c + di) = (ac - bd) + (ad + bc)i :) ( this:pr($z1)*this:pr($z2) - this:pi($z1)*this:pi($z2), this:pr($z1)*this:pi($z2) + this:pi($z1)*this:pr($z2) ) }; (:~ : pow() : Raise a complex number to the given (positive integer) power. : A convenience function for repeated multiplication. For general powers use ppow() : : @param $z: the complex number : @param $pow: the power to raise it to : @return z^pow :) declare function this:pow( $z as xs:double*, $pow as xs:integer ) as xs:double* { if (this:pi($z)=0) then this:complex(math:pow(this:pr($z), $pow), 0) else switch ($pow) case 0 return $this:one case 1 return $z case 2 return $z=>this:multiply($z) case 3 return $z=>this:multiply($z)=>this:multiply($z) default return (: General: : a + ib = r(cosφ + isinφ) r² = a² + b², φ = atan(b/a) : (a + ib)^N = r^N(cos(Nφ) + isin(Nφ)) :) let $r := this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) let $φ := math:atan2(this:pi($z), this:pr($z)) let $r_N := math:pow($r,$pow) return this:complex($r_N*math:cos($pow*$φ), $r_N*math:sin($pow*$φ)) }; (:~ : ppow() : Principle power for non-integer powers. : @param $z: the complex number : @param $pow: the power to raise it to : @return z^pow :) declare function this:ppow( $z as xs:double*, $pow as xs:double* ) as xs:double* { (: a^b = e^(b log(a)) :) this:exp(this:log($z)=>this:multiply($pow)) }; (: https://math.stackexchange.com/questions/1103102/how-to-raise-1-to-non-integer-powers :) (: http://www.milefoot.com/math/complex/functionsofi.htm :) (: http://en.wikipedia.org/wiki/Complex_number :) (:~ : log() : Natural log of complex number. : : @param $z: the complex number : @return log(z) :) declare function this:log( $z as xs:double* ) as xs:double* { this:complex(math:log(this:modulus($z)), this:angle($z)=>util:radians()) }; (:~ : sqrt() : Principal square root of complex number. : : @param $z: the complex number : @return √z :) declare function this:sqrt( $z as xs:double* ) as xs:double* { if (this:pi($z) = 0) then ( if (this:pr($z) >= 0) then this:complex(math:sqrt(this:pr($z)), 0) else this:complex(0, math:sqrt(-this:pr($z))) ) else ( let $r := this:modulus($z) return this:complex( math:sqrt(($r + this:pr($z)) div 2), util:sign(this:pi($z)) * math:sqrt(($r - this:pr($z)) div 2) ) ) }; (:~ : cbrt() : Principal cubic root of a complex number. (Highest real part.) : Roots for n integer: for 0 ≤ k < n : z^(1/n) = r^(1/n)(cos((φ + 2kπ)/n) + i sin((φ + 2kπ)/n)) : : @param $z: the complex number : @return z^1/3 :) declare function this:cbrt( $z as xs:double* ) as xs:double* { if (this:pi($z) = 0) then ( if (this:pr($z) >= 0) then this:complex(util:cbrt(this:pr($z)), 0) else this:complex(-util:cbrt(-this:pr($z)), 0) ) else ( let $r := this:modulus($z) let $φ := this:angle($z)=>util:radians() let $rcbrt := util:cbrt($r) let $k := head(for $k in 0 to 2 order by math:cos(($φ + 2*$k*math:pi()) div 3) descending return $k) return ( this:complex( $rcbrt * math:cos(($φ + 2*$k*math:pi()) div 3), $rcbrt * math:sin(($φ + 2*$k*math:pi()) div 3) ) ) ) }; (:~ : sin() : Sine of complex number. : : @param $z: the complex number : @return sin(z) :) declare function this:sin( $z as xs:double* ) as xs:double* { (: : sin(x + iy) = sin(x)cosh(y) + i cos(x)sinh(y) :) this:complex( math:sin(this:pr($z))*util:cosh(this:pi($z)), math:cos(this:pr($z))*util:sinh(this:pi($z)) ) }; (:~ : cos() : Cosine of complex number. : : @param $z: the complex number : @return cos(z) :) declare function this:cos( $z as xs:double* ) as xs:double* { (: : cos(x + iy) = cos(x)cosh(y) - i sin(x)sinh(y) :) this:complex( math:cos(this:pr($z))*util:cosh(this:pi($z)), -math:sin(this:pr($z))*util:sinh(this:pi($z)) ) }; (:~ : sinh() : Hyperbolic sine. : : @param $z: the complex number : @return sinh(z) :) declare function this:sinh($z as xs:double*) as xs:double* { (: sinh(x + iy) = sinh(x)cos(y) + cosh(x)sin(y) :) this:complex( util:sinh(this:pr($z))*math:cos(this:pi($z)), util:cosh(this:pr($z))*math:sin(this:pi($z)) ) }; (:~ : cosh() : Hyperbolic cosine. : : @param $z: the complex number : @return cosh(z) :) declare function this:cosh($z as xs:double*) as xs:double* { (: cosh(x + iy) = cosh(x)cos(y) - sinh(x)sin(y) :) this:complex( util:cosh(this:pr($z))*math:cos(this:pi($z)), -util:sinh(this:pr($z))*math:sin(this:pi($z)) ) }; (:~ : asin() : arcsin(z): -i ln(iz + √(1 - z²)) : : @param $z: the complex number : @return asin(z) :) declare function this:asin( $z as xs:double* ) as xs:double* { this:log( this:multiply($this:i, $z)=>this:add( this:sqrt( $this:one=>this:sub( this:pow($z, 2) ) ) ) )=>this:multiply(this:minus($this:i)) }; (:~ : acos() : arccos(z): (1/i) ln(z + √(z² - 1)) : : @param $z: the complex number : @return acos(z) :) declare function this:acos( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:sub( $this:one ) ) ) )=>this:multiply( this:reciprocal($this:i) ) }; (:~ : asinh() : Inverse hyperbolic sine: asinh(z) = ln(z + √(z²+1)) :) declare function this:asinh( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:add( $this:one ) ) ) ) }; (:~ : acosh() : Inverse hyperbolic cosine: acosh(z) = ln(z + √(z²-1)) :) declare function this:acosh( $z as xs:double* ) as xs:double* { this:log( $z=>this:add( this:sqrt( this:pow($z, 2)=>this:sub( $this:one ) ) ) ) }; (:~ : exp() : Exponential of z: e^z : : @param $z: the complex number : @return e^z :) declare function this:exp( $z as xs:double* ) as xs:double* { ( math:exp(this:pr($z)) * math:cos(this:pi($z)), math:exp(this:pr($z)) * math:sin(this:pi($z)) ) }; (:~ : times() : Multiply a complex by a constant. : : @param $z: the complex number : @param $k: the constant to multiply by : @return k*z :) declare function this:times( $z as xs:double*, $k as xs:double ) as xs:double* { $z=>v:times($k) }; (:~ : plus() : Add a constant to a complex number. (i.e. add complex number ($k, 0)) : : @param $z: the complex number : @param $k: the constant to add : @return z+k :) declare function this:plus( $z as xs:double*, $k as xs:double ) as xs:double* { $z=>this:add(this:complex($k, 0)) }; (:~ : divide() : Divide two complex numbers. : : @param $z1: one complex number : @param $z2: other complex number : @return z1/z2 :) declare function this:divide( $z1 as xs:double*, $z2 as xs:double* ) as xs:double* { (: (a + bi)/(c + di) = ((ac + bd) + i(bc - ad))/(c² + d²) :) let $r2 := this:pr($z2)*this:pr($z2) + this:pi($z2)*this:pi($z2) return ( (this:pr($z1)*this:pr($z2) + this:pi($z1)*this:pi($z2)) div $r2, (this:pi($z1)*this:pr($z2) - this:pr($z1)*this:pi($z2)) div $r2 ) }; (:~ : divide-by-i() : Divide complex numbers by i. : : @param $z : @return z/i :) declare function this:divide-by-i( $z as xs:double* ) as xs:double* { (: (a + bi)/(c + di) = ((ac + bd) + i(bc - ad))/(c² + d²) :) (: (a + bi)/(0 + 1i) = ((0a + b1) + i(b0 - a1))/(0² + 1²) = b - ai :) ( this:pi($z), -this:pr($z) ) }; (:~ : modulus() : Modulus of a complex number. Given z = re^iφ, the r. : : @param $z: the complex numbers : @return modulus :) declare function this:modulus( $z as xs:double* ) as xs:double { math:sqrt(this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z)) }; (:~ : modsq() : Modulus of a complex number, squared. Given z = re^iφ, r². Used for cases : where we want to avoid a lot of square root calculations. : : @param $z: the complex number : @return modulus² :) declare function this:modsq( $z as xs:double* ) as xs:double { this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) }; (:~ : angle() : The angle of the complex number. Given z = re^iφ, the φ in degrees. : : @param $z: the complex numbers : @return phase angle, in degrees :) declare function this:angle( $z as xs:double* ) as xs:double { math:atan2(this:pi($z), this:pr($z))=>util:degrees()=>util:remap-degrees() }; (:~ : normalize() : Normalize the complex number so modulus is 1. : : @param $z: the complex number to normalize : @return complex number :) declare function this:normalize($z as xs:double*) as xs:double* { let $l := this:modulus($z) return this:complex(this:pr($z) div $l, this:pi($z) div $l) }; (:~ : is-gauss-prime() : Test whether complex number is gaussian prime; snaps to integral value. : : @param $z: complex number to test : @return true if z is Gaussian prime :) declare function this:is-gauss-prime($z as xs:double*) as xs:boolean { let $a := this:r($z) let $b := this:i($z) return ( if ($a * $b != 0) then ( util:is-prime($a*$a + $b*$b) ) else ( let $c := abs($a + $b) return util:is-prime($c) and $c mod 4 = 3 ) ) }; (:~ : conjugate() : Return the complex conjugate : : @param $z: complex number : @return conj(z) :) declare function this:conjugate($z as xs:double*) as xs:double* { this:complex(this:pr($z), -this:pi($z)) }; (:~ : reciprocal() : The reciprocal of z: 1 / z : : @param $z: complex number : @return 1/z :) declare function this:reciprocal($z as xs:double*) as xs:double* { let $r := this:pr($z)*this:pr($z) + this:pi($z)*this:pi($z) return this:complex(this:pr($z) div $r, -this:pi($z) div $r) }; (:~ : abs() : The absolute value of z : : @param $z: complex number : @return abs(z) :) declare function this:abs($z as xs:double*) as xs:double* { this:complex(abs(this:pr($z)), abs(this:pi($z))) }; (:~ : quote() : Return a string value of the complex numbers : : @param $zs: complex numbers : @return string :) declare function this:quote($zs as xs:double*) as xs:string { string-join( let $chunks := for $z at $i in $zs return ( if ($i mod 2 = 0) then ( array {$zs[$i - 1], $z} ) else () ) for $chunk in $chunks let $z := $chunk?* return ( let $r := this:pr($z) let $i := this:pi($z) return if ($r = 0 and $i = 0) then "0" else if ($r = 0) then $i||"i" else if ($i = 0) then string($r) else if ($i < 0) then $r||$i||"i" else $r||"+"||$i||"i" ) , " " ) }; (:~ : unquote() : Parse a string value of a complex number to produce that complex number. : Number is of the form 33+12i : : @param $zs: the string representation of the number : @return complex number :) declare function this:unquote($zs as xs:string) as xs:double* { (: Cases: : 2 : -2 : i : 3i : -3i : 2+3i : -2+3i : 2-3i : -2-3i : 2+ i : 2- i : -2+ i : -2- i :) let $z := number($zs) return if ($z = $z) then this:complex($z, 0) (: 2 | -2 :) else if ($zs = "i") then this:complex(0, 1) (: i :) else ( let $parts := analyze-string($zs, "[-+]?[0123456789.]+") return ( switch (count($parts/fn:match)) case 0 return if ($parts/fn:non-match=("i","+i")) then this:complex(0, 1) else if ($parts/fn:non-match="-i") then this:complex(0, -1) else errors:error("UTIL-BADCOMPLEX", $zs) case 1 return let $next := $parts/fn:match/following-sibling::fn:non-match[1] return if (empty($next)) then this:complex(number($parts/fn:match), 0) else if ($next="+i") then this:complex(number($parts/fn:match), 1) else if ($next="-i") then this:complex(number($parts/fn:match), -1) else this:complex(0, number($parts/fn:match)) case 2 return this:complex(number($parts/fn:match[1]), number($parts/fn:match[2])) default return errors:error("UTIL-BADCOMPLEX", $zs) ) ) }; (:~ : eq() : Is the complex number equal to the double value? That is, does it have : no imaginary part and a real part equal to the value? : : @param $z: one complex number : @param $val: a double value : @return real(z)=val and imaginary(z)=0 (within epsilon) :) declare function this:eq($z as xs:double*, $val as xs:double) as xs:boolean { this:pr($z)=$val and this:is-real($z) }; (:~ : same() : Are the two complex numbers the same? : : @param $z1: one complex number : @param $z2: other complex number : @return z1=z2 :) declare function this:same($z1 as xs:double*, $z2 as xs:double*) as xs:boolean { this:pr($z1)=this:pr($z2) and this:pi($z1)=this:pi($z2) }; (:~ : decimal() : Cast the values to a values with the given number of digits. : : @param $zs: the complex numbers : @param $digits: how many digits to preserve : @return complex numbers :) declare function this:decimal($zs as xs:double*, $digits as xs:integer) as xs:double* { v:decimal($zs, $digits) };