How to define a custom cost function for Pulp library - python

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?

Related

Using logarithmic in the objective function in IBM CPLEX

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")

How to view Gekko variables/parameters for debug purposes?

I have a fitting task where I am using GEKKO.
There are a lot of variables, arrays of variables, some variables that must contain arrays, and so on.
I didn't have success with the fitting,
so I need to do step-by-step verification of all parameters that I am providing for GEKKO and all the calculated intermediate values.
Is there a way to print out the values of each variable for debugging purposes?
Or to view the values of the variables in line-by-line execution?
for example, I have an array that is saved like a variable ro:
phi = model.Intermediate( c * ro) # phase shift
where c is some constant defined somewhere above in the model definition.
How can I view the values inside phi that will be used in the next steps?
I need to view/save all the values of all variables/constants/intermediates used during the model creation - before a try to solve. Is it possible?
Turn up the DIAGLEVEL to 2 or higher to produce diagnostic files in the run directory m.path.
from gekko import GEKKO
m = GEKKO(remote=False)
c = 2
x = m.Param(3,name='x')
ro = m.Var(value=4,lb=0,ub=10,name='ro')
y = m.Var()
phi = m.Intermediate(c*ro,name='phi')
m.Equation(y==phi**2+x)
m.Maximize(y)
m.options.SOLVER = 1
m.options.DIAGLEVEL=2
m.open_folder()
m.solve()
Here is a summary of the diagnostic files that are produced:
Variables, Equations, Jacobian, Lagrange Multipliers, Objective
apm_eqn.txt
apm_jac.txt
apm_jac_fv.txt
apm_lam.txt
apm_lbt.txt
apm_obj.txt
apm_obj_grad.txt
apm_var.txt
Solver Output and Options
APOPT.out
apopt_current_options.opt
Model File
gk_model0.apm
Data File
gk_model0.csv
Options Files
gk_model0.dbs
options.json
Specification File for FV, MV, SV, CV
gk_model0.info
Inputs to the Model
dbs_read.rpt
input_defaults.dbs
input_gk_model0.dbs
input_measurements.dbs
input_overrides.dbs
measurements.dbs
Results
rto.t0
results.csv
results.json
gk_model0_r_2022y12m04d08h12m28.509s.t0
Initialization Steps Before Solve
rto_1.t0
rto_2.t0
rto_3.t0
rto_3_eqn.txt
rto_3_eqn_var.txt
rto_3_var.t0
Reports After Solve
rto_4.t0
rto_4_eqn.txt
rto_4_eqn_var.txt
rto_4_var.t0
The files of interest for you are likely the rto* initialization files. The name changes based on the IMODE that you run. It is mpu* for your application for a Model Parameter Update with IMODE=2.

reseting a model in cplex python API

I am using Cplex python API for my optimization problem. I want to run many instances of the problem and each time I want to create a new model with a different set of variables. The problem is that I am getting a warning that says I have used some variables before. For that, I want to reset the model each time. Even when I call a function and from that function I create the model, still I get that warning. I there any function in cplex python API to reset the variables and everything in a model?
Some examples in Easy optimization with python
monte carlo optimization
import random
import math
random.seed(1)
from docplex.mp.model import Model
# original model
nbKids=300
mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
costBus40=500.0;
costBus30=400.0;
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= nbKids, 'kids')
mdl.minimize(nbbus40*costBus40 + nbbus30*costBus30)
nbSamples=20
nbMaxKidsAbsent=30;
nbKidsLess=[random.randint(0,nbMaxKidsAbsent) for i in range(0,nbSamples)]
nbKidsOptions=[nbKids-nbKidsLess[i] for i in range(0,nbSamples)]
#Monte Carlo optimization
totalCost=0.0;
for i in range(0,nbSamples):
mdl.get_constraint_by_name("kids").rhs=nbKidsOptions[i]
mdl.solve()
cost=mdl.solution.get_objective_value()
totalCost+=cost
print("if we need to bring ",nbKidsOptions[i]," kids to the zoo");
print("cost = ",cost)
print()
averageCost=1/nbSamples*totalCost
print("------------------------------");
print("average cost = ",math.ceil(averageCost));

ODE with non-analytical time-dependent parameters in PyMC3

I'm working on solving the following ODE with PyMC3:
def production( y, t, p ):
return p[0]*getBeam( t ) - p[1]*y[0]
The getBeam( t ) is my time dependent coefficient. Those coefficients are given by an array of data which is accessed by the time index as follows:
def getBeam( t ):
nBeam = I[int(t/10)]*pow( 10, -6 )/q_e
return nBeam
I have successfully implemented it by using the scipy.integrate.odeint, but I have hard time to do it with pymc3.ode. In fact, by using the following:
ode_model = DifferentialEquation(func=production, times=x, n_states=1, n_theta=3, t0=0)
with pm.Model() as model:
a = pm.Uniform( "S-Factor", lower=0.01, upper=100 )
ode_solution = ode_model(y0=[0], theta=[a, Yield, lambd])
I obviously get the error TypeError: __trunc__ returned non-Integral (type TensorVariable), as the t is a TensorVariable, thus can not be used to access the array in which the coefficients are stored.
Is there a way to overcome this difficulty? I thought about using the theano.function but I can not get it working since, unfortunately, the coefficients can not be expressed by any analytical function: they are just stored inside the array I which index represents the time variable t.
Thanks
Since you already have a working implementation with scipy.integrate.odeint, you could use theano.compile.ops.as_op, though it comes with some inconveniences (see how to fit a method belonging to an instance with pymc3? and How to write a custom Deterministic or Stochastic in pymc3 with theano.op?)
Using your exact definitions for production and getBeam, the following code seems to work for me:
from scipy.integrate import odeint
from theano.compile.ops import as_op
import theano.tensor as tt
import pymc3 as pm
def ScipySolveODE(a):
return odeint(production, y0=[0], t=x, args=([a, Yield, lambd],)).flatten()
#as_op(itypes=[tt.dscalar], otypes=[tt.dvector])
def TheanoSolveODE(a):
return ScipySolveODE(a)
with pm.Model() as model:
a = pm.Uniform( "S-Factor", lower=0.01, upper=100 )
ode_solution = TheanoSolveODE(a)
Sorry I know this is more of a workaround than an actual solution...

Set an optimization using LMFIT and Parameters class with condition to be checked

How to use ExpressionModel in LMFIT to fit a conditional model that can be represented as:
from lmfit.models import ExpressionModel
# read(xdata and ydata) here
if xdata < some_parameter_value:
model = ExpressionModel('expression1')
else:
model = ExpressionModel('expression2')
How to write this conditional model as one model (global_model) and pass it to the fit method
results = global_model.fit(y, x = x, parameters_dictionary)
some_parameter_value: is a member of parameters_dictionary which is created using Parameters class
lmfit Models are defined independent of the data and cannot be used for "part of the data".
Perhaps you can rewrite the expression for the model as:
expr1 if x < x0 else expr2
Otherwise, I think you'll have to write a custom Model that tests the condition and does a different calculation based on that condition.

Categories