I asked ChatGTP to add the docstrings (which I edited, but I have no clue what this code does)
Fixed the tabulation error.
I suggest to use math.complex instead of the real and imaginary parts
I added some "TODO:" labels
Fixed the tabulation error.
I suggest to use math.complex instead of the real and imaginary parts
I added some "TODO:" labels
Code:
# This code uses Shanghai46 method for calculation of tetration as described in
# TODO: fix link
# https://tetrationforum.org/search.php?action=results&sid=afae76cdf0119ae9ab1587cdd6166152&sortby=dateline&order=desc&uid=0
#
#Call tree
# tetra
# ├── fn <-- n is integer
# ├── tetraa <-- e^-e < X < e^(1/e)
# │ ├── entier
# │ ├── decimal
# │ ├── Nu
# │ ├── fn
# │ ├── TAU
# │ ├── LPr
# │ ├── LPi
# │ └── logan
# └── fin <-- e^(1/e) < X
# ├── decimal
# ├── entier
# ├── logwan
# ├── lim
# ├── NA
# ├── BIGx
# ├── gamma
# ├── Gn
# ├── BIGn
# ├── logan
# ├── PUr
# └── PUi
from math import *
import numpy as np
def mod(a, b):
# TODO this function is unnecessary, because is equivalent to abs(math.complex(a,b))
"""Calculates the modulus of a and b.
Args:
a: A number.
b: A number.
Returns:
The modulus of a and b.
"""
# A = (a**2 + b**2) ** 0.5
# return A
return abs(complex(a, b))
def Arg(a, b):
# TODO this function is unnecessary, because is equivalent to np.angle(math.complex(a,b))
"""Calculates the argument of a and b.
Args:
a: A number.
b: A number.
Returns:
The argument of a and b.
"""
# Z = atan2(b, a)
# return Z
return np.angle(complex(a, b))
def p(x):
"""returns x when x is positive,
or the fractional part of x, when x is negative
Args:
x: A number.
Returns:
If x is positive, the function returns x.
If x is negative, the function returns the fractional part of x.
"""
# a = x
# while a < 0:
# a = a + 1
# return a
return x if x >= 0 else x % 1
def fn(a, n):
"""Calculates the tetration of a to the power of n.
Args:
a: A number.
n: A number.
Returns:
The repeated power of a, n times
"""
# X = 0
# while n + 1 > 0:
# n = n - 1
# X = a**X
# return X
result = 1
for i in range(n):
result = a**result
return result
def logan(X, Y, a, n):
"""Calculates the n-iterated logarithm of X in base a.
Args:
X: A number.
Y: A number.
a: A number.
n: A number.
Returns:
a tuple of real numbers:
The real, and the imaginary part of:
The n-iterated logarithm of X in base a.
"""
result = complex(X, Y)
for i in range(n):
result = log(result, a)
return result.real, result.imag
def TAU(X):
"""Calculates the TAU function of X.
Args:
X: A number.
Returns:
The TAU function of X.
"""
# TODO: Is this a limit for long tetrations?
# It will rapidly overflow
# maybe is better to check the radius of convergence and calcualte the limit using the known functions.
# n = 0
# a = 1
# while n < 400:
# a = X**a
# n += 1
# return a
a = 1
for i in range(400):
a = X**a
return a
def LAMBDA(X):
"""Calculates the LAMBDA function of X.
Args:
X: A number.
Returns:
The LAMBDA function of X.
"""
# a = log(X, e) * TAU(X)
a = log(X) * TAU(X)
return a
def lpr(x, p, b):
# TODO: No clue if this calculates a real part
# Should use complex numbers right away?
"""Calculates the real part of the lp function of x, p, and b.
Args:
x: A number.
p: A number.
b: A number.
Returns:
The real part of the lp function of x, p, and b.
"""
X = LAMBDA(x)
if X >= 0:
A = (X**p) * cos(log(X) * b)
else:
A = exp(log(-X, e) * p - pi * b) * cos(log(-X) * b + p * pi)
return A
def lpi(x, p, b):
# TODO: No clue if this calculates a maginary part
# Should use complex numbers right away?
"""Calculates the imaginary part of the L function of x, p, and b.
Args:
x: A number.
p: A number.
b: A number.
Returns:
The imaginary part of the L function of x, p, and b.
"""
X = LAMBDA(x)
if X >= 0:
A = (X**p) * sin(log(X, e) * b)
else:
A = e ** (log(-X, e) * p - pi * b) * sin(log(-X, e) * b + p * pi)
return A
def entier(X):
# TODO:redundant function, which renames floor()
# Is better to rename the function to "floor" and delete it.
"""Calculates the integer part of X.
Args:
X: A number.
Returns:
The integer part of X.
"""
return floor(X)
def decimal(X):
# TODO: check if is required for readability.
# Otherwise rename decimal(X) to "x % 1"
"""Calculates the decimal part of X."""
# a = entier(X)
# b = X - a
# return b
return X % 1
def Nu(X):
"""Calculates the number of iterations needed to calculate the b**iterations = X.
Args:
X: A number.
Returns:
An integer.
The number of iterations.
"""
n = 0
a = fn(X, n)
b = TAU(X)
error_squared = (
0.0001**2
) # To avoid redundant calculations and improve readability
while ((a - b) ** 2) > error_squared:
n = n + 1
a = fn(X, n)
return n
def tetraa(X, a, b):
"""Calculates the iterated logarithm of [TODO:SOMETHING] in base X, Nu(X) times.
Args:
X: A number.
a: A number.
b: A number.
Returns:
A tuple of real numbers
"""
E = entier(a)
D = decimal(a)
N = Nu(X)
A = fn(X, N + E) - TAU(X)
B = (A * (lpr(X, D, b))) + TAU(X)
C = A * (lpi(X, D, b))
O = logan(B, C, X, N)
return O
def BIGn(X):
"""Calculates the BIGn function of X.
Which is a number of iterations
TODO:
WARNING: SIDE EFFECT:
THE VALUE OF X IS MODIFIED
Args:
X: A number.
Returns:
an integer
"""
n = X
a = 1
if 3.9 < X < 5:
X = X**X
a = 2
else:
# TODO: if X is complex, X < 3000 will fail
while X < 3000:
X = n**X
a = a + 1
return a
def BIGx(X):
"""Calculates the BIGx function of X. TODO: ?
Args:
X: A number.
Returns:
The BIGx function of X.
"""
n = X
if 3.9 < X < 5:
X = X**X
else:
while X < 3000:
X = n**X
return X
def logwan(X, a, n):
"""Calculates the n-iterated-logarithm of X in base a.
Args:
X: A number.
a: A number.
n: A number.
Returns:
A number.
"""
# while n > 0:
# X = log(X + 1, a)
# n = n - 1
# return X
for i in range(n):
X = log(X + 1, a)
return X
def PUr(X, a, b, n):
"""Calculates the [real part?] of the PU [?] function of X, a, b, and n.
TODO:
WARNING: SIDE EFFECTS
a, b and n are modified
Args:
X: A number.
a: A number.
b: A number.
n: A number.
Returns:
A number
"""
while n > 0:
A = (X**a) * cos(log(X, e) * b)
B = (X**a) * sin(log(X, e) * b)
a = A
b = B
n = n - 1
return a
def PUi(X, a, b, n):
"""Calculates the [imaginary part?] of the PU function of X, a, b, and n.
Args:
X: A number.
a: A number.
b: A number.
n: A number.
Returns:
A number
"""
while n > 0:
A = (X**a) * cos(log(X, e) * b)
B = (X**a) * sin(log(X, e) * b)
a = A
b = B
n = n - 1
return b
def Gn(a, b, X, n):
"""Calculates the [real and imaginary parts?] of the G function of a, b, X, and n.
Args:
a: A number.
b: A number.
X: A number.
n: A number.
Returns:
a tuple of numbers
"""
while n > 0:
A = (X**a) * cos(log(X, e) * b) - 1
B = (X**a) * sin(log(X, e) * b)
a = A
b = B
n = n - 1
return a, b
def lim(X):
"""Calculates the limit of the tetrahedral function of X.
Args:
X: A number.
Returns:
The limit of the tetrahedral function of X.
"""
A = BIGx(X)
# if X < e:
# b = logwan(A, X, 400)
# else:
# b = 0
# return b
return logwan(A, X, 400) if X < e else 0
def gamma(X):
#TODO: if this is the standard gammma function, it is available in scipy.special.gammma()
#Otherwise is an unfortunate name choice
"""Calculates the [gamma function?] of X.
Args:
X: A number.
Returns:
The gama function of X.
"""
#A = (lim(X) + 1) * log(X, e)
A = (lim(X) + 1) * log(X) #Log() is base e when the base is non specified
return A
def NA(X):
"""Calculates a number of iterations .
Args:
X: A number.
Returns:
an integer
"""
A = BIGx(X)
B = lim(X)
n = 0
error_squared = (10 ** -6)**2
while ((A - B) ** 2) > error_squared:
n = n + 1
A = logwan(A, X, 1)
return n
def fin(X, p, b):
"""Calculates the [fin?] function of X, p, and b, where X is greater than e**(1/e).
Args:
X: A number.
p: A number.
b: A number.
Returns:
A tuple of numbers
"""
E = decimal(1 - decimal(p))
Z = entier(p)
A = BIGx(X)
B = logwan(A, X, NA(X))
C = B - lim(X)
D = (C / (gamma(X) ** E) * cos(log(gamma(X), e) * b)) + lim(X)
W = C / (gamma(X) ** E) * sin(log(gamma(X), e) * b)
F, U = Gn(D, W, X, NA(X))
Y = BIGn(X) - E - p
if Y >= 0:
O = logan(F, U, X, Y)
else:
O = PUr(F, U, X, -Y), PUi(F, U, X, -Y)
return O
def tetra(X, n, b):
"""Calculates [the tetration?] of X to n, and b.
Args:
X: A number.
n: A number.
b: A number.
Returns:
#TODO returns different types? Better would be to use math.complex() and always return complex
A number when n >= -1 and decimal(n) <= 0 and b == 0:
A tuple of numbers otherwise
"""
if n < -2 and p(n) <= 0:
# Z = "ERROR"
raise ValueError("n must be greater than -2 and p(n) must be greater than 0.")
#TODO: decimal() cannot return a value decimal(n) <= 0, so the check is redundant or there is some problem.
elif n >= -1 and decimal(n) <= 0 and b == 0:
Z = fn(X, n)
else:
if e ** (-e) <= X <= e ** (1 / e):
Z = tetraa(X, n, b)
elif X > e ** (1 / e):
Z = fin(X, n, b)
else:
# Z = "ERROR"
raise ValueError("X must satisfy e^-e <= X )
return Z