Create arrays of variables in loop GEKKO - optimization

I'm wondering if it is possible to create arrays of variables with different lenghts in a loop in GEKKO.
Below is just a simple example of what I mean. Parameters in the list "lengths" define what length each GEKKO array should have:
lengths = [10,20,30]
m = GEKKO()
for i in lengths:
# something...
So from this I would like to get something like:
array1 = m.Array(m.Var,10)
array2 = m.Array(m.Var,20)
array3 = m.Array(m.Var,30)
In the real problem that I'm trying to solve there will be quite many arrays that I want to include in the optimization, and they might be different depending on the situation. So it is not a good option to manually create them every time.

There is no problem to define arrays in a loop. Here is an example:
from gekko import GEKKO
model = GEKKO(remote=True)
lengths = [10,20,30]
m = GEKKO()
x = []
for i in lengths:
x.append(m.Array(m.Var,i))
for j in range(i):
m.Minimize((x[-1][j]-j)**2)
m.solve()
for xi in x:
print(xi)
This gives a unique solution where the value is equal to the index.
This is Ipopt version 3.12.10, running with linear solver ma57.
Number of nonzeros in equality constraint Jacobian...: 0
Number of nonzeros in inequality constraint Jacobian.: 0
Number of nonzeros in Lagrangian Hessian.............: 60
Total number of variables............................: 60
variables with only lower bounds: 0
variables with lower and upper bounds: 0
variables with only upper bounds: 0
Total number of equality constraints.................: 0
Total number of inequality constraints...............: 0
inequality constraints with only lower bounds: 0
inequality constraints with lower and upper bounds: 0
inequality constraints with only upper bounds: 0
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 1.1310000e+04 0.00e+00 5.80e+01 0.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 0.0000000e+00 0.00e+00 0.00e+00 -11.0 2.90e+01 - 1.00e+00 1.00e+00f 1
Number of Iterations....: 1
(scaled) (unscaled)
Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00
Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00
Overall NLP error.......: 0.0000000000000000e+00 0.0000000000000000e+00
Number of objective function evaluations = 2
Number of objective gradient evaluations = 2
Number of equality constraint evaluations = 0
Number of inequality constraint evaluations = 0
Number of equality constraint Jacobian evaluations = 0
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations = 1
Total CPU secs in IPOPT (w/o function evaluations) = 0.001
Total CPU secs in NLP function evaluations = 0.000
EXIT: Optimal Solution Found.
The solution was found.
The final value of the objective function is 0.000000000000000E+000
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 4.600000000209548E-003 sec
Objective : 0.000000000000000E+000
Successful solution
---------------------------------------------------
[[0.0] [1.0] [2.0] [3.0] [4.0] [5.0] [6.0] [7.0] [8.0] [9.0]]
[[0.0] [1.0] [2.0] [3.0] [4.0] [5.0] [6.0] [7.0] [8.0] [9.0] [10.0] [11.0]
[12.0] [13.0] [14.0] [15.0] [16.0] [17.0] [18.0] [19.0]]
[[0.0] [1.0] [2.0] [3.0] [4.0] [5.0] [6.0] [7.0] [8.0] [9.0] [10.0] [11.0]
[12.0] [13.0] [14.0] [15.0] [16.0] [17.0] [18.0] [19.0] [20.0] [21.0]
[22.0] [23.0] [24.0] [25.0] [26.0] [27.0] [28.0] [29.0]]

Related

Constraint saying all elements of vector has to be >= 0 in scipy optimization

The input vector is x, which contains 5 elements and I want to optimize (minimize) a function with a constraint that all elements of x should be greater than or equal to 0.
ie., x[i] >= 0 for 1 <= i <= 5
In one of the answer I saw this and used in my code, but the answer is returning negative values also
def constraint2(x):
"""constrain all elements of a to be >= 0"""
return x
cons2 = {'type': 'ineq', 'fun': constraint2}
Where am I going wrong? How to enforce the constraint?
all(ele >= 0 for ele in x)
Try this

scipy minimization with more complex marketing function

I am new to scipy minimize. I want to minimize a function. There are 2 vectors in play :
x : 4 element vector of spending
y : 4 element vector of cost per customer
each element in y is defined something like 50 from 0 to 100000, and 0.0005 * X from 100000 to infinity
The objective function is to minimize the spend :
def objective(x):
x1=x[0]
x2=x[1]
x3=x[2]
x4=x[3]
return x1+x2+x3+x4
As the constraint I have the number of users I have to sign up for like this :
def constraint1(x,y):
x[0]/y[0]+x[1]/y[1]+x[2]/y[2]+x[3]/y[3]>5035
bounds and definition like this
b=(0,1000000)
bnds=(b,b,b,b)
con1={'type': 'ineq', 'fun': constraint1}
x0=[20000,20000,20000,20000]
sol= minimize(objective,x0, method= "SLSQP",bounds=bnds,constraints=con1)
I simply do not know to define the Y vector properly. Any feedback or help wound be very much appreciated .

Optimizing a Summation function - GEKKO

I just started learning optimization and I have some issues finding the optimal value for the problem below.
Note: This is just a random problem that came to my mind and has no real application.
Problem:
where x can be any value from the list ([2,4,6]) and y is between 1 and 3.
My attempt:
from gekko import GEKKO
import numpy as np
import math
def prob(x,y,sel):
z = np.sum(np.array(x)*np.array(sel))
cst = 0
i=0
while i <= y.VALUE:
fact = 1
for num in range(2, i + 1): # find the factorial value
fact *= num
cst += (z**i)/fact
i+=1
return cst
m = GEKKO(remote=False)
sel = [2,4,6] # list of possible x values
x = m.Array(m.Var, 3, **{'value':1,'lb':0,'ub':1, 'integer': True})
y = m.Var(value=1,lb=1,ub=3,integer=True)
# switch to APOPT
m.options.SOLVER = 1
m.Equation(m.sum(x) == 1) # restrict choice to one selection
m.Maximize(prob(x,y,sel))
m.solve(disp=True)
print('Results:')
print(f'x: {x}')
print(f'y : {y.value}')
print('Objective value: ' + str(m.options.objfcnval))
Results:
----------------------------------------------------------------
APMonitor, Version 0.9.2
APMonitor Optimization Suite
----------------------------------------------------------------
--------- APM Model Size ------------
Each time step contains
Objects : 0
Constants : 0
Variables : 4
Intermediates: 0
Connections : 0
Equations : 2
Residuals : 2
Number of state variables: 4
Number of total equations: - 1
Number of slack variables: - 0
---------------------------------------
Degrees of freedom : 3
----------------------------------------------
Steady State Optimization with APOPT Solver
----------------------------------------------
Iter: 1 I: 0 Tm: -0.00 NLPi: 2 Dpth: 0 Lvs: 0 Obj: -7.00E+00 Gap: 0.00E+00
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 0.024000000000000004 sec
Objective : -7.
Successful solution
---------------------------------------------------
Results:
x: [[0.0] [0.0] [1.0]]
y : [1.0]
Objective value: -7.0
x should be [0,0,1] (i.e. 6) and y should be 3 to get the maximum value (61). x value I get is correct but for some reason the y value I get is wrong. What is causing this issue ? Is there something wrong with my formulation ? Also it would be very helpful if you could kindly point me towards more information about the various notations (like Tm, NLPi, etc) in APOPT solver output.
Here is a solution in gekko:
x=6.0
y=3.0
You'll need to use the gekko functions to build the functions and pose the problem in a way so that the equations don't change as the variable values change.
from gekko import GEKKO
import numpy as np
from scipy.special import factorial
m = GEKKO(remote=False)
x = m.sos1([2,4,6])
yb = m.Array(m.Var,3,lb=0,ub=1,integer=True)
m.Equation(m.sum(yb)==1)
y = m.sum([yb[i]*(i+1) for i in range(3)])
yf = factorial(np.linspace(0,3,4))
obj = x**0/yf[0]
for j in range(1,4):
obj += x**j/yf[j]
m.Maximize(yb[j-1]*obj)
m.solve()
print('x='+str(x.value[0]))
print('y='+str(y.value[0]))
print('Objective='+str(-m.options.objfcnval))
For your problem, I used a Special Ordered Set (type 1) to get the options of 2, 4, or 6. To select y as 1, 2, or 3 I calculated all possible values and then used a binary selector yb to choose one. There is a constraint that only one of them can be used with m.sum(yb)==1. There are gekko examples, documentation, and a short course available if you need additional resources.
Here is the solver output:
----------------------------------------------------------------
APMonitor, Version 0.9.2
APMonitor Optimization Suite
----------------------------------------------------------------
--------- APM Model Size ------------
Each time step contains
Objects : 1
Constants : 0
Variables : 11
Intermediates: 1
Connections : 4
Equations : 10
Residuals : 9
Number of state variables: 11
Number of total equations: - 7
Number of slack variables: - 0
---------------------------------------
Degrees of freedom : 4
----------------------------------------------
Steady State Optimization with APOPT Solver
----------------------------------------------
Iter: 1 I: 0 Tm: 0.00 NLPi: 6 Dpth: 0 Lvs: 0 Obj: -6.10E+01 Gap: 0.00E+00
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 0.047799999999999995 sec
Objective : -61.
Successful solution
---------------------------------------------------
x=6.0
y=3.0
Objective=61.0
Here is more information on the solver APOPT options. The iteration summary describes the branch and bound progress. It is Iter=iteration number, Tm=time to solve the NLP, NLPi=NLP iterations, Dpth=depth in the branching tree, Lvs=number of candidates leaves, Obj=NLP solution objective, and Gap=gap between integer solution and best non-integer solution.
equation to be minimzedhey how to solve these type of prolems
problem:
Minimization
summation(xij*yij)
i=from 0 to 4000
j= from 0 to 100
y is coast matrix given
m = GEKKO(remote=False)
dem_var = m.Array(m.Var,(4096,100),lb=0)
for i,j in s_d:
m.Minimize(sum([dem_var[i][j]*coast_new[i][j]]))
here y=coast_new
x= dem_var

CPLEX and MOSEK with YALMIP gives different results

I am solving an optimization problem using MATLAB with YALMIP which is similar to a unit commitment problem.
This is a Mixed Integer Linear Programming problem.
I am considering two decision variables --> P and T_room
I formulated the problem in MATLAB with YALMIP,
When I use CPLEX and MOSEK solvers, I am getting different results.
Can anyone explain to me why that is happening?
CPLEX solver results
MOSEK solver results
clc;
clear all;
rng(0,'twister');
%% time step of the demand response --> 15 mins
deltaT = 15/60 ;
%% number of air conditioners
Nunits = 3;
%% demand required for each interval
Pdemand = [2 3 4 2 5 5 8 9]';
% Pdemand = randi([2,10],8,1);
%% time interval considered for the study --> 15 mins intervals for 2
%%% hours
Horizon = length(Pdemand) ;
%% cost for each appliance ( need to think little about this approach )
Q = diag([rand(1,Nunits)]);
%% defining the possible reduction levels for the appliances
% ratedPower = [1 6 4]';
ratedPower = randi([5,7],Nunits,1);
%% defining minimum and maximum power limits for the appliances
Pmax = randi([6,8],Nunits,1);
Pmin = zeros(Nunits,1);
% possible power levels for appliances (discrete levels)
LevelsOutput = [0 0.5 0.75 1.0] ;
% matrix containing all the possible levels of output power for all the
%% appliances
PowerLevelMatrix = ratedPower * LevelsOutput ;
%% parameters based on the temperature
%%% outside temperature (we assume that the outdoor temperature remains the same throughout the optimisation process)
T_outdoor = randi([34, 38], Nunits,1);
%%% preferred lower level of temperature for the appliances
T_lower = randi([20,21], Nunits,1) ;
%%% preferred upper level of temperature for the appliances
T_upper = randi([28, 29], Nunits,1) ;
%%% initial temperature for the appliances
T_initial = randi([22, 28], Nunits,1);
%% parameters of the house
%% equivalent thermal resistance
R = (2.5-1.5)*rand(Nunits,1) + 1.5 ;
%%% equivalent thermal capacitance
Ca = (2.5-1.5)*rand(Nunits,1) + 1.5 ;
%% for the air condtioner
c = repmat(0.03,Nunits,1);
d = repmat(-0.4,Nunits,1);
a = repmat(0.06,Nunits,1);
b = repmat(-0.3,Nunits,1);
%% defining the variables of the demand response problem
%%% power levels for the appliances
P = sdpvar(Nunits, Horizon, 'full');
%% slack variable for exceeding the demand
% Demand_Penalty = 50;
% DemandSlack = sdpvar(1,Horizon);
%% decision variable for the room temperature
T_room = sdpvar(Nunits,Horizon,'full') ;
%% Constraints for the optimisation problem
Constraints = [];
for k = 1: Horizon
% Constraints = [Constraints, sum(P(:,k)) + DemandSlack(k) >= Pdemand(k)];
% Constraints = [Constraints,DemandSlack(k) >= 0];
Constraints = [Constraints, sum(P(:,k))>= Pdemand(k)];
end
%%% constraint on min amd max power levels
for k = 1: Horizon
Constraints = [Constraints, Pmin <= P(:,k) <= Pmax];
end
%%% adding the constraint on discrete power levels for each appliance
for nApp = 1 : Nunits
for k = 1 : Horizon
Constraints = [Constraints, ismember(P(nApp,k),PowerLevelMatrix(nApp,:))];
end
end
%% the temperature should be within the desired limits --> cannot go beyond those limits
for k = 2: Horizon
Constraints = [Constraints, T_lower <= T_room(:,k) <= T_upper ];
end
%% adding the initial constraint of temperature
Constraints = [Constraints, T_room(:,1) == T_initial];
%%% adding the temperature model of the constraint for the inverter type
%%% air condtioner
for k = 2: Horizon
Constraints = [Constraints, T_room(:,k) == T_outdoor - ((a./c).*P(:,k) + ((b.*c - a.*d)./c)).*R.*(1- exp((-deltaT)./(R.*Ca))) - T_outdoor.* exp((-deltaT)./(R.*Ca)) + T_room(:,k-1).* exp((-deltaT)./(R.*Ca)) ];
end
%% adding a sample constraints to the temperature update
% for k =2: Horizon
%
% Constraints = [Constraints, T_room(:,k) == T_room(:,k-1) ];
% end
%%% defining the objective function
% weighting factors
alpha = 1 ;
beta = 1 ;
Objective = 0 ;
for k = 2 : Horizon
Objective = Objective + alpha * Q * P(:,k) + beta * ((2* T_room(:,k) - T_lower - T_upper)./(T_upper - T_lower));
% Objective = Objective + P(:,k)' * Q * P(:,k);
% Objective = Objective + Demand_Penalty * DemandSlack(k) ;
end
%%% solving the optimisation problem
%
ops = sdpsettings('verbose',2, 'debug', 1, 'solver', 'mosek');
% ops = sdpsettings('verbose',1, 'debug', 1);
solution = optimize (Constraints, Objective, ops) ;
Pout = value(P);
T_room_out = value(T_room);
Your code does not make sense to begin with, as your objective is a vector
>> Objective
Linear matrix variable 3x1 (full, real, 42 variables)
With that, YALMIP will solve three optimization problems, and then values you obtain when applying value command will be the values from the last solution.
Having said that, concentrating on the last objective you have defined (although I think you intended to minimize the sum or something), I get the same objective with both solvers (not the same solution, the solution simply isn't unique)
>> solution = optimize (Constraints, Objective(3), sdpsettings('solver','cplex'))
>> value(Objective(3))
ans =
1.8418
>> value(P)
ans =
0 5.2500 3.5000 5.2500 3.5000 5.2500 5.2500 5.2500
0 3.0000 3.0000 6.0000 6.0000 6.0000 3.0000 4.5000
5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 0 0
>> solution = optimize (Constraints, Objective(3), sdpsettings('solver','mosek'))
>> value(Objective(3))
ans =
1.8418
ans =
3.5000 3.5000 3.5000 3.5000 3.5000 3.5000 5.2500 5.2500
3.0000 3.0000 3.0000 3.0000 6.0000 0 3.0000 6.0000
3.7500 5.0000 5.0000 5.0000 5.0000 5.0000 0 0

How to add magnitude or value to a vector in Python?

I am using this function to calculate distance between 2 vectors a,b, of size 300, word2vec, I get the distance between 'hot' and 'cold' to be equal 1.
How to add this value (1) to a vector, becz i thought simply new_vec=model['hot']+1, but when I do the calc dist(new_vec,model['hot'])=17?
import numpy
def dist(a,b):
return numpy.linalg.norm(a-b)
a=model['hot']
c=a+1
dist(a,c)
17
I expected dist(a,c) will give me back 1!
You should review what the norm is. In the case of numpy, the default is to use the L-2 norm (a.k.a the Euclidean norm). When you add 1 to a vector, the call is to add 1 to all of the elements in the vector.
>> vec1 = np.random.normal(0,1,size=300)
>> print(vec1[:5])
... [ 1.18469795 0.04074346 -1.77579852 0.23806222 0.81620881]
>> vec2 = vec1 + 1
>> print(vec2[:5])
... [ 2.18469795 1.04074346 -0.77579852 1.23806222 1.81620881]
Now, your call to norm is saying sqrt( (a1-b1)**2 + (a2-b2)**2 + ... + (aN-bN)**2 ) where N is the length of the vector and a is the first vector and b is the second vector (and ai being the ith element in a). Since (a1-b1)**2 == (a2-b2)**2 == ... == (aN-bN)**2 == 1 we expect this sum to produce N which in your case is 300. So sqrt(300) = 17.3 is the expected answer.
>> print(np.linalg.norm(vec1-vec2))
... 17.320508075688775
To answer the question, "How to add a value to a vector": you have done this correctly. If you'd like to add a value to a specific element then you can do vec2[ix] += value where ix indexes the element that you wish to add. If you want to add a value uniformly across all elements in the vector that will change the norm by 1, then add np.sqrt(1/300).
Also possibly relevant is a more commonly used distance metric for word2vec vectors: the cosine distance which measures the angle between two vectors.