Calling a previous function in a new function - python

I'm doing the CS1301xII course through edX and I'm being asked to calculate Pokemon damage by using one function to calculate the modifier, which I need to call another for the calculation.
There are 9 parameters:
STAB, Type, Critical, Other, Random, Level, Attack, Defense, and Base.
My first function calculates a modifier used in the damage calculation. This is (STAB * Type * Critical * Other * Random) for reference.
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
My second function is to calculate overall damage. This is (((2 * Level + 10) / 250) * (Attack / Defense) * Base + 2) for reference.
def calculate_damage(l, a, d, b):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2)
How do I go about calling the calculate_modifier function within my calculate_damage function? Do I list all 9 of the parameters? Really struggling with how this should look.
The final calculate_damage formula should be dam * mod

I am on this course too, but I've done this question. This is what you should do:
dam = (((2 * l + 10) / 250) * (a / d) * b + 2) * calculate_modifier(STAB * Type * Critical * Other * Random)
If you try to calculate it inside the dam function, the autograder disqualifies you.

You just return the mod value from the first function and pass it to second,
You don't have to pass 9 parameters to second function.
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
return mod
def calculate_damage(l, a, d, b, mod):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2) * mod
return dam
mod = calculate_modifier(s, t, c, o, r)
dam = calculate_damage(l, a, d, b, mod)
or you can return from both function and pass them to the third function to calculate the final value
def calculate_modifier(s, t, c, o, r):
mod = s * t * c * o * r
return mod
def calculate_damage(l, a, d, b, mod):
dam = (((2 * l + 10) / 250) * (a / d) * b + 2)
return dam
def calculate_total_damage(mod, dam):
return dam * mod
mod = calculate_modifier(s, t, c, o, r)
dam = calculate_damage(l, a, d, b)
final = calculate_total_damage(mod, dam)

Related

How can I write this diffusion creep equation in python?

In the image I wrote the diffusion creep equation with all its variables. I just need to understand how I can transfer this into python.
I was trying to the first part of the equation but I'm not sure how to include the last part.
Use exp method in math module
import math
if __name__ == "__main__":
foo = lambda A, d, m, n, E, P, V, R, T: 2 * pow(A, -1 / n) * pow(d, m / n) * \
math.exp((E + P * V) / (n * R * T))
print(foo(A=4.5, d=1, m=3, n=1, E=10.0 ** -15, P=1, V=6, R=8.314463, T=1623))

np.int64 behaves differently from int in math-operations

I have come across a very strange problem where i do a lot of math and the result is inf or nan when my input is of type <class 'numpy.int64'>, but i get the correct (checked analytically) results when my input is of type <class 'int'>. The only library functions i use are np.math.factorial(), np.sum() and np.array(). I also use a generator object to sum over series and the Boltzmann constant from scipy.constants.
My question is essentially this: Are their any known cases where np.int64 objects will behave very differently from int objects?
When i run with np.int64 input, i get the RuntimeWarnings: overflow encountered in long_scalars, divide by zero encountered in double_scalars and invalid value encountered in double_scalars. However, the largest number i plug into the factorial function is 36, and i don't get these warnings when i use int input.
Below is a code that reproduces the behaviour. I was unable to find out more exactly where it comes from.
import numpy as np
import scipy.constants as const
# Some representible numbers
sigma = np.array([1, 2])
sigma12 = 1.5
mole_weights = np.array([10,15])
T = 100
M1, M2 = mole_weights/np.sum(mole_weights)
m0 = np.sum(mole_weights)
fac = np.math.factorial
def summation(start, stop, func, args=None):
#sum over the function func for all ints from start to and including stop, pass 'args' as additional arguments
if args is not None:
return sum(func(i, args) for i in range(start, stop + 1))
else:
return sum(func(i) for i in range(start, stop + 1))
def delta(i, j):
#kronecker delta
if i == j:
return 1
else:
return 0
def w(l, r):
# l,r are ints, return a float
return 0.25 * (2 - ((1 / (l + 1)) * (1 + (-1) ** l))) * np.math.factorial(r + 1)
def omega(ij, l, r):
# l, r are int, ij is and ID, returns float
if ij in (1, 2):
return sigma[ij - 1] ** 2 * np.sqrt(
(np.pi * const.Boltzmann * T) / mole_weights[ij - 1]) * w(l, r)
elif ij in (12, 21):
return 0.5 * sigma12 ** 2 * np.sqrt(
2 * np.pi * const.Boltzmann * T / (m0 * M1 * M2)) * w(l, r)
else:
raise ValueError('(' + str(ij) + ', ' + str(l) + ', ' + str(r) + ') are non-valid arguments for omega.')
def A_prime(p, q, r, l):
'''
p, q, r, l are ints. returns a float
'''
F = (M1 ** 2 + M2 ** 2) / (2 * M1 * M2)
G = (M1 - M2) / M2
def inner(w, args):
i, k = args
return ((8 ** i * fac(p + q - 2 * i - w) * (-1) ** (r + i) * fac(r + 1) * fac(
2 * (p + q + 2 - i - w)) * 2 ** (2 * r) * F ** (i - k) * G ** w) /
(fac(p - i - w) * fac(q - i - w) * fac(r - i) * fac(p + q + 1 - i - r - w) * fac(2 * r + 2) * fac(
p + q + 2 - i - w)
* 4 ** (p + q + 1) * fac(k) * fac(i - k) * fac(w))) * (
2 ** (2 * w - 1) * M1 ** i * M2 ** (p + q - i - w)) * 2 * (
M1 * (p + q + 1 - i - r - w) * delta(k, l) - M2 * (r - i) * delta(k, l - 1))
def sum_w(k, i):
return summation(0, min(p, q, p + q + 1 - r) - i, inner, args=(i, k))
def sum_k(i):
return summation(l - 1, min(l, i), sum_w, args=i)
return summation(l - 1, min(p, q, r, p + q + 1 - r), sum_k)
def H_i(p, q):
'''
p, q are ints. Returns a float
'''
def inner(r, l):
return A_prime(p, q, r, l) * omega(12, l, r)
def sum_r(l):
return summation(l, p + q + 2 - l, inner, args=l)
val = 8 * summation(1, min(p, q) + 1, sum_r)
return val
p, q = np.int64(8), np.int64(8)
print(H_i(p,q)) #nan
print(H_i(int(p) ,int(q))) #1.3480582058153066e-08
Numpy's int64 is a 64-bit integer, meaning it consists of 64 places that are either 0 or 1. Thus the smallest representable value is -2**63 and the biggest one is 2**63 - 1
Python's int is essentially unlimited in length, so it can represent any value. It is equivalent to a BigInteger in Java. It's stored as a list of int64s essentially that are considered a single large number.
What you have here is a classic integer overflow. You mentioned that you "only" plug 36 into the factorial function, but the factorial function grows very fast, and 36! = 3.7e41 > 9.2e18 = 2**63 - 1, so you get a number bigger than you can represent in an int64!
Since int64s are also called longs this is exactly what the warning overflow encountered in long_scalars is trying to tell you!

Python holding back the value from the previous execution

This is a program to find the roots of a quadratic equation, but when i execute the program more than once the values from the previous execution still remain in the list root. How can I clear it?
When I put del root in the function quad(), it gives an error UnboundLocalError: local variable 'root' referenced before assignment. Why?
import math
import cmath
root=[]
def roots(a:int,b:int,c:int):
if ((b**2)-4*a*c)>=0:
x1=(-b+(math.sqrt((b**2)-4*a*c)))/(2*a)
x2=(-b-(math.sqrt((b**2)-4*a*c)))/(2*a)
else:
x1=(-b+cmath.sqrt((b**2)-4*a*c))/(2*a)
x2=(-b-cmath.sqrt((b**2)-4*a*c))/(2*a)
root.append(x1)
root.append(x2)
return root
def quad():
a=int(input("enter the co-efficient of x^2-integer"))
b=int(input("enter the co-efficient of x-integer"))
c=int(input("enter the constant-integer"))
roots(a,b,c)
print(root)
del root
convert root to a local variable,
import math
import cmath
def calculate_roots(a: int, b: int, c: int):
roots = []
if ((b ** 2) - 4 * a * c) >= 0:
x1 = (-b + (math.sqrt((b ** 2) - 4 * a * c))) / (2 * a)
x2 = (-b - (math.sqrt((b ** 2) - 4 * a * c))) / (2 * a)
else:
x1 = (-b + cmath.sqrt((b ** 2) - 4 * a * c)) / (2 * a)
x2 = (-b - cmath.sqrt((b ** 2) - 4 * a * c)) / (2 * a)
roots.append(x1)
roots.append(x2)
return roots
def quad():
a = int(input("enter the co-efficient of x^2-integer"))
b = int(input("enter the co-efficient of x-integer"))
c = int(input("enter the constant-integer"))
roots = calculate_roots(a, b, c)

Sympy - Integration is slow when expression contains many symbols

Say I have the following expression which I would like to integrate over the variable z from 0 to L.
import sympy as sp
mdot, D, R, alpha, beta, xi, mu0, q, cp, Tin, L = sp.symbols("\dot{m}, D, R, alpha, beta, xi, mu_0, q, c_p, T_in, L", real=True, positive=True, constant=True)
z = sp.symbols("z", real=True, positive=True)
n = sp.Symbol("n", real=True)
firstexpr = 8 * mdot**2 * R / (sp.pi**2 * D**5) * (alpha + beta * (sp.pi * D * mu0 / (4 * mdot))**xi * (q * z / (mdot * cp) + Tin)**(n * xi)) * (q * z / (mdot * cp) + Tin)
res1 = sp.integrate(firstexpr, (z, 0, L), conds="none")
This will take forever: I had to stop the computation after 10 minutes on my pc without getting an answer.
Situation improves dramatically if I rewrite my expression so that it contains only the minimum number of constant symbols, integrating it, and finally substituting the original symbols:
a = 8 * mdot**2 * R / (sp.pi**2 * D**5)
b = beta * (sp.pi * D * mu0 / (4 * mdot))**xi
c = q / (mdot * cp)
_a, _b, _c = sp.symbols("a, b, c", real=True, positive=True, constant=True)
secondexpr = _a * (alpha + _b * (_c * z + Tin)**(n * xi)) * (_c * z + Tin)
res2 = sp.integrate(secondexpr, (z, 0, L), conds="none")
sp.simplify(res2.subs([(_a, a), (_b, b), (_c, c)]))
Why is sympy taking extremely long time in the first case? Did I miss some assumption in the creation of my symbols?

Bracket one of two roots in root finding algorithm for roots of a multivariate function

Apologies for the (maybe misleading) title and the probably confusing question itself, i struggle a lot with wording my problem and especially compressing it into one sentence for the title. I want to find the roots of a function f(w, t, some_other_args) with two variables, w and t, using python. The real function structure is really long and complicated, you can find it on the end of this post. The important thing is that it contains the following line:
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
This means that w can't exceed 1, because that would lead to calculating the square root of a negative number, which, of course, is impossible. I have algorithms for calculating the approximate values of w and t using other values in my function, but they are very inaccurate.
So, i try to calculate the roots with scipy.optimize.fsolve (after trying literally every root finding algorithm i could find online, i found this one to be the best for my function) using these approximate values as starting points, which would look like this:
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
For most values, this works perfectly fine. If w is too close to 1, however, there always comes a point when fsolve tries some value bigger than 1 for w, which, in turn, raises a ValueError(because calculating the root of a negative number is mathematically impossible). This is an example printing out the values that fsolveis using, where w should be somewhere around 0.997:
w_approx: 0.9960090844989311
t_approx: 24.26777844720981
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.26777844720981, w:0.9960090844989311
Values: t:24.267778808827888, w:0.9960090844989311
Values: t:24.26777844720981, w:0.996009099340623
Values: t:16.319554685876746, w:1.0096680915775516
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 148, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "C:\Users\...\venv\lib\site-packages\scipy\optimize\minpack.py", line 227, in _root_hybr
ml, mu, epsfcn, factor, diag)
File "C:\Users\...\algorithm.py", line 9, in f
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
ValueError: math domain error
So, how can i tell optimize.fsolve that w can't get bigger than 1? Or what are alternative algorithms for doing something like this (i know about brentq and so on, but all of those require giving an interval for both roots, which i don't want to do.)?
Code for testing (What's important to note here: even though func theoretically is supposed to calculate R and T given t and w, i have to use it the other way around. It's a bit clunky, but i simply don't manage to rewrite the function so that it accepts T, R to calculate t, w - it's a bit too much for my mediocre mathematical expertise ;)) :
import math as m
from scipy import optimize
import numpy as np
def func(t, w, r_1, r_2, r_3):
k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
k23 = 2 * k / 3
z1 = 1 / (1 + k23)
z2 = 1 / (1 - k23)
z3 = 3 * ((1 / 5 + r_1 - r_2 - 1 / 5 * r_1 * r_2) / (z1 - r_2 * z2)) * m.exp(t * (k - 1))
z4 = -(z2 - r_2 * z1) / (z1 - r_2 * z2) * m.exp(2 * k * t)
z5 = -(z1 - r_2 * z2) / (z2 - r_2 * z1)
z6 = 3 * (1 - r_2 / 5) / (z2 - r_2 * z1)
beta_t = r_3 / (z2 / z1 * m.exp(2 * k * t) + z5) * (z6 - 3 / (5 * z1) * m.exp(t * (k - 1)))
alpha_t = beta_t * z5 - r_3 * z6
beta_r = (z3 - r_1 / 5 / z2 * m.exp(-2 * t) * 3 - 3 / z2) / (z1 / z2 + z4)
alpha_r = -z1 / z2 * beta_r - 3 / z2 - 3 / 5 * r_1 / z2 * m.exp(-2 * t)
It_1 = 1 / 4 * w / (1 - 8 / 5 * w) * (alpha_t * z2 * m.exp(-k * t) + beta_t * z1 * m.exp(k * t) + 3 * r_3 * m.exp(-t))
Ir_1 = (1 / 4 * w / (1 - 8 / 5 * w)) * (z1 * alpha_r + z2 * beta_r + 3 / 5 + 3 * r_1 * m.exp(-2 * t))
T = It_1 + m.exp(-t) * r_3
R = Ir_1 + m.exp(-2 * t) * r_1
return [T, R]
def calc_1(t, w, T, R, r_1, r_2, r_3):
t_begin = float(t[0])
T_new, R_new = func(t_begin, w, r_1, r_2, r_3)
a = abs(-1 + T_new/T)
b = abs(-1 + R_new/R)
return np.array([a, b])
def calc_2(x, T, R, r_1, r_2, r_3):
t = x[0]
w = x[1]
T_new, R_new = func(t, w, r_1, r_2, r_3)
a = abs(T - T_new)
b = abs(R - R_new)
return np.array([a, b])
def approximate_w(R):
k = (1 - R) / (R + 2 / 3)
w_approx = (1 - ((2 / 3 * k) ** 2)) / (1 - ((1 / 3 * k) ** 2))
return w_approx
def approximate_t(w, T, R, r_1, r_2, r_3):
t = optimize.root(calc_1, x0=np.array([10, 0]), args=(w, T, R, r_1, r_2, r_3))
return t.x[0]
def solve(T, R, r_1, r_2, r_3):
w_x = approximate_w(R)
t_x = approximate_t(w_x, T, R, r_1, r_2, r_3)
sol = optimize.fsolve(calc_2, x0=np.array([t_x, w_x]), args=(T, R, r_1, r_2, r_3))
return sol
# Values for testing:
T = 0.09986490557943692
R = 0.8918728343037964
r_1 = 0
r_2 = 0
r_3 = 1
print(solve(T, R, r_1, r_2, r_3))
What about logisticing the argument that you want to constrain? I mean, inside f, you could do
import numpy as np
def f(free_w, ...):
w = 1/(1 + np.exp(-free_w)) # w will always lie between 0 and 1
...
return zeros
And then, you would just have to apply the same logistic-transformation to the solution value of free_w to get w*. See
solution = optimize.fsolve(f, x0=np.array([t_approx, w_approx]), args=(some_other_args))
free_w = solution[0]
w = 1/(1 + np.exp(-free_w))
Your reported error occurs as fsolve can not deal with the implicit restrictions in the conversion of w to k. This can be solved radically by inverting that dependence, making func dependent on t and k instead.
def w2k(w): return 3 * m.sqrt((1.0 - w) / (4.0 - w))
#k = 1.5 * m.sqrt((1.0 - w) / (1.0 - 0.25 * w))
# (k/3)**2 * (4-w)= 1-w
def k2w(k): return 4 - 3/(1-(k/3)**2)
def func(t, k, r_1, r_2, r_3):
w = k2w(k)
print "t=%20.15f, k=%20.15f, w=%20.15f"%(t,k,w)
...
Then remove the absolute values from the function values in calc1 and calc2. This only renders your solutions as non-differentiable points which is bad for any root-finding algorithm. Sign changes and smooth roots are good for Newton-like methods.
def calc_2(x, T, R, r_1, r_2, r_3):
t = x[0]
k = x[1]
T_new, R_new = func(t, k, r_1, r_2, r_3)
a = T - T_new
b = R - R_new
return np.array([a, b])
It makes not much sense to find the value for t by solving the equation keeping w resp. k fixed, it just doubles the computational effort.
def approximate_k(R):
k = (1 - R) / (R + 2 / 3)
return k
def solve(T, R, r_1, r_2, r_3):
k_x = approximate_k(R)
t_x = 10
sol = optimize.fsolve(calc_2, x0=np.array([t_x, k_x]), args=(T, R, r_1, r_2, r_3))
return sol
t,k = solve(T, R, r_1, r_2, r_3)
print "t=%20.15f, k=%20.15f, w=%20.15f"%(t, k, k2w(k))
With these modifications the solution
t= 14.860121342410327, k= 0.026653140486605, w= 0.999763184675043
is found within 15 function evaluations.
You should try defining explicitly your function before optimizing it, that way you can check for domain more easily.
Essentially you have a function of T and R. this worked for me:
def func_to_solve(TR_vector, r_1, r_2, r_3):
T, R = TR_vector # what you are trying to find
w_x = approximate_w(R)
t_x = approximate_t(w_x, T, R, r_1, r_2, r_3)
return (calc_2([t_x, w_x], T, R, r_1, r_2, r_3))
def solve(TR, r_1, r_2, r_3):
sol = optimize.fsolve(func_to_solve, x0=TR, args=(r_1, r_2, r_3))
return sol
Also, replace m.exp by np.exp

Categories