Last active
July 7, 2018 19:00
-
-
Save dekrain/a276741c41bfca44ff3f4dc5a209b4a6 to your computer and use it in GitHub Desktop.
Python algorithm to find roots of complex function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Python 3 | |
# This algorithm tries to find a complex solution to the complex function | |
# Example: | |
# find_root((lambda n: n**2 + 1), ComplexRect(-2+2j, 2-2j)) | |
# -> [-1j, 1j] | |
import math | |
def complex2polar(n): | |
radius = math.sqrt(n.real**2 + n.imag**2) | |
angle = math.atan2(n.imag, n.real) | |
return (radius, angle%(2*math.pi)) | |
class ComplexRect: | |
def __init__(self, c1, c2): | |
self.corner1 = c1 | |
self.corner2 = c2 | |
def __repr__(self): | |
return 'ComplexRect(%r, %r)' % (self.corner1, self.corner2) | |
class ComplexLine: | |
def __init__(self, org, off, d): | |
self.origin = org | |
self.offset = off | |
self.direction = d | |
def getOrgCord(self): | |
if self.direction == 'R': | |
return self.origin.real | |
return self.origin.imag | |
def getOtherCord(self): | |
if self.direction == 'R': | |
return self.origin.imag*1j | |
return self.origin.real | |
def getOrgUnit(self): | |
if self.direction == 'R': | |
return 1 | |
return 1j | |
def getOtherUnit(self): | |
if self.direction == 'R': | |
return 1j | |
return 1 | |
def __repr__(self): | |
return 'ComplexLine(%r, %f, %c)' % (self.origin, self.offset, | |
self.direction) | |
def _find_roots_line(func, line, pitch): | |
roots = [] | |
for n in range(int(line.getOrgCord()), int(line.getOrgCord()+line.offset)): | |
num = line.getOtherCord()+n*line.getOrgUnit() | |
if func(num) == 0: | |
roots.append(num) | |
return roots | |
def _find_hue_diff(func, line): | |
org = func(line.origin) | |
off = func(line.origin + line.offset*line.getOtherUnit()) | |
return (complex2polar(off)[1] - complex2polar(org)[1])/(2*math.pi) | |
# returns: | |
# - complex number(s) which are solutions to the function | |
# - rect(s) which contain possible roots to the function (if depth is 0) | |
# args: | |
# func - a function that a solution is searching for (callable taking one | |
# complex number and returning complex number) | |
# rect - a given range to search (ComplexRect interface instance) | |
# depth - how many iterations this algorithm will search for (positive integer) | |
# pitch - how big spaces bitween numbers (positive float) | |
def find_root(func, rect, depth=10, pitch=0.1): | |
if depth == 0: | |
return [rect] | |
lines = [ComplexLine(rect.corner1, rect.corner2.real-rect.corner1.real, 'R'), | |
ComplexLine(rect.corner1, rect.corner2.imag-rect.corner1.imag, 'I'), | |
ComplexLine(rect.corner2, rect.corner1.imag-rect.corner2.imag, 'I'), | |
ComplexLine(rect.corner2, rect.corner1.real-rect.corner2.real, 'R')] | |
for line in lines: | |
r = _find_roots_line(func, line, pitch) | |
if len(r) > 0: | |
return r | |
hues = [_find_hue_diff(func, line) for line in lines] | |
hue = round(math.fsum(hues)) | |
if hue == 0: | |
return [] | |
split = [ComplexRect(rect.corner1, | |
(rect.corner2.real+rect.corner1.real)/2 + rect.corner2.imag*1j), | |
ComplexRect((rect.corner2.real+rect.corner1.real)/2 | |
+ rect.corner1.imag*1j, rect.corner2)] | |
return (find_root(func, split[0], depth-1, pitch) | |
+ find_root(func, split[1], depth-1, pitch)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment