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
Related
when i import a python file(let's call it function file 1 ) that contains a function that i need in another python file(let's call it file 2) and call the function from file 2 using different function inputs, i get the results that i expect from file 1( when calling the function according to the inputs of file 1 ) and then i get the results that i want( from running the function in file 2 with the new function inputs). What could be the reason for that?
file 2 should call the function jacobi from the file Jacobi_Iteration and give the two arrays A,f and x(guess array) as inputs and the function"jacobi" should return x and stor it in ans_s. What calling the function, however, does is to call jacobi and give it old inputs that were used for calling jacobi in the file Jacobi_Iterations and then call jacobi with inputs given in file 2. The end result is getting the results expected from the old inputs and then those of the new inputs after each other in the results pane. Of course, i tried not calling jacobi in Jacobi_Iterations and only calling it in file2, but in vain.
Remarks:
Both functions are present in the same directory
This is file 2:
import numpy
import numpy.linalg as nl
from Jacobi_Iteration import jacobi
A = numpy.array([[72.0,0.0,0.0,0.0,0.0],
[0.0,38.0,0.0,0.0,0.0],
[72.0,38.0,-160.0,0.0,0.0],
[0.0,0.0,160.0,-185.0,0.0],
[0.0,0.0,0.0,180.0,-215.0]])
f = numpy.array([180.0,810.0,-630.0,-2750.0,-3820.0])
# sol = nl.solve(A,f)
#print("sol=",sol)
# solving using the jacobi iteration
x = [15.0,15.0,15.0,15.0,15.0]
ans_2 = jacobi(A,f,x)
print(ans_2)
This is the function file"Jacobi_Iterations"
import numpy
import numpy.linalg as nl
def jacobi(A,f,x,maxIter=100,tol=0.0001):
# x is the guess vector
xnew = numpy.copy(x)
n = f.size
# Checking for the dimensions of the matrices
if (A.shape[0] != n) or (A.shape[1] != n):
print("Incorrect dimentions !")
return f
# Generating new guesses and seeing whether A.x will converge during the maxIter
for iter in range(maxIter):
# checking if the guess vector satisfies the tol:
res = f - numpy.dot(A,x)
if ( nl.norm(res,2) < tol ):
print("converged after",iter,"iterations!")
return x
# Getting a better guess vector x:
for i in range(n):
sum = 0.0
for j in range(n):
if (i != j):
sum+= A[i,j] * x[j]
xnew[i] = (f[i] - sum)/A[i,i]
x = numpy.copy(xnew)
return x
Python by default will look for packages in some pre-determined places. Working dir might be a candidate
It might not be the case for you but try to find out if there are conflicts with these.
I had this prob in the past
This is a nice link:
https://leemendelowitz.github.io/blog/how-does-python-find-packages.html
def f(x):
f='exp(x)-x-2'
y=eval(f)
print(y)
return y
def bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2):
x=a
result_a=f(a)
x=b
result_b=f(b)
if (f.evalf(a)*f.evalf(b)>=0):
print("Interval [a,b] does not contain a zero ")
exit()
zeta=min(epsilon1,epsilon2)/10
x=a
while(f_line(x)>0):
if(x<b or x>-b):
x=x+zeta
else:
stop
ak=a
bk=b
xk=(ak+bk)/2
k=0
if (f(xk)*f(ak)<0):
ak=ak
bk=xk
if (f(xk)*f(bk)<0):
ak=xk
bk=bk
k=k+1
from sympy import *
import math
x=Symbol('x')
f=exp(x)-x-2
f_line=f.diff(x)
f_2lines=f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a=int(input('Beginning of interval: '))
b=int(input('End of interval: '))
epsilon1=input('1st tolerance: ')
epsilon2=input('2nd tolerance: ')
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
This program is an attempt to implement the Bissection Method. I've tried writing two functions:
The first one, f, is supposed to receive the extremes of the interval that may or may not contain a root (a and b) and return the value of the function evaluated in this point.
The second one, bissection, should receive the function, the function's first and second derivatives, the extremes of the interval (a,b) and two tolerances (epsilon1,epsilon2).
What I want to do is pass each value a and b, one at a time, as arguments to the function f, that is supposed to return f(a) and f(b); that is, the values of the function in each of the points a and b.
Then, it should test two conditions:
1) If the function values in the extremes of the intervals have opposite signs. If they don't, the method won't converge for this interval, then the program should terminate.
if(f.evalf(a)*f.evalf(b)>=0)
exit()
2)
while(f_line(x)>0): #while the first derivative of the function evaluated in x is positive
if(x<b or x>-b): #This should test whether x belongs to the interval [a,b]
x=x+zeta #If it does, x should receive x plus zeta
else:
stop
At the end of this loop, my objective was to determine whether the first derivative was strictly positive (I didn't do the negative case yet).
The problem: I'm getting the error
Traceback (most recent call last):
File "bissec.py", line 96, in <module>
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
File "bissec.py", line 41, in bissection
result_a=f(a)
TypeError: 'Add' object is not callable
How can I properly call the function so that it returns the value of the function (in this case, f(x)=exp(x)-x-2), for every x needed? That is, how can I evaluate f(a) and f(b)?
Ok, so I've figured it out where your program was failing and I've got 4 reasons why.
First of all, and the main topic of your question, if you want to evaluate a function f for a determined x value, let's say a, you need to use f.subs(x, a).evalf(), as it is described in SymPy documentation. You used in 2 different ways: f.evalf(2) and f_line(a); both were wrong and need to be substituted by the correct syntax.
Second, if you want to stop a while loop you should use the keyword break, not "stop", as written in your code.
Third, avoid using the same name for variables and functions. In your f function, you also used f as the name of a variable. In bissection function, you passed f as a parameter and tried to call the f function. That'll fail too. Instead, I've changed the f function to f_calc, and applied the correct syntax of my first point in it.
Fourth, your epsilon1 and epsilon2 inputs were missing a float() conversion. I've added that.
Now, I've also edited your code to use good practices and applied PEP8.
This code should fix this error that you're getting and a few others:
from sympy import *
def func_calc(func, x, val):
"""Evaluate a given function func, whose varible is x, with value val"""
return func.subs(x, val).evalf()
def bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2):
"""Applies the Bissection Method"""
result_a = func_calc(f, x, a)
result_b = func_calc(f, x, b)
if (result_a * result_b >= 0):
print("Interval [a,b] does not contain a zero")
exit()
zeta = min(epsilon1, epsilon2) / 10
x_val = a
while(func_calc(f_line, x, a) > 0):
if(-b < x_val or x_val < b):
x_val = x_val + zeta
else:
break # the keyword you're looking for is break, instead of "stop"
print(x_val)
ak = a
bk = b
xk = (ak + bk) / 2
k = 0
if (func_calc(f, x, xk) * func_calc(f, x, ak) < 0):
ak = ak
bk = xk
if (func_calc(f, x, xk) * func_calc(f, x, bk) < 0):
ak = xk
bk = bk
k = k + 1
def main():
x = Symbol('x')
f = exp(x) - x - 2
f_line = f.diff(x)
f_2lines = f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a = int(input('Beginning of interval: '))
b = int(input('End of interval: '))
epsilon1 = float(input('1st tolerance: '))
epsilon2 = float(input('2nd tolerance: '))
bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2)
if __name__ == '__main__':
main()
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 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?
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))