addgenconstrlog() constraint value is different from math.log value (Similar issue with addConstrExp( ) ))
AnsweredHi,
The m.addGenConstrLog(x,y) output result is not y = ln(x).
m.addGenConstrExp(x,y) output is not y = e^(x)
I am trying to solve the following problem.
But I keep getting Model is infeasible error. I suspect that the values inside ln( ) were going below 1.
So I tried to eliminate some terms in the objective function, ln(closs,cyc) to simplify and find the root cause. Now I only keep the simple ln(Ah,i,v) term. I even simplified the objective to 1.
When I query the values of ln( Ah,i,v) and Ah,i,v the values are not same as y = ln(x). It is shown in the print out.
import gurobipy as gp
from gurobipy import GRB
import math
Nv = 5
SOCdep = [0.36,0,0,0,0]
char_per = [8,0,0,0,0]
SOC_1 = [0.1,0,0,0,0]
del_t = 0.1
Cbat = [270]*5
t_s = 0
Imax = 100
Icmax = Nv*Imax
SOC_xtra = 0.01
soc_min = 0
soc_max = 1
Tiv = 30 # temperature
ks1 = -4.092*(10**-4)
ks2 = -2.167
ks3 = 1.408*(10**-5)
ks4 = 6.130
I_lim = 1
TT = []
for v in range(0,Nv):
TT.append( math.ceil((char_per[v] + t_s) / del_t) )
max_TT = max(TT)
m = gp.Model('bat_deg')
m.params.NonConvex = 2
m.params.Presolve = 0
m.reset(0)
# Decision variable declaration
I = []
for v in range(0,Nv):
I.append( m.addVars((TT[v]), vtype=GRB.CONTINUOUS) )
# upper_bound battery power constraint
bat_pwr_constr_l = []
for v in range(0,Nv):
for i in range(0,TT[v]):
bat_pwr_constr_l.append( m.addConstr( I[v][i] >= 0 ) )
# lower_bound battery power constraint
bat_pwr_constr_u = []
for v in range(0,Nv):
for i in range(0,TT[v]):
bat_pwr_constr_u.append( m.addConstr( I[v][i] <= Imax ) )
# slot power constraint
for i in range(0,max_TT):
slot_pwr = []
for v in range(0,Nv):
if i < TT[v]:
slot_pwr.append(I[v][i])
m.addConstr( sum(slot_pwr) <= Icmax )
# lower_bound Energy constraint
tot_char_curr = []
for v in range(0,Nv):
each_veh_curr = []
for i in range(0,TT[v]):
each_veh_curr.append(I[v][i])
tot_char_curr.append(I[v][i])
if(TT[v] > 0):
m.addConstr( ( sum(each_veh_curr) )* del_t >= (SOCdep[v] - SOC_1[v])*Cbat[v] )
print(v,i)
# upper_bound Energy constraint
for v in range(0,Nv):
each_veh_curr = []
for i in range(0,TT[v]):
each_veh_curr.append(I[v][i])
if(TT[v] > 0):
m.addConstr( ( sum(each_veh_curr) )* del_t <= (SOCdep[v] - SOC_1[v] + SOC_xtra)*Cbat[v] )
print(v,i)
Ah_log = []
for v in range(0,Nv):
Ah_log.append( m.addVars((TT[v]), vtype=GRB.CONTINUOUS) )
temp_ah = []
for v in range(0,Nv):
temp_ah.append( m.addVars((TT[v]), vtype=GRB.CONTINUOUS) )
for v in range(0,Nv):
for i in range(0,TT[v]):
m.addConstr(temp_ah[v][i], GRB.EQUAL, (I[v][i]*del_t) + I_lim )
m.addGenConstrLog(temp_ah[v][i], Ah_log[v][i])
Ah_array = []
for v in range(0,Nv):
for i in range(0,TT[v]):
Ah_array.append(Ah_log[v][i])
m.setObjective( 1 , GRB.MINIMIZE)
#m.setObjective( sum(B_array + Ah_array + Crate_array + b1_array + SOC_array + d_array + a1_a2_array), GRB.MINIMIZE)
m.update()
m.optimize()
print('\n')
for v in range(0,Nv):
for i in range(0,TT[v]):
print(temp_ah[v][i].x)
print((Ah_log[v][i]).x)
print(math.log(temp_ah[v][i].x) )

How is ln(11) equal to 0.0102292663 ?
I am also trying to print exponential term values as shown below and find them to be different.
exp1 = []
for v in range(0,Nv):
exp1.append( m.addVars((TT[v]), vtype=GRB.CONTINUOUS) )
temp1 = []
for v in range(0,Nv):
temp1.append( m.addVars((TT[v]), vtype=GRB.CONTINUOUS, lb = -1000) )
for v in range(0,Nv):
for i in range(0,TT[v]):
#bat_vbat = m.addVar(vbat_min,vbat_max,name="bat_SOC")
#temp1[v][i] == ks2*(SOC_avg[v][i])
m.addConstr(temp1[v][i], GRB.EQUAL, ks2*SOC_avg[v][i] )
m.addGenConstrExp(temp1[v][i], exp1[v][i])
print(temp1[v][i].x)
print(math.exp(temp1[v][i].x) )
print(exp1[v][i].x)
Please help me. I need to start with the bigger objective ASAP.
Thanks.
-
This looks like a bug. Thanks for reporting! I will investigate and check what is going on.
Tobias
0 -
This is actually not a bug. It is due to the large (actually, infinite) domains of your variables and the consequences that this has for the piece-wise linear approximation that we use for the log constraint.
If you use general function constraints (like log, exp, sin, cos, tan) then you should really try to specify the domain of the argument variable (x) as precisely as possible. If you know that your argument variables will only be, e.g., inside [0,100], then you should specify those bounds when you create the variables.
The reason is that the function constraints are converted into a piece-wise linear approximation. You can specify exactly how this approximation should be done, using the "FuncPieceError", "FuncPieceLength", "FuncPieceRatio", and "FuncPieces" attributes. If you don't, Gurobi tries to do something reasonable as a tradeoff between approximation error and resulting model size. In your case with the infinite domain, we arbitrarily restrict the domains of the argument variables to [0,1000000]. Then, we limit the total number of pieces for the PWL approximation in the model. This yields a piece length of 8888 for your y = ln(x) functions. Consequently, in particular the first piece of each function is a very very rough approximation. Because y >= 0, we can infer x >= 1, so that the first piece is the secant in [1,8889], which is y_0 = ln(8889) * (x-1)/8888.
Thus, you get y_0(11) = 0.01 even though ln(11) = 2.39.
If you keep presolve enabled, then Gurobi finds much tighter bounds and is thus able to produce a much better approximation with the same number of pieces.
But you should really restrict the domains of the argument variables.
Regards,
Tobias
0 -
Thanks Tobias. I have used lb and ub for all my variables. Now 'exp' and 'log' are working as expected. However, the solutions take some time to compute as shown below. Do you think anything is unusal in the execution log below?
I don't know the meaning of the following: Nodes | Current Node | Objective Bounds | Work
Do you think I can increase the speed by specifying "FuncPieceError", "FuncPieceLength", "FuncPieceRatio", and "FuncPieces" attributes as well?
Thanks.
0 -
The log file looks okay. It seems pretty difficult to find a feasible solution for your model.
What you see in the table is the output of the branch-and-bound tree search. The algorithm successively divides your problem into smaller sub-problems until a sub-problem is small or easy enough so that Gurobi can find an optimal solution to that sub-problem or prove that no feasible solution can exist in this sub-problem. This branch-and-bound process generates a search tree, with the "Expl" column telling you how many nodes of this search tree have already been processed, and the "Unexpl" telling you how many open nodes still exist in the tree.
The "Func*" attributes are about the tradeoff between precision and performance. The more pieces are used to approximate a non-linear function, the more accurate will the approximation be, but also the more difficult it will be to solve the resulting model.
0
Please sign in to leave a comment.
Comments
4 comments