Obtaining the value of a 'GK_Operators' class - python

The main purpose of this question is to figure out how to obtain the value of what seems to be a 'GK.Operator'. I am new in the gekko environment and I may be not specific enough but I will try my best.
Here it is an example code
from gekko import GEKKO
from numpy import triu_indices, diag_indices, full
#Create a gekko model
model=GEKKO()
n=2
idx=triu_indices(n,1)
#Create a 1xn array
T=model.Array(model.CV, n)
#Create a nxn array
R = full((n, n), 0, dtype=object)
#Fill only the upper and lower triangle of the R matrix
if n>1:
R[idx] = model.FV(name='R')
R[idx[::-1]] = R[idx]
#Same as R array
Q = full((n, n), 0, dtype=object)
Q[diag_indices(n)] = model.Const(0)
if n>1:
Q[idx] = (T[idx[1]] - T[idx[0]]) / R[idx]
Q[idx[::-1]] = -Q[idx]
#Assign values to T and R
T[1].VALUE,T[0].VALUE=25,12
R[0,1].VALUE=4
print(R)
model.solve(disp=False)
print(R)
print(Q[0,1].VALUE)
print(T[1].MODEL,T[0].MODEL,R[0,1].VALUE)
print(type(R[0,1]),
type(Q[0,1]))
First of all, I think that it would be useful to say that this code comes from a bigger one that simulates a dynamic system, there is not an objective function and therefore is not an optimization problem.
The problem here, is that I can not obtain the value of any of the items of the Q array. As long as I am concerned, the attribute .VALUE or .MODEL will return the value of a gekko variable. However, it seems like it is not working with the variable Q[0,1] which is supposed to be equal to the result of the operation (T[1]-T[0])/R[0,1] or (25-12)/4. When asking for that value with Q[0,1].VALUE a 0 is returned, but that is clearly not the result of that operation. I thought that the class of that variable could have something to do with this, and when checking with type(Q[0,1]), it returns a GK.Operator. I am not sure about what really a GK.Operator is, but I guess that using the attributes .VALUE or .MODEL will not work. It is quite important for me to be able to obtain the values of Q.
In addition, there is another problem with the array R. Before solving the model, that array is what it is supposed to be. However, after solving the model some items of that array become themselves arrays.
I hope that you can help me understanding these doubts. Thanks for reading.

The Q value needs to be a Gekko Var, Param, or Intermediate to use .value. Here is a simplified version of the code that works:
from gekko import GEKKO
from numpy import triu_indices, diag_indices, full
#Create a gekko model
model=GEKKO()
#Create a 1xn array
T=model.Array(model.Var,2)
#Create a nxn array
R = full((2,2), 0, dtype=object)
#Fill only the upper and lower triangle of the R matrix
R[0,1] = model.FV(name='R')
R[1,0] = R[0,1]
#Same as R array
Q = full((2,2), 0, dtype=object)
Q[0,0] = 0
Q[1,1] = 0
Q[0,1] = model.Intermediate((T[1] - T[0]) / R[0,1])
Q[1,0] = model.Intermediate(-Q[0,1])
#Assign values to T and R
T[1].VALUE,T[0].VALUE=25,12
R[0,1].VALUE=4
print('R before solve: ',R)
model.solve(disp=False)
print('R after solve: ',R)
print('Q[0,1]:',Q[0,1].value)
print('Q[1,0]:',Q[1,0].value)
print('T[1],T[0]:',T[1].value,T[0].value)
print('R[0,1] type:',type(R[0,1]))
print('Q[0,1] type:',type(Q[0,1]))
Results:
R before solve: [[0 4]
[4 0]]
R after solve: [[0 [4.0]]
[[4.0] 0]]
Q[0,1]: [3.25]
Q[1,0]: [-3.25]
T[1],T[0]: [25.0] [12.0]
R[0,1] type: <class 'gekko.gk_parameter.GK_FV'>
Q[0,1] type: <class 'gekko.gk_operators.GK_Intermediate'>

Related

Parameter Optimization Using Minimize in Python

I have written the following two functions to calibrate a model :
The main function is:
def function_Price(para,y,t,T,tau,N,C):
# y= price array
# C = Auto and cross correlation array
# a= paramters need to be calibrated
a=para[0:]
temp=0
for j in range(N):
price_j = a[j]*C[j]*P[t:T-tau,j]
temp=temp+price_j
Price=temp
return Price
The objective function is :
def GError_function_Price(para,y,k,t,T,tau,N,C):
# k is the price need to be fitted
return sum((function_Price(para,y,t,T,tau,N,C)-k[t+tau:T]) ** 2)
Now, I am calling these two functions to do the optimization of the model:
import numpy as np
from scipy.optimize import minimize
# Prices (example)
y = np.array([[1,2,3,4,5,4], [4,5,6,7,8,9], [6,7,8,7,8,6], [13,14,15,11,12,19]])
# Correaltion (example)
Corr= np.array([[1,2,3,4,5,4], [4,5,6,7,8,9], [6,7,8,7,8,6], [13,14,15,11,12,19],[1,2,3,4,5,4],[6,7,8,7,8,6]])
# Define
tau=1
Size = y.shape
N = Size[1]
T = Size[0]
t=0
# initial Values
para=np.zeros(N)
# Bounds
B = np.zeros(shape=(N,2))
for n in range(N):
B[n][0]= float('-inf')
B[n][1]= float('inf')
# Calibration
A = np.zeros(shape=(N,N))
for i in range (N):
k=y[:,i] #fitted one
C=Corr[i,:]
parag=minimize(GError_function_Price,para,args=(y,Y,t,T,tau,N,C),method='SLSQP',bounds=B)
A[i,:]=parag.x
Once, I run the model, It should produce an N by N array of optimized values of paramters. But, except for the first column, it keeps zeros for the rest. Something is wrong.
Can you help me fix the problem, please?
I know how to do it in Matlab.
The following is Matlab Code :
main function
function Price=function_Price(para,P,t,T,tau,N,C)
a=para(:,:);
temp=0;
for j=1:N
price_j = a(j).*C(j).*P(t:T-tau,j);
temp=temp+price_j;
end
Price=temp;
end
The objective function:
function gerr=GError_function_Price(para,P,Y,t,T,tau,N,C)
gerr=sum((function_Price(para,P,t,T,tau,N,C)-Y(t+tau:T)).^2);
end
Now, I call these two functions in the following way:
P = [1,2,3,4,5,4;4,5,6,7,8,9;6,7,8,7,8,6;13,14,15,11,12,19];
AutoAndCrossCorr= [1,2,3,4,5,4;4,5,6,7,8,9;6,7,8,7,8,6;13,14,15,11,12,19;1,2,3,4,5,4;6,7,8,7,8,6];
tau=1;
Size = size(P);
N =6;
T =4;
t=1;
for i=1:N
Y=P(:,i); % fitted one
C=AutoAndCrossCorr(i,:);
para=zeros(1,N);
lb= repmat(-inf,N,1);
ub= repmat(inf ,N,1);
parag=fminsearchbnd(#(para)abs(GError_function_Price(para,P,Y,t,T,tau,N,C)),para,lb,ub);
a(i,:)=parag;
end
The problem seems to be that you're passing the result of a function call to minimize, rather than the function itself. The arguments get passed by the args parameter. So instead of:
minimize(GError_function_Price(para,y,k,t,T,tau,N,C),para,method='SLSQP',bounds=B)
the following should work
minimize(GError_function_Price,para,args=(y,k,t,T,tau,N,C),method='SLSQP',bounds=B)

Solving an ODE with scipy.integrate.solve_bvp, the return of my function is not able to be broadcast into the appropriate array shape for solve_bvp

I am trying to solve a second order ODE with solve_bvp. I have split the second order ODE into a system of tow first oder ODEs. I have a changing set of constants depending on the x (mesh) value. So I am passing these as an array of shape (N,) into my function numdens. While trying to run solve_bvp I get the error that the returns have different shapes namely (N,) and (N-1,) and thus cannot be broadcast into one array. But when I check each return back manually outside of the function it has the shape (N,).
If I run the solver without my changing constants I get a solution akin to the right one.
import numpy as np
from scipy.integrate import solve_bvp,odeint
import matplotlib.pyplot as plt
E_0 = 1 * 0.0000016021773 #erg: gcm^2/s^2
m_H = 1.6*10**(-24) #g
c = 3e11 #cm
sigma_c = 2*10**(-23)
n_0 = 1*10**(20) #1/cm^3
v_0 = (2*E_0/m_H)**(0.5) #cm/s
T = 10**7
b = 20.3
n_eq = b*T**3
n_s = 2.03*10**(19)
Q = 1
def velocity(v,x):
dvdx = -sigma_c*n_0*v_0*((8*v_0*v-7*v**2-v_0**2)/(2*v*c))
return dvdx
n_num = 100
x_num = np.linspace(-1*10**(6),3*10**(6), n_num)
sol_velo = odeint(velocity,0.999999999999*v_0,x_num)
sol_new = np.reshape(sol_velo,n_num)
def constants(v):
D1 = (c*v/(3*n_0*v_0*sigma_c))
D2 = ((v**2-8*v_0*v+v_0**2)/(6*v))
D3 = sigma_c*n_0*v_0*((8*v_0*v-7*v**2-v_0**2)/(2*v*c))
return D1,D2,D3
def numdens(x,y):
v = sol_new
D1,D2,D3 = constants(v)
return np.vstack((y[1],(-D2*y[1]-D3*y[0]+Q*((1-y[0])/n_eq))/(D1)))
def bc_num(ya, yb):
return np.array([ya[0]-n_s,yb[0]-n_eq])
y_num = np.array([np.linspace(n_s, n_eq, n_num),np.linspace(n_s, n_eq, n_num)])
sol_num = solve_bvp(numdens, bc_num, x_num, y_num)
plt.plot(sol_num.x, sol_num.y[0], label='$n(x)$')
plt.plot(x_num, sol_velo-v_0/7, label='$v(x)$')
plt.yscale('log')
plt.grid(alpha=0.5)
plt.legend(framealpha=1)
plt.show()
You need to take into account that the BVP solver uses an adaptive mesh. That is, after refining the initial guess on the initial grid the solver identifies regions with overly large errors and creates new mesh nodes there. As far as I have seen, the opposite is not implemented, even if it may be in some applications sensible to reduce the number of mesh nodes on especially "nice" segments.
Thus what you are doing the the numdens function is incomprehensible, it has to function exactly like any other function that you would pass to an ODE solver. If I had to propose some fast fix, and without knowing what the underlying problem is that you want to solve, I would change the assignment of v to
v = np.interp(x,x_num,sol_velo)
as that should at least produce an array of the correct format.

How to vectorize a function with array lookups

I'm trying to vectorize my fitness function for a Minimum Vector Cover genetic algorithm, but I'm at a loss about how to do it.
As it stands now:
vert_cover_fitness = [1 if self.dna[edge[0]] or self.dna[edge[1]] else -num_edges for edge in edges]
The dna is a one-dimensional binary array of size [0..n], where each index corresponds to a vertex, and its value indicates if we have chosen it or not. edges is a two dimensional positive integer array, where each value corresponds to a vertex (index) in dna. Both are ndarrays.
Simply explained - if one of the vertices connected by an edge is "selected", then we get a score of one. If not, the function is penalized by -num_edges.
I have tried np.vectorize as an attempt to get away cheap with a lambda function:
fit_func = np.vectorize(lambda edge: 1 if self.dna[edge[0]] or self.dna[edge[1]] else -num_edges)
vert_cover_fitness = fit_func(edges)
This returns IndexError: invalid index to scalar variable., as this function is applied to each value, and not each row.
To fix this I tried np.apply_along_axis. This works but it's just a wrapper for a loop so I'm not getting any speedups.
If any Numpy wizards can see some obvious way to do this, I would much appreciate your help. I'm guessing a problem lies with the representation of the problem, and that changing either the dna or edges shapes could help. I'm just not skilled enough to see what I should do.
I came up with this bit of numpy code, it runs 30x faster than your for loop on my randomly generated data.
import numpy as np
num_vertices = 1000
num_edges = 500
dna = np.random.choice([0, 1], num_vertices)
edges = np.random.randint(0, num_vertices, num_edges * 2).reshape(-1, 2)
vert_cover_fitness1 = [1 if dna[edge[0]] or dna[edge[1]] else -num_edges for edge in edges]
vert_cover_fitness2 = np.full([num_edges], -num_edges)
mask = (dna[edges[:, 0]] | dna[edges[:, 1]]).astype(bool)
vert_cover_fitness2[mask] = 1.0
print((vert_cover_fitness1 == vert_cover_fitness2).all()) # this shows it's correct
Here is the timeit code used to measure the speedup.
import timeit
setup = """
import numpy as np
num_vertices = 1000
num_edges = 500
dna = np.random.choice([0, 1], num_vertices)
edges = np.random.randint(0, num_vertices, num_edges*2).reshape(-1, 2)
"""
python_loop = "[1 if dna[edge[0]] or dna[edge[1]] else -num_edges for edge in edges]"
print(timeit.timeit(python_loop, setup, number=1000))
vectorised="""
vert_cover_fitness2 = np.full([num_edges], -num_edges)
mask = (dna[edges[:, 0]] | dna[edges[:, 1]]).astype(bool)
vert_cover_fitness2[mask] = 1.0
"""
print(timeit.timeit(vectorised, setup, number=1000))
# prints:
# 0.375906624016352
# 0.012783741112798452

Modified Gram Schmidt in Python for complex vectors

I wrote some code to implement the modified Gram Schmidt process. When
I tested it on real matrices, it is correct. However, when I tested it
on complex matrices, it went wrong.
I believe my code is correct by doing a step by step check. Therefore,
I wonder if there are numerical reasons why the modified Gram Schmidt
process fails on complex vectors.
Following is the code:
import numpy as np
def modifiedGramSchmidt(A):
"""
Gives a orthonormal matrix, using modified Gram Schmidt Procedure
:param A: a matrix of column vectors
:return: a matrix of orthonormal column vectors
"""
# assuming A is a square matrix
dim = A.shape[0]
Q = np.zeros(A.shape, dtype=A.dtype)
for j in range(0, dim):
q = A[:,j]
for i in range(0, j):
rij = np.vdot(q, Q[:,i])
q = q - rij*Q[:,i]
rjj = np.linalg.norm(q, ord=2)
if np.isclose(rjj,0.0):
raise ValueError("invalid input matrix")
else:
Q[:,j] = q/rjj
return Q
Following is the test code:
import numpy as np
# If testing on random matrices:
# X = np.random.rand(dim,dim)*10 + np.random.rand(dim,dim)*5 *1j
# If testing on some good one
v1 = np.array([1, 0, 1j]).reshape((3,1))
v2 = np.array([-1, 1j, 1]).reshape((3,1))
v3 = np.array([0, -1, 1j+1]).reshape((3,1))
X = np.hstack([v1,v2,v3])
Y = modifiedGramSchmidt(X)
Y3 = np.linalg.qr(X, mode="complete")[0]
if np.isclose(Y3.conj().T.dot(Y3), np.eye(dim, dtype=complex)).all():
print("The QR-complete gives orthonormal vectors")
if np.isclose(Y.conj().T.dot(Y), np.eye(dim, dtype=complex)).all():
print("The Gram Schmidt process is tested against a random matrix")
else:
print("But My modified GS goes wrong!")
print(Y.conj().T.dot(Y))
Update
The problem is that I implemented a algorithm designed for inner product linear in first argument
whereas I thought it were linear in second argument.
Thanks #landogardner
Your problem is to do with how numpy.vdot handles complex numbers — the complex conjugate of the first argument is used for the calculation (ref). So you're calculating rij as q*.Q[:,i] instead of q.Q[:,i]*. Just swap the order of the args:
rij = np.vdot(Q[:,i], q)
This got the test code working for me.

ValueError: setting an array element with a sequence symbolic

I am beginner with python. I have the following code:
import Deformation
import Qtheta
import numpy as np
import sympy as sp
def champs_de_contraintes(epaisseurs,angles,El,Et,Glt,Nult):
E0=np.mat('[0;0;0]') #inizialising E0
K=np.mat('[0;0;0]') #inizialising K
E0K=np.mat('[0;0;0;0;0;0]') #inizialising K
E0K = Deformation.defos(epaisseurs,angles,El,Et,Glt,Nult) #function that return a 6x1 matrix type <class 'numpy.matrixlib.defmatrix.matrix'>
E0=E0K[:3] #Slicing E0K into 2 vectors E0 and K
K=E0K[3:]
nb_composantes = 3 #sigma x, sigma y, taux xy
Sigmaxy=np.zeros((nb_composantes,len(epaisseurs))) #sigma x, sigma y, taux xy, Array
#===============This bloc calculate the altitude of a ply =================
z=[]
e=[]
z.append(-(np.sum(epaisseurs))/2)
for k in (range(len(epaisseurs))): #initialising e[k]
e[len(e):] = [0] #Values to add to get the altitude
for i in (range(len(epaisseurs))):
e[i]= e[i-1] + epaisseurs[i] #sum e
z[len(z):] = [z[0] + e[i]] #Altitude
#===========================This bloc calculate a vector===================
for i in (range(len(epaisseurs))):
newcolumn= Qtheta.Qtheta(angles[i],El,Et,Glt,Nult)*E0+z[i]*Qtheta.Qtheta(angles[i],El,Et,Glt,Nult)*K #z is the altitude
#3x1 = 3x3*3x1 + 1x1*3x3*3x1
for m in (range(len(newcolumn))):
Sigmaxy[i,m]=newcolumn[m]
return Sigmaxy
This returns me the error
Sigmaxy[i,m]=newcolumn[m]
ValueError: setting an array element with a sequence
Basically, what i want to do is to save the vector "newcolumn" in a newcolumn in the Sigmaxy matrix.
I think that I get this error because "newcolumn" is symbolic. Actually, E0 and K depend on 2 variables.
Could anybody help me with this one ?
Thanks in advance !
If you want to set elements of your array in this way, you need to make sure that the shapes are matching.
The error you get is thrown if you try something like this:
my_1d_array = np.array([1,2,3])
my_1d_array[0] = [4, 5, 6]
As the error explains, you are trying to set a single element to a sequence of elements, which is not possible. Debug your code, and make sure that the shapes (.shape) of Sigmaxy[i,m] and newcolumn[m] are matching.
Initialize your array with the correct size with space for all the elements in the beginning. If you don't know the exact size, you can create bigger arrays by adding columns, see other questions for this.

Categories