I am working on Google's "Doomsday Fuel" problem in Python 2.7 (it needs to be done in Python 2.7, hence the from __future__ import division line) that uses NumPy, which admittedly I am not too familiar with.
The WIP code (with a lot of comments added for your convenience):
from __future__ import division
from fractions import Fraction
import numpy as np
from numpy import linalg as LA
def gcd(m,n):
'''
function for finding the greatest common divisor of m and n
used mostly for the LCM function
'''
if m < n:
return gcd(n,m)
return gcd(n,m%n)
def lcm(m,n):
'''
function for finding the least common multiple of m and n
using the fact that m*n = gcd(m,n)*lcm(m,n)
'''
return (m*n)/(gcd(m,n))
def answer(m):
'''
m is an square matrix of nonnegative integers
dimensions guaranteed to be at most 10x10
'''
tbd = [] #stands for To Be Deleted
l = len(m)
for i in range(l):
'''
Checks each row
If row i is empty, add i to tbd, then make m[i][i] = 1
Otherwise, divide row i by the sum of row i to "normalize" it
e.g. [[3,2],[0,0]] would become [[0.6,0.4],[0,1]]
'''
s = sum(m[i])
if s == 0:
tbd.append(i)
m[i][i] = 1
else:
for j in range(l):
m[i][j] /= s
tbd.sort(reverse=True)
a = np.array(m)
r = np.diag([1 for x in range(l)]) #set initial matrix r which is just the identity matrix with same dimensions as a
for i in range(100):
r *= a #with each row adding up to just 1, r should stay stable
initial = [0 for x in range(l)]
initial[0] = 1
final = initial * r
for i in tbd:
del final[i]
dens = [] #denominators
for i in range(len(final)):
final[i] = final[i].limit_denominator()
dens.append(final[i].denominator) #collect all denominators
lc = dens[0]
for j in range(1,len(dens)):
lc = lcm(lc,dens[j]) #find LCM of all the denominators
for i in range(len(final)):
final[i] = int(final[i] * lc) #multiply the final array (which uses Fractions) by the LCM, then convert elements to int
final.append(lc)
return final
def main():
print answer([[1,2],[2,1]])
print answer([[0,1,0,0,0,1],[4,0,0,3,2,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]])
main()
Code in Ideone: http://ideone.com/DO1otS
The error message:
Traceback (most recent call last):
File "prog.py", line 51, in <module>
File "prog.py", line 48, in main
File "prog.py", line 29, in answer
TypeError: Cannot cast ufunc multiply output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
Why can't the program multiply int and float together? Or is there another part in this error message that I'm missing?
Related
I have written a code to compare the solution of sympy and PARI/GP, how ever I am facing a problem to get an array/vector from PARI/GP.
When I try to return the vector res from PARI/GP function nfroots, I get a address like this (see the last line) -
[3, 4]
elements as long (only if of type t_INT):
3
4
<__main__.LP_LP_c_long object at 0x00000000056166C8>
how can I get the res as vector/array from nfroots so I can use that array like normal python vector/array?
The code is given below to download the libpari.dll file, click here-
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.dll")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
#Changed c_long to c_float, but got no output
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def Quartic_Comparison():
x = Symbol('x')
#a=0;A=0;B=1;C=-7;D=13/12 #PROBLEM 1
a=0;A=0;B=1;C=-7;D=12
#a=0;A=0;B=-1;C=-2;D=1
solution=solve(a*x**4+A*x**3+B*x**2+ C*x + D, x)
print(solution)
V=(A,B,C,D)
P = pari.gtopoly(t_vec(V), c_long(-1))
res = pari.nfroots(None, P)
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
print(pari.itos(res[i]))
return res #PROBLEM 2
f=Quartic_Comparison()
print(f)
res is an element from the PARI/C world. It is a PARI vector of PARI integers (t_VEC of t_INTs). Python does not know it.
If it is to be processed further on the Python side, it must be converted. This is generally necessary if data needs to be exchanged between Python and the PARI/C world.
So if you have a t_VEC with t_INTs on the PARI/C side, as in this case, you most likely want to convert it to a Python list.
One possible approach might look like this:
...
roots = pari.nfroots(None, P)
result = []
for i in range(1, pari.glength(roots) + 1):
result.append(pari.itos(roots[i]))
return result
Referring to my code below (only the relevant part of original code), since x0 is a 4 X 3 array, x should also be the same. But I get an 'invalid index to scalar variable' error in constraint1.
I wrote the constraints iteratively as done in the answer in scipy.optimize.minimize (COBYLA and SLSQP) ignores constraints initiated within for loop
Any better (general) way to write the constraints would be great. Thanks in advance!
I need the loop for the constraints as this is just a toy optimization problem and not the original optimization problem(Game theory) I wish to solve.
The code(link to complete code below):
def constraint1(i):
def g(x):
con = 20
for k in range(3):
con = con - x[i][k]
return con
return g
x0 = np.array([[5,5,5],[5,5,5],[5,5,5],[5,5,5]])
cons = []
for i in range(4):
cons.append({'type': 'ineq', 'fun': constraint1(i)})
solution = minimize(objective,x0,method='SLSQP',\
bounds=None,constraints=cons)
And the error (Please ignore the line numbers as the above is a part of a slightly bigger code):
Traceback (most recent call last):
File "opt.py", line 44, in <module>
bounds=None,constraints=cons)
File "C:\Users\dott\Anaconda2\lib\site-packages\scipy\optimize\_minimize.py", line 458, in minimize constraints, callback=callback, **options)
File "C:\Users\dott\Anaconda2\lib\site-packages\scipy\optimize\slsqp.py", line 312, in _minimize_slsqp
mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['ineq']]))
File "opt.py", line 15, in g
con = con - x[i][k]
IndexError: invalid index to scalar variable.
The complete code: https://pastebin.com/cvYBvW3B
It seems that optimization task flatten your initial guess and return after each iteration flattened solution array (instead of 4x3 array it returns 1x12 array). That's why you get this kind of error. You should reshape your x array in objective and constraints functions from 1x12 to 4x3. After that, you can access second dimension of x variable and avoid IndexError: invalid index to scalar variable.. Your functions should be like this:
def objective(x):
global q
sum = 0
x = x.reshape((4, 3))
for i in range(4):
for j in range(3):
sum = sum + x[i][j]*q[i][j]
return -1*sum
def constraint1(i):
def g(x):
con = 20
x = x.reshape((4, 3))
for k in range(3):
con = con - x[i][k]
return con
return g
def constraint2(k):
def h(x):
sum_eq = 20
x = x.reshape((4, 3))
for i in range(4):
sum_eq = sum_eq - x[i][k]
return sum_eq
return h
This is a followup question from the one I posted a few minutes ago. The problem I was having with multiplying int with float is fixed, thanks to user2357112 in the comments. However, it's come across another roadblock.
Code:
from __future__ import division
from fractions import Fraction
import numpy as np
from numpy import linalg as LA
def gcd(m,n):
if m < n:
return gcd(n,m)
return gcd(n,m%n)
def lcm(m,n):
return (m*n)/(gcd(m,n))
def answer(m):
tbd = []
l = len(m)
for i in range(l):
s = sum(m[i])
if s == 0:
tbd.append(i)
m[i][i] = 1
else:
for j in range(l):
m[i][j] /= s
tbd.sort(reverse=True)
a = np.array(m)
r = np.diag([1.0 for x in range(l)])
for i in range(100):
r *= a
initial = [0 for x in range(l)]
initial[0] = 1
final = initial * r
for i in tbd:
del final[i]
dens = []
for i in range(len(final)):
final[i] = final[i].limit_denominator()
dens.append(final[i].denominator)
lc = dens[0]
for j in range(1,len(dens)):
lc = lcm(lc,dens[j])
for i in range(len(final)):
final[i] = int(final[i] * lc)
final.append(lc)
return final
def main():
print answer([[1,2],[2,1]])
print answer([[0,1,0,0,0,1],[4,0,0,3,2,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]])
main()
Code in ideone: http://ideone.com/DO1otS
Error:
Traceback (most recent call last):
File "prog.py", line 51, in <module>
File "prog.py", line 48, in main
File "prog.py", line 37, in answer
AttributeError: 'numpy.ndarray' object has no attribute 'limit_denominator'
I am confused about why final[i] was recognized as a numpy.ndarray object. I thought that, since final is a 1-dimensional array, final[i] will therefore return the value (a float) within that array at index i. I'm not sure why that is not the case. Thank you in advance!
This is the answer to your question "I am confused about why final[i] was recognized as a numpy.ndarray object." In the following snippet of code
r = np.diag([1.0 for x in range(l)])
initial = [0 for x in range(l)]
final = initial * r
I skipped non-essential code. The code above shows that r is a numpy.ndarray and initial is a list. Then final is a product of a numpy.ndarray and a list. The result of this product is a numpy.ndarray.
What is also important is that r is an array of floats. Therefore final is also an array of floats and not fraction objects. Therefore you cannot call limit_denominator() on elements of final.
In addition, code such as:
for i in tbd:
del final[i]
looks quite suspicious.
I am trying to complete the following exercise:
https://www.codewars.com/kata/whats-a-perfect-power-anyway/train/python
I tried multiple variations, but my code breaks down when big numbers are involved (I tried multiple variations with solutions involving log and power functions):
Exercise:
Your task is to check wheter a given integer is a perfect power. If it is a perfect power, return a pair m and k with m^k = n as a proof. Otherwise return Nothing, Nil, null, None or your language's equivalent.
Note: For a perfect power, there might be several pairs. For example 81 = 3^4 = 9^2, so (3,4) and (9,2) are valid solutions. However, the tests take care of this, so if a number is a perfect power, return any pair that proves it.
The exercise uses Python 3.4.3
My code:
import math
def isPP(n):
for i in range(2 +n%2,n,2):
a = math.log(n,i)
if int(a) == round(a, 1):
if pow(i, int(a)) == n:
return [i, int(a)]
return None
Question:
How is it possible that I keep getting incorrect answers for bigger numbers? I read that in Python 3, all ints are treated as "long" from Python 2, i.e. they can be very large and still represented accurately. Thus, since i and int(a) are both ints, shouldn't the pow(i, int(a)) == n be assessed correctly? I'm actually baffled.
(edit note: also added integer nth root bellow)
you are in the right track with logarithm but you are doing the math wrong, also you are skipping number you should not and only testing all the even number or all the odd number without considering that a number can be even with a odd power or vice-versa
check this
>>> math.log(170**3,3)
14.02441559235585
>>>
not even close, the correct method is described here Nth root
which is:
let x be the number to calculate the Nth root, n said root and r the result, then we get
rn = x
take the log in any base from both sides, and solve for r
logb( rn ) = logb( x )
n * logb( r ) = logb( x )
logb( r ) = logb( x ) / n
blogb( r ) = blogb( x ) / n
r = blogb( x ) / n
so for instance with log in base 10 we get
>>> pow(10, math.log10(170**3)/3 )
169.9999999999999
>>>
that is much more closer, and with just rounding it we get the answer
>>> round(169.9999999999999)
170
>>>
therefore the function should be something like this
import math
def isPP(x):
for n in range(2, 1+round(math.log2(x)) ):
root = pow( 10, math.log10(x)/n )
result = round(root)
if result**n == x:
return result,n
the upper limit in range is to avoid testing numbers that will certainly fail
test
>>> isPP(170**3)
(170, 3)
>>> isPP(6434856)
(186, 3)
>>> isPP(9**2)
(9, 2)
>>> isPP(23**8)
(279841, 2)
>>> isPP(279841)
(529, 2)
>>> isPP(529)
(23, 2)
>>>
EDIT
or as Tin Peters point out you can use pow(x,1./n) as the nth root of a number is also expressed as x1/n
for example
>>> pow(170**3, 1./3)
169.99999999999994
>>> round(_)
170
>>>
but keep in mind that that will fail for extremely large numbers like for example
>>> pow(8191**107,1./107)
Traceback (most recent call last):
File "<pyshell#90>", line 1, in <module>
pow(8191**107,1./107)
OverflowError: int too large to convert to float
>>>
while the logarithmic approach will success
>>> pow(10, math.log10(8191**107)/107)
8190.999999999999
>>>
the reason is that 8191107 is simple too big, it have 419 digits which is greater that the maximum float representable, but reducing it with a log produce a more reasonable number
EDIT 2
now if you want to work with numbers ridiculously big, or just plain don't want to use floating point arithmetic altogether and use only integer arithmetic, then the best course of action is to use the method of Newton, that the helpful link provided by Tin Peters for the particular case for cube root, show us the way to do it in general alongside the wikipedia article
def inthroot(A,n):
if A<0:
if n%2 == 0:
raise ValueError
return - inthroot(-A,n)
if A==0:
return 0
n1 = n-1
if A.bit_length() < 1024: # float(n) safe from overflow
xk = int( round( pow(A,1/n) ) )
xk = ( n1*xk + A//pow(xk,n1) )//n # Ensure xk >= floor(nthroot(A)).
else:
xk = 1 << -(-A.bit_length()//n) # power of 2 closer but greater than the nth root of A
while True:
sig = A // pow(xk,n1)
if xk <= sig:
return xk
xk = ( n1*xk + sig )//n
check the explanation by Mark Dickinson to understand the working of the algorithm for the case of cube root, which is basically the same for this
now lets compare this with the other one
>>> def nthroot(x,n):
return pow(10, math.log10(x)/n )
>>> n = 2**(2**12) + 1 # a ridiculously big number
>>> r = nthroot(n**2,2)
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
nthroot(n**2,2)
File "<pyshell#47>", line 2, in nthroot
return pow(10, math.log10(x)/n )
OverflowError: (34, 'Result too large')
>>> r = inthroot(n**2,2)
>>> r == n
True
>>>
then the function is now
import math
def isPPv2(x):
for n in range(2,1+round(math.log2(x))):
root = inthroot(x,n)
if root**n == x:
return root,n
test
>>> n = 2**(2**12) + 1 # a ridiculously big number
>>> r,p = isPPv2(n**23)
>>> p
23
>>> r == n
True
>>> isPPv2(170**3)
(170, 3)
>>> isPPv2(8191**107)
(8191, 107)
>>> isPPv2(6434856)
(186, 3)
>>>
now lets check isPP vs isPPv2
>>> x = (1 << 53) + 1
>>> x
9007199254740993
>>> isPP(x**2)
>>> isPPv2(x**2)
(9007199254740993, 2)
>>>
clearly, avoiding floating point is the best choice
I have written the following code in python 2.7 in order to calculate an integration numerically and then use the result of this integration for further steps of the project.
import numpy as np
from scipy import linspace,logspace
from cosmicpy import *
Omega_Matter, Omega_DarkEnergy, A, b, rho_critical, m = 0.306, 0.694, 0.3222, 0.707, 2.77536627e+11, 1000000
def D(z):
a = 1/(1+z)
x = (Omega_DarkEnergy/Omega_Matter)**(1/3)*a
return (5/2)*(Omega_Matter/Omega_DarkEnergy)**(1/3)*x**(-3/2)*(1+x**3)**(1/2)* \
(x**2/(3*x**3 + 3) - np.log(x + 1)/9 + np.log(x**2 - x + 1)/18 \
+ np.sqrt(3)*np.arctan(2*np.sqrt(3)*x/3 \
- np.sqrt(3)/3)/9 + np.sqrt(3)*np.pi/54)
def delta(z):
return D(z)/D(0)
def W(k, M):
rho_m = rho_critical*Omega_Matter
R = (3*M/(4*np.pi*rho_m))**(1/3)
x = k*R
return (3/x)*(sin(x)-x*cos(x))
my_cosmology = cosmology(Omega_m=0.306, Omega_de=0.694, h=0.679, Omega_b=0.0483, n=0.968, tau=0.067, sigma8=0.815, w=-1)
k_array = np.logspace(-16,4,m)
P = my_cosmology.pk_lin(k_array)
def sigma_squared(z, M):
dk = (np.max(k_array)-np.min(k_array))/(m-1)
summation = []
for k in k_array:
Integral = 0
Integrand = k**2*P[k]*(W(k, M))**2
Integral += dk * np.sum(Integrand[k])
summation.append(Integral)
return ((delta(z))**2/(2*(np.pi)**2))*summation[-1]
print(summation)
sigma_squared(0.01, 1e+9)
As I write more of the code, I check my steps one by one by getting a print and see if the output is what I expect. However, I am unable to produce the final product of the last function which is supposed to be a value given the values for the variables z and M. In particular I am sure that something is wrong with the integration inside that function because I am not getting any thing for print(summation) which is supposed to be a big 1d array whose last element print(summation[-1])should give me the area under the curve (upto a pre-factor defined in the final return of the function). Here is the error message and I couldn't find any on-line source for the particular error message I am getting. Your help is greatly appreciated.
mycode.py:95: VisibleDeprecationWarning: using a non-integer number
instead of an integer will result in an error in the future
Integrand = k**2*P[k]*(W(k, M))**2 Traceback (most recent call last):
File "mycode.py", line 102, in
sigma_squared(0.01, 1e+9) File "mycode.py", line 96, in sigma_squared
Integral += dk * np.sum(Integrand[k]) TypeError: 'Zero' object has no attribute 'getitem'
Edited Code (which is too slow to know if it is working correctly):
k_array = np.logspace(-16,4,m)
my_cosmology = cosmology(Omega_m=0.306, Omega_de=0.694, h=0.679, Omega_b=0.0483, n=0.968, tau=0.067, sigma8=0.815, w=-1)
P = my_cosmology.pk_lin(k_array)
M_array = np.logspace(8,16,n)
def W(k, M):
rho_m = rho_critical*Omega_Matter
R = (3*M/(4*np.pi*rho_m))**(1/3)
y = k*R
return (3/y**3)*(sin(y)-y*cos(y))
def sigma_squared(z, M):
dk = (np.max(k_array)-np.min(k_array))/(m-1)
summation = []
for k in k_array:
for M in M_array:
Integral = 0
Integrand = k**2*P[k]*(W(k, M))**2
Integral += dk * np.sum(Integrand)
summation.append(Integral)
return ((delta(z))**2/(2*(np.pi)**2))*summation[-1]
print(sigma_squared(0, 1e+9))