Using logarithmic in the objective function in IBM CPLEX - python

My objective function in IBM CPLEX is as follows:
objective = opt_model.sum(math.log(r_vars[0,0]*(3*w_vars[0]-1))+math.log(r_vars[1,0]*(3*w_vars[0]-1)))
opt_model.maximize(objective)
The variable w_vars can get a value in the range [0,1] and the value of r_vars can be in the range of [1,100]. But I am getting this error:
TypeError: must be real number, not QuadExpr
I assume the problem is the result of the parentheses for the math.log function. How can I use a log function in the objective function in IBM CPLEX? Or any thoughts on this?

What you could do is rely on cpo within Cplex
See
https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoononlinear.py
For a tiny example
from docplex.cp.model import CpoModel
mdl = CpoModel(name='buses')
nbbus40 = mdl.integer_var(0,1000,name='nbBus40')
nbbus30 = mdl.integer_var(0,1000,name='nbBus30')
mdl.add(nbbus40*40 + nbbus30*30 >= 300)
#non linear objective
mdl.minimize(mdl.exponent(nbbus40)*500 + mdl.exponent(nbbus30)*400)
msol=mdl.solve()
print(msol[nbbus40]," buses 40 seats")
print(msol[nbbus30]," buses 30 seats")

Related

How to define a custom cost function for Pulp library

I am trying to use a custom cost function for using the PuLP Python library(https://realpython.com/linear-programming-python/). However I am not sure how to use extract my optimization variables. The objective function has a model I am trying to tune that has both integer and continues parameters
def opt_funct(bins, reg):
return some_calcuation(bins, reg) #returns some integer
model = pulp.LpProblem(name="small-problem", sense=pulp.LpMinimize)
bins = pulp.LpVariable(name="bins", lowBound=1, upBound=100, cat='Integer')
reg = pulp.LpVariable(name="reg", lowBound=0.0001, upBound=1.0, cat='Continues')
model += opt_funct(bins, reg)
status = model.solve()
The problem seems to be that variables are in some PuLP variable format. How can I use the variables for my own functions?

How could constraints be dynamically constructed in gekko?

I'm a newbie in gekko, and want to use it in my linear programming problems.
I have variable names, costs, minimum and maximum bounds in separate dictionaries (my_vars, Cost, Min and Max) with variable names as their keys, and the objective is minimizing total cost with determining the amount of variables satisfying the constraints.
I did as below;
LP = GEKKO(remote=False)
vars = LP.Array(LP.Var, (len(my_vars)))
i=0
for xi in vars:
xi.lower = Min[list(my_vars)[i]]
xi.upper = Max[list(my_vars)[i]]
i += 1
Here I'd like to use variable original names instead of xi, is there any way?
it continues as;
LP.Minimize(sum(float(Cost[list(my_vars)[i]])*vars[i] for i in range(len(my_vars))))
LP.Equation(sum(vars) == 100)
Also I have constraint's left hand side (LHS) (coefficients of variables) and right hand side (RHS) numbers in two pandas data frame files, and like to construct equations using a for loop.
I don't know how to do this?
Here is one way to use your dictionary values to construct the problem:
from gekko import GEKKO
# stored as list
my_vars = ['x1','x2']
# stored as dictionaries
Cost = {'x1':100,'x2':125}
Min = {'x1':0,'x2':0}
Max = {'x1':70,'x2':40}
LP = GEKKO(remote=False)
va = LP.Array(LP.Var, (len(my_vars))) # array
vd = {} # dictionary
for i,xi in enumerate(my_vars):
vd[xi] = va[i]
vd[xi].lower = Min[xi]
vd[xi].upper = Max[xi]
# Cost function
LP.Minimize(LP.sum([Cost[xi]*vd[xi] for xi in my_vars]))
# Summation as an array
LP.Equation(LP.sum(va)==100)
# This also works as a dictionary
LP.Equation(LP.sum([vd[xi] for xi in my_vars])==100)
LP.solve(disp=True)
for xi in my_vars:
print(xi,vd[xi].value[0])
print ('Cost: ' + str(LP.options.OBJFCNVAL))
This produces a solution:
EXIT: Optimal Solution Found.
The solution was found.
The final value of the objective function is 10750.00174236579
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 0.012199999999999996 sec
Objective : 10750.00174236579
Successful solution
---------------------------------------------------
x1 69.999932174
x2 30.0000682
Cost: 10750.001742
Here are a few examples of efficient linear programming with Gekko by exploiting problem sparsity.

Issue with Mixed Integer Non-Linear Programming problem in GEKKO

I am using GEKKO for solving an MINLP problem in Python that involves a co-simulation with PowerFactory, a power system simulation software. The MINLP problem objective function needs to call PowerFactory from within and execute particular tasks before returning the values to the MILP problem definition. In the equality constraint definition, I need to also use two Pandas data frames (tables with 10000x2 cells) to get particular values corresponding to the values of the decision variables in the constraint expression. But, I am getting errors while writing any code involving loops, or Pandas 'loc' or 'iloc' functions, within the objective/constraint functions due to some issues with the nature of GEKKO variables in these function calls. Any help in this regard would be much appreciated. The structure of the code is given below:
import powerfactory as pf
from gekko import GEKKO
import pandas as pd
# Execute the PF setup commands for Python
# Pandas dataframe in question
df1 = pd.read_csv("table1.csv")
df2 = pd.read_csv("table2.csv")
def constraint1(X):
P = 0
for i in range(length(X)):
V = X[i] * 1000
D = round(V, 1)
P += df1.loc[D, "ColumnName"]
return P
def objective(X):
for i in range(length(X)):
V = X[i] * 1000
D = round(V, 1)
I = df2.loc[D, "ColumnName"]
# A list with the different values of 'I' is generated for passing to PF
# Some PowerFactory based commands below, involving inputs, and extracting results from PF, using a list generated from the values of 'I'. PF returns some result values to the code
return results
# MINLP problem definition:
m = GEKKO(remote=False)
x = m.Array(m.Var, nInv, value=1.0, lb=0.533, ub=1.0)
m.Equation(constraint1(x) == 30)
m.Minimize(objective(x))
m.options.SOLVER = 3
m.solve(disp=False)
# Command for exporting the results to a .txt file
In another problem formulation, I am trying to run MINLP optimization problems within the objective and constraint function as a nested optimization problem. However, I am running into errors in that as well. The structure of the code is as follows:
import powerfactory as pf
from gekko import GEKKO
# Execute the PF setup commands for Python
def constraint1(X):
P = 0
for i in range(length(X)):
V = X[i] * 1000
# 2nd MINLP problem: Finds 'I' from value of 'V', a single element
# Calculate 'Pcal' from 'I'
P += Pcal
return P
def objective(X):
Iset = []
for i in range(length(X)):
V = X[i] * 1000
# 3rd MINLP problem: Finds 'I' from value of 'V'
# Appends 'I' to a 'Iset'
# 'Iset' list passed on to PF
# Some PowerFactory based commands below, involving inputs, and extracting results from PF, using the 'Iset' list. PF returns some result values to the code
return results
# Main MINLP problem definition:
m = GEKKO(remote=False)
x = m.Array(m.Var, nInv, value=1.0, lb=0.533, ub=1.0)
m.Equation(constraint1(x) == 30)
m.Minimize(objective(x))
m.options.SOLVER = 3
m.solve(disp=False)
# Command for exporting the results to a .txt file
Gekko does not have call-backs to external functions. This is because the solvers are gradient-based and a precursor steps is automatic differentiation to obtain exact 1st and 2nd derivatives in sparse form. Similar to Gekko and CoolProp, one option is to build an approximation to your external (in this case PowerFactory) model that the optimizer can use. Two options are the cubic spline (cspline) or the basis spline (bspline).
If you can't use these approximations then I recommend switching to a different platform for solving the optimization problem. Perhaps you could try scipy.optimize.minimize that can obtain gradients by finite difference and add branch and bound to solve the mixed integer portion.

Network Flow Optimimization (Gurobi)

I am trying to model and solve an optimization problem, with python and gurobi optimizer. It is my first experience to solve a problem using optimizer. firstly I wrote a really big problem and add all variables and constraints, step by step. But there was problem(S) in that. so I reduce the problem to the small version, again and again. After all, now I have a very simple code:
from gurobipy import *
m = Model('net')
x = m.addVar(name = 'x')
y = m.addVar(name = 'y')
m.addConstr(x >= 0 and x <= 9000, name = 'flow0')
m.addConstr(y >= 0 and y <= 1000, name = 'flow1')
m.addConstr(y + x == 9990, name = 'total_flow')
m.setObjective(x *(4 + 0.6*(x/9000)) + (y * (4 + 0.6*(y/1000))), GRB.MINIMIZE)
solo = m.optimize()
if solo:
print ('find!!!')
It actually is a simple network flow problem (for a graph with two nodes and two edges) I want to calculate the flow of each edge (x and y). Obviously the flow of each edge cant be negative and cant be bigger than edge capacity(x(capa) = 9000, y(capa) = 1000). and the third constraint shows the the total flow limitation on both edges. Finally, the objective function has to minimize the equation.
Now I have some question on this code:
why 'solo' is (None)?
How can I print solution variables. I used getAttr() function. but I couldn't find out the role of variables name (x, y or flow0, flow1)
3.Ive got this result. But I really cant understand this!!!!
for example: what dose it calculate in each iteration??!
Tnx in advance, and excuse for my simple question...
The optimize() method always returns None, see print(help(m.optimize)). The status of your model after calling this method is stored in m.status while the solution values are stored in the .X attribute for each variable (assumed the model was solved to optimality). To access them you can use m.getVars():
# your model ...
m.optimize()
if m.status = GRB.OPTIMAL:
for var in m.getVars():
print(var.VarName, var.X)
Your posted log shows for each iteration of the barrier method (also known as interior point method) the objective value. See here for a detailed overview.

How to define General deterministic function in PyMC

In my model, I need to obtain the value of my deterministic variable from a set of parent variables using a complicated python function.
Is it possible to do that?
Following is a pyMC3 code which shows what I am trying to do in a simplified case.
import numpy as np
import pymc as pm
#Predefine values on two parameter Grid (x,w) for a set of i values (1,2,3)
idata = np.array([1,2,3])
size= 20
gridlength = size*size
Grid = np.empty((gridlength,2+len(idata)))
for x in range(size):
for w in range(size):
# A silly version of my real model evaluated on grid.
Grid[x*size+w,:]= np.array([x,w]+[(x**i + w**i) for i in idata])
# A function to find the nearest value in Grid and return its product with third variable z
def FindFromGrid(x,w,z):
return Grid[int(x)*size+int(w),2:] * z
#Generate fake Y data with error
yerror = np.random.normal(loc=0.0, scale=9.0, size=len(idata))
ydata = Grid[16*size+12,2:]*3.6 + yerror # ie. True x= 16, w= 12 and z= 3.6
with pm.Model() as model:
#Priors
x = pm.Uniform('x',lower=0,upper= size)
w = pm.Uniform('w',lower=0,upper =size)
z = pm.Uniform('z',lower=-5,upper =10)
#Expected value
y_hat = pm.Deterministic('y_hat',FindFromGrid(x,w,z))
#Data likelihood
ysigmas = np.ones(len(idata))*9.0
y_like = pm.Normal('y_like',mu= y_hat, sd=ysigmas, observed=ydata)
# Inference...
start = pm.find_MAP() # Find starting value by optimization
step = pm.NUTS(state=start) # Instantiate MCMC sampling algorithm
trace = pm.sample(1000, step, start=start, progressbar=False) # draw 1000 posterior samples using NUTS sampling
print('The trace plot')
fig = pm.traceplot(trace, lines={'x': 16, 'w': 12, 'z':3.6})
fig.show()
When I run this code, I get error at the y_hat stage, because the int() function inside the FindFromGrid(x,w,z) function needs integer not FreeRV.
Finding y_hat from a pre calculated grid is important because my real model for y_hat does not have an analytical form to express.
I have earlier tried to use OpenBUGS, but I found out here it is not possible to do this in OpenBUGS. Is it possible in PyMC ?
Update
Based on an example in pyMC github page, I found I need to add the following decorator to my FindFromGrid(x,w,z) function.
#pm.theano.compile.ops.as_op(itypes=[t.dscalar, t.dscalar, t.dscalar],otypes=[t.dvector])
This seems to solve the above mentioned issue. But I cannot use NUTS sampler anymore since it needs gradient.
Metropolis seems to be not converging.
Which step method should I use in a scenario like this?
You found the correct solution with as_op.
Regarding the convergence: Are you using pm.Metropolis() instead of pm.NUTS() by any chance? One reason this could not converge is that Metropolis() by default samples in the joint space while often Gibbs within Metropolis is more effective (and this was the default in pymc2). Having said that, I just merged this: https://github.com/pymc-devs/pymc/pull/587 which changes the default behavior of the Metropolis and Slice sampler to be non-blocked by default (so within Gibbs). Other samplers like NUTS that are primarily designed to sample the joint space still default to blocked. You can always explicitly set this with the kwarg blocked=True.
Anyway, update pymc with the most recent master and see if convergence improves. If not, try the Slice sampler.

Categories