/******************************************************************************\
Complex numbers support
\******************************************************************************/
-- faster access to some math library functions
local abs = math.abs
local Round = math.Round
local sqrt = math.sqrt
local exp = math.exp
local log = math.log
local sin = math.sin
local cos = math.cos
local sinh = math.sinh
local cosh = math.cosh
local acos = math.acos
local atan2 = math.atan2
local function format(value)
local dbginfo
if abs(value[1]) < delta then
if abs(value[2]) < delta then
dbginfo = "0"
else
dbginfo = Round(value[2]*1000)/1000 .. "i"
end
else
if value[2] > delta then
dbginfo = Round(value[1]*1000)/1000 .. "+" .. Round(value[2]*1000)/1000 .. "i"
elseif abs(value[2]) <= delta then
dbginfo = Round(value[1]*1000)/1000
elseif value[2] < -delta then
dbginfo = Round(value[1]*1000)/1000 .. Round(value[2]*1000)/1000 .. "i"
end
end
return dbginfo
end
WireLib.registerDebuggerFormat("COMPLEX", format)
/******************************************************************************/
registerType("complex", "c", { 0, 0 },
function(self, input) return { input[1], input[2] } end,
nil,
function(retval)
if type(retval) ~= "table" then error("Return value is not a table, but a "..type(retval).."!",0) end
if #retval ~= 2 then error("Return value does not have exactly 2 entries!",0) end
end,
function(v)
return type(v) ~= "table" or #v ~= 2
end
)
/******************************************************************************/
local function cexp(x,y)
return {exp(x)*cos(y), exp(x)*sin(y)}
end
local function clog(x,y)
local r,i,l
l = x*x+y*y
if l < delta then return {-1e+100, 0} end
r = log(sqrt(l))
local c,s
c = x/sqrt(l)
i = acos(c)
if y<0 then i = -i end
return {r, i}
end
local function cdiv(a,b)
local l=b[1]*b[1]+b[2]*b[2]
return {(a[1]*b[1]+a[2]*b[2])/l, (a[2]*b[1]-a[1]*b[2])/l}
end
/******************************************************************************/
e2function complex operator=(complex lhs, complex rhs)
self.vars[lhs] = rhs
self.vclk[lhs] = true
return rhs
end
e2function number operator_is(complex z)
if (z[1]==0) && (z[2]==0) then return 0 else return 1 end
end
e2function number operator==(complex lhs, complex rhs)
if abs(lhs[1]-rhs[1])<=delta &&
abs(lhs[2]-rhs[2])<=delta then
return 1
else return 0 end
end
e2function number operator==(complex lhs, number rhs)
if abs(lhs[1]-rhs)<=delta &&
abs(lhs[2])<=delta then
return 1
else return 0 end
end
e2function number operator==(number lhs, complex rhs)
if abs(lhs-rhs[1])<=delta &&
abs(rhs[2])<=delta then
return 1
else return 0 end
end
e2function number operator!=(complex lhs, complex rhs)
if abs(lhs[1]-rhs[1])>delta ||
abs(lhs[2]-rhs[2])>delta then
return 1
else return 0 end
end
e2function number operator!=(complex lhs, number rhs)
if abs(lhs[1]-rhs)>delta ||
abs(lhs[2])>delta then
return 1
else return 0 end
end
e2function number operator!=(number lhs, complex rhs)
if abs(lhs-rhs[1])>delta ||
abs(rhs[2])>delta then
return 1
else return 0 end
end
/******************************************************************************/
e2function complex operator_neg(complex z)
return {-z[1], -z[2]}
end
e2function complex operator+(complex lhs, complex rhs)
return {lhs[1]+rhs[1], lhs[2]+rhs[2]}
end
e2function complex operator+(number lhs, complex rhs)
return {lhs+rhs[1], rhs[2]}
end
e2function complex operator+(complex lhs, number rhs)
return {lhs[1]+rhs, lhs[2]}
end
e2function complex operator-(complex lhs, complex rhs)
return {lhs[1]-rhs[1], lhs[2]-rhs[2]}
end
e2function complex operator-(number lhs, complex rhs)
return {lhs-rhs[1], -rhs[2]}
end
e2function complex operator-(complex lhs, number rhs)
return {lhs[1]-rhs, lhs[2]}
end
e2function complex operator*(complex lhs, complex rhs)
return {lhs[1]*rhs[1]-lhs[2]*rhs[2], lhs[2]*rhs[1]+lhs[1]*rhs[2]}
end
e2function complex operator*(number lhs, complex rhs)
return {lhs*rhs[1], lhs*rhs[2]}
end
e2function complex operator*(complex lhs, number rhs)
return {lhs[1]*rhs, lhs[2]*rhs}
end
e2function complex operator/(complex lhs, complex rhs)
local z = rhs[1]*rhs[1] + rhs[2]*rhs[2]
return {(lhs[1]*rhs[1]+lhs[2]*rhs[2])/z, (lhs[2]*rhs[1]-lhs[1]*rhs[2])/z}
end
e2function complex operator/(number lhs, complex rhs)
local z = rhs[1]*rhs[1] + rhs[2]*rhs[2]
return {lhs*rhs[1]/z, -lhs*rhs[2]/z}
end
e2function complex operator/(complex lhs, number rhs)
return {lhs[1]/rhs, lhs[2]/rhs}
end
e2function complex operator^(complex lhs, complex rhs)
local l = clog(lhs[1], lhs[2])
local e = {rhs[1]*l[1] - rhs[2]*l[2], rhs[1]*l[2] + rhs[2]*l[1]}
return cexp(e[1], e[2])
end
e2function complex operator^(complex lhs, number rhs)
local l = clog(lhs[1], lhs[2])
return cexp(rhs*l[1], rhs*l[2])
end
/******************************** constructors ********************************/
--- Returns complex zero
e2function complex comp()
return {0, 0}
end
--- Converts a real number to complex (returns complex number with real part and imaginary part 0)
e2function complex comp(a)
return {a, 0}
end
--- Returns +*i
e2function complex comp(a, b)
return {a, b}
end
--- Returns the imaginary unit i
e2function complex i()
return {0, 1}
end
--- Returns *i
e2function complex i(b)
return {0, b}
end
/****************************** helper functions ******************************/
--- Returns the absolute value of
e2function number abs(complex z)
return sqrt(z[1]*z[1] + z[2]*z[2])
end
--- Returns the argument of
e2function number arg(complex z)
local l = z[1]*z[1]+z[2]*z[2]
if l==0 then return 0 end
local c = z[1]/sqrt(l)
local p = acos(c)
if z[2]<0 then p = -p end
return p
end
--- Returns the conjugate of
e2function complex conj(complex z)
return {z[1], -z[2]}
end
--- Returns the real part of
e2function number real(complex z)
return z[1]
end
--- Returns the imaginary part of
e2function number imag(complex z)
return z[2]
end
/***************************** exp and logarithms *****************************/
--- Raises Euler's constant e to the power of
e2function complex exp(complex z)
return cexp(z[1], z[2])
end
--- Calculates the natural logarithm of
e2function complex log(complex z)
return clog(z[1], z[2])
end
--- Calculates the logarithm of to a complex base
e2function complex log(complex base, complex z)
return cdiv(clog(z),clog(base))
end
--- Calculates the logarithm of to a real base
e2function complex log(number base, complex z)
local l=clog(z)
return {l[1]/log(base), l[2]/log(base)}
end
--- Calculates the logarithm of to base 2
e2function complex log2(complex z)
local l=clog(z)
return {l[1]/log(2), l[2]/log(2)}
end
--- Calculates the logarithm of to base 10
e2function complex log10(complex z)
local l=clog(z)
return {l[1]/log(10), l[2]/log(10)}
end
/******************************************************************************/
--- Calculates the square root of
e2function complex sqrt(complex z)
local l = clog(z[1], z[2])
return cexp(0.5*l[1], 0.5*l[2])
end
--- Calculates the complex square root of the real number
e2function complex csqrt(n)
if n<0 then
return {0, sqrt(-n)}
else
return {sqrt(n), 0}
end
end
/******************* trigonometric and hyperbolic functions *******************/
--- Calculates the sine of
e2function complex sin(complex z)
return {sin(z[1])*cosh(z[2]), sinh(z[2])*cos(z[1])}
end
--- Calculates the cosine of
e2function complex cos(complex z)
return {cos(z[1])*cosh(z[2]), -sin(z[1])*sinh(z[2])}
end
--- Calculates the hyperbolic sine of
e2function complex sinh(complex z)
return {sinh(z[1])*cos(z[2]), sin(z[2])*cosh(z[1])}
end
--- Calculates the hyperbolic cosine of
e2function complex cosh(complex z)
return {cosh(z[1])*cos(z[2]), sinh(z[1])*sin(z[2])}
end
--- Calculates the tangent of
e2function complex tan(complex z)
local s,c
s = {sin(z[1])*cosh(z[2]), sinh(z[2])*cos(z[1])}
c = {cos(z[1])*cosh(z[2]), -sin(z[1])*sinh(z[2])}
return cdiv(s,c)
end
--- Calculates the cotangent of
e2function complex cot(complex z)
local s,c
s = {sin(z[1])*cosh(z[2]), sinh(z[2])*cos(z[1])}
c = {cos(z[1])*cosh(z[2]), -sin(z[1])*sinh(z[2])}
return cdiv(c,s)
end
--- Calculates the inverse sine of
e2function complex asin(complex z)
local log1mz2 = clog(1-z[1]*z[1]+z[2]*z[2], 2*z[1]*z[2])
local rt = cexp(log1mz2[1]*0.5,log1mz2[2]*0.5)
local flog = clog(rt[1]-z[2], z[1]+rt[2])
return {flog[2], -flog[1]}
end
--- Calculates the inverse cosine of
e2function complex acos(complex z)
local logz2m1 = clog(z[1]*z[1]-z[2]*z[2]-1, 2*z[1]*z[2])
local rt = cexp(logz2m1[1]*0.5,logz2m1[2]*0.5)
local flog = clog(z[1]+rt[1], z[2]+rt[2])
return {flog[2], -flog[1]}
end
--- Calculates the inverse tangent of
e2function complex atan(complex z)
local frac = cdiv({-z[1],1-z[2]},{z[1],1+z[2]})
local logfrac = clog(frac[1], frac[2])
local rt = cexp(logfrac[1]*0.5,logfrac[2]*0.5)
local flog = clog(rt[1], rt[2])
return {flog[2], -flog[1]}
end
-- ******************** hyperbolic functions *********************** --
--- Calculates the hyperbolic tangent of
e2function complex tanh(complex z)
local s,c
s = {sinh(z[1])*cos(z[2]), sin(z[2])*cosh(z[1])}
c = {cosh(z[1])*cos(z[2]), sinh(z[1])*sin(z[2])}
return cdiv(s,c)
end
--- Calculates the hyperbolic cotangent of
e2function complex coth(complex z)
local s,c
s = {sinh(z[1])*cos(z[2]), sin(z[2])*cosh(z[1])}
c = {cosh(z[1])*cos(z[2]), sinh(z[1])*sin(z[2])}
return cdiv(c,s)
end
--- Calculates the secant of
e2function complex sec(complex z)
local c
c = {cos(z[1])*cosh(z[2]), -sin(z[1])*sinh(z[2])}
return cdiv({1,0},c)
end
--- Calculates the cosecant of
e2function complex csc(complex z)
local s
s = {sin(z[1])*cosh(z[2]), sinh(z[2])*cos(z[1])}
return cdiv({1,0},s)
end
--- Calculates the hyperbolic secant of
e2function complex sech(complex z)
local c
c = {cosh(z[1])*cos(z[2]), sinh(z[1])*sin(z[2])}
return cdiv({1,0},c)
end
--- Calculates the hyperbolic cosecant of
e2function complex csch(complex z)
local s
s = {sinh(z[1])*cos(z[2]), sin(z[2])*cosh(z[1])}
return cdiv({1,0},s)
end
/******************************************************************************/
--- Formats as a string.
e2function string toString(complex z)
return format(z)
end
e2function string complex:toString()
return format(this)
end