# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Complex Numbers

import cmath
from pydash import py_ as _

# # Identity
#
# A complex number is the combination of a real number, and an imaginary number.
#
# The imaginary number is

cmath.sqrt(-1)

type(cmath.sqrt(-1))

A = complex(1.0, 2.0); 
B = complex(3.0, 4.0); 
C = complex(-5.0, -6.0);
[A, B, C]

# ## Polar Coordinates

{
    "A": [A, cmath.polar(A), [abs(A), cmath.phase(A)]],
    "B": [B, cmath.polar(B), [abs(B), cmath.phase(B)]],
    "C": [C, cmath.polar(C), [abs(C), cmath.phase(C)]],
}

# ## Powers

# The imaginary number multiplied by itself is -1

cmath.sqrt(-1) * cmath.sqrt(-1)

# Higher powers form the points of a complex circle

[ "i^%d == %s" % (x, cmath.sqrt(-1)**x) for x in range(1,9) ]

# ## Addition

# Add the real and imaginary parts

A + B

(A.real + A.imag*1j) + (B.real + B.imag*1j)

A + B == (A.real + A.imag*1j) + (B.real + B.imag*1j)

# ## Subtraction

# Subtract the real and imaginary parts

A - B

(A.real + A.imag*1j) - (B.real + B.imag*1j)

A - B == (A.real + A.imag*1j) - (B.real + B.imag*1j) == A.real - B.real + A.imag*1j - B.imag*1j

A - (B - C) == (A - B) + C

# ## Multiplication

# #### Cartisian Multiplication

# (A<sub>1</sub> + A<sub>2</sub>i) x (B<sub>1</sub> + B<sub>2</sub>i) = (A<sub>1</sub> B<sub>2</sub> - A<sub>1</sub> B<sub>2</sub>) + (A<sub>2</sub> B<sub>1</sub>+ B<sub>1</sub> A<sub>2</sub>)i

A * B

((A.real * B.real) - (A.imag * B.imag)) + ((A.real * B.imag) + (A.imag * B.real))*1j

A * B == ((A.real * B.real) - (A.imag * B.imag)) + ((A.real * B.imag) + (A.imag * B.real))*1j

A * B == B * A

A * (B * C) == (A * B) * C

# #### Polar Multiplication
#
# A * B = (|A|\*|B|)r + (Aφ * Bφ)φ

A * B, cmath.polar(A*B)

cmath.polar(A*B) == (abs(A)*abs(B), cmath.phase(A)+cmath.phase(B))

# ## Division

# #### Cartisian Multiplication

A / B

( ((A.real * B.real) + (A.imag * B.imag)) - ((A.real * B.imag) - (B.real * A.imag))*1j ) / ( B.real**2 + B.imag**2 )

(A / B) == (( ((A.real * B.real) + (A.imag * B.imag)) - ((A.real * B.imag) - (A.imag * B.real))*1j ) / ( B.real**2 + B.imag**2 ))

# #### Polar Division
#
# A / B = (|A|/|B|)r + (Aφ - Bφ)φ
#
# NOTE: small floating point rounding error

A / B, cmath.polar(A/B)

cmath.polar(A/B), \
(abs(A)/abs(B), cmath.phase(A)-cmath.phase(B))

complex(cmath.rect(*cmath.polar(A/B))) - \
complex(cmath.rect(*(abs(A)/abs(B), cmath.phase(A)-cmath.phase(B))))


def round_complex(number, digits):
    if isinstance(number, complex):
        return complex(round(number.real, digits), round(number.imag, digits))
    if isinstance(number, tuple):
        return tuple( round(n, digits) for n in number )
    return complex(round(number, digits))


round_complex(cmath.polar(A/B), 10), round_complex((abs(A)/abs(B), cmath.phase(A)-cmath.phase(B)), 10)

round_complex(cmath.polar(A/B), 10) == round_complex((abs(A)/abs(B), cmath.phase(A)-cmath.phase(B)), 10)

# ## Conjugate 
#
# [Complex_conjugate](https://en.wikipedia.org/wiki/Complex_conjugate)
#
# In mathematics, the complex conjugate of a complex number is the number with an equal real part and an imaginary part equal in magnitude but opposite in sign.

import numpy
[C, numpy.conj(C)]

import math
math.sqrt(C.real**2 + C.imag**2)

# ## Modulus
#
# Modulus of complex number, in mathematics, the norm or absolute value, of a complex number, denoted: 
#
# |c|<sup>2</sup> = |x + yi|<sup>2</sup> = x<sup>2</sup> + y<sup>2</sup> 

cmath.sqrt(C.real**2 + C.imag**2)

# The modulus is also defined as the sqrt of the complex number multiplied by its conjugate

cmath.sqrt(C * numpy.conj(C))

numpy.absolute(C)

# |AB| = |A||B|

numpy.absolute(A) * numpy.absolute(B) == numpy.absolute(A * B)

# |A + B| <= |A| + |B|

numpy.absolute(A + B) <= numpy.absolute(A) + numpy.absolute(B)

[ numpy.absolute(A + B), numpy.absolute(A) + numpy.absolute(B), [numpy.absolute(A), numpy.absolute(B)]]

# ## Properties of Complex Numbers

# ### [Associative](https://en.wikipedia.org/wiki/Associative_property)
#
# Within an expression containing two or more occurrences in a row of the same associative operator, the order in which the operations are performed does not matter as long as the sequence of the operands is not changed. That is, rearranging the parentheses in such an expression will not change its value. 

A + (B + C) == (A + B) + C

A * (B * C) == (A * B) * C

# Subraction AND Division are NOT associative

A - (B - C) == (A - B) - (-C)

A / (B / C) == (A / B) / C

# ### [Commutative](https://en.wikipedia.org/wiki/Commutative_property)
#
# In mathematics, a binary operation is '''commutative''' if changing the order of the operands does not change the result. 

A + B == B + A

A * B == B * A

# Subraction AND Division are NOT Commutative

A - B == B - A

A / B == B / A

# ### [Distributive](https://en.wikipedia.org/wiki/Distributive_property)
#
# The Distributive Law says that multiplying a number by a group of numbers added together is the same as doing each multiplication separately.
#
# There is a distinction between left-distributivity and right-distributivity:
# - A x (B + C) = (A x B) + (A x C) = left-distributive
# - (A x B) + C = (A x C) + (B x C) = right-distributive

A * (B + C) == (A * B) + (A * C)

(A + B) * C == (A * C) + (B * C)

StarcoderdataJupyterScriptsDedupFiltered