MathComplexNumbers
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
//@description A set of utility functions to handle complex numbers without arrays.
library("MathComplex")

//@function Complex type. 
export type complex
    float re
    float im 

//@function Convert a complex number into a tuple
//@param complex_number is a complex type
//@returns float tuple
export complex_tuple(complex complex_number)=>
    [complex_number.re, complex_number.im]

//@function Convert a complex number into a tuple
//@param complex_number is a complex type
//@returns float tuple
export ct(complex complex_number)=>
    [complex_number.re, complex_number.im]

//@function Get the real part of the complex number
//@peram complex_number is a complex type
//@returns float
export get_real(complex complex_number)=>
    complex_number.re

//@function Get the imaginary part of the complex number
//@peram complex_number is a complex type
//@returns float
export get_imaginary(complex complex_number)=>
    complex_number.im

//@function Get the real part of the complex number
//@peram complex_number is a complex type
//@returns float
export re(complex complex_number)=>
    get_real(complex_number)

//@function Get the imaginary part of the complex number
//@peram complex_number is a complex type
//@returns float
export im(complex complex_number)=>
    get_imaginary(complex_number)

//@function Adds complex number A to B, in the form:
//         [a.re + b.re, a.im + b.im]
//@peram Complex number A
//@peram Complex number B
//@returns complex
export add(complex a, complex b)=>
    complex.new(a.re + b.re, a.im + b.im)

//@function Subtract B from A, in the form: 
//        [a.re - b.re, a.im - b.im]
//@param Complex number A
//@param Complex number B
//@returns complex
export subtract(complex a, complex b)=>
    complex.new(a.re - b.re, a.im - b.im)

//@function Computes the conjugate of complex_number by reversing the sign of the imaginary part.
//@param Complex number
//@returns complex
export conjugate(complex complex_number)=>
    complex.new(complex_number.re, -1 * complex_number.im)

//@function Multiply A with B, in the form: 
//        [(a.re * b.re) - (a.im * b.im), (a.re * b.im) + (a.im * b.re)]
//@param Complex number A
//@param Complex number B
//@returns complex
export multiply(complex a, complex b)=>
    complex.new(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)

//@function Divide A with B, in the form: 
//        [(a.re * b.re) - (a.im * b.im), (a.re * b.im) + (a.im * b.re)]
//@param Complex number A
//@param Complex number B
//@returns complex
export divide(complex a, complex b)=>
    divident = multiply(a, conjugate(b))
    divider  = math.pow(b.re, 2) + math.pow(b.im, 2)
    complex.new(divident.re / divider, divident.im / divider)

//@function Computes the reciprocal or inverse of complex_number.
//@param Complex number
//@returns complex
export reciprocal(complex complex_number)=>
    if complex_number.re == 0 and complex_number.im == 0
        complex.new(0, 0)
    else
        divide(complex.new(1, 0), complex_number)

//@function Inverse of complex_number, in the form: [1/complex_number.re, 1/complex_number.im]
//@param Complex number
//@returns complex
export inverse(complex complex_number)=>
    if complex_number.re != 0 and complex_number.im != 0
        float d = complex_number.re * complex_number.re + complex_number.im * complex_number.im
        complex.new(complex_number.re / d, (0 - complex_number.im) / d)
    else
        complex.new(0, 0)

//@function Negative of complex_number, in the form: [-complex_number.re, -complex_number.im]
//@param complex_number float array, pseudo complex number in the form of a array [real, imaginary].
//@returns complex
export negative(complex complex_number)=>
    complex.new(-complex_number.re, -complex_number.im)

//@function Exponential of complex_number.
//@param Complex number
//@returns complex
export exponential(complex complex_number)=>
    er = math.exp(complex_number.re)
    complex.new(er * math.cos(complex_number.im), er * math.sin(complex_number.im))

//@function Ceils complex_number. 
//@param Complex number
//@param digits int, digits to use as ceiling.
//@returns complex
export ceil(complex complex_number, int digits)=>
    places = math.pow(10, digits)
    complex.new(math.ceil(complex_number.re * places) / places, math.ceil(complex_number.im * places) / places)

//@function Radius(magnitude) of complex_number, in the form: [sqrt(pow(complex_number))]
//    This is defined as its distance from the origin (0,0) of the complex plane.
//@param Complex number
//@returns float
export radius(complex complex_number)=>
    math.sqrt(math.pow(complex_number.re, 2) + math.pow(complex_number.im, 2))

// EXAMPLE USE
test = complex.new(50, 2)
real_t = test.re
real_i = test.im
test_array = array.new<complex>(1, complex.new(50, 2))

[real, imaginary] = complex_tuple(array.get(test_array, 0))

plot(real)
plot(imaginary)