How do I solve Error retrieving component IndexedVar[1]: The component has not been constructed - pyomo

I'm getting this error (Error retrieving component IndexedVar[1]: The component has not been constructed.), and I can't figure out where I went wrong with my code below, I'm coding a linear program in pyomo, I'm not versed in python, I'm basically repeating when I learned for linear programming. Can you help me out? The error seems to be in the line defining the objective function... please help
'''
#!/usr/bin/env python3
-- coding: utf-8 --
"""
Created on Sun Jun 12 20:01:39 2022
#author: israathiab
"""
import pyomo.environ as pyo
def pyomoresults(QEMCAProfitModel): # define a function to print optimization results
""""Print results of the optimization of model 'QEMCAProfitModel' including
objective value at optimum, optimal decision variable values and
dual/slack information on constraints"""
print('')
print('=========================')
print('QEMCAProfitModel Maximization Solution')
print('=========================')
print('')
print('Objective Function Value at Optimum')
# loop over objective objects in the model
for f in QEMCAProfitModel.component_objects(pyo.Objective, active=True):
print ('Objective', f) # print the name of the objective
# loop over subobjectives (in this course we will only have one)
for index in f:
print (' ', index, pyo.value(f[index]))
print('')
print('Decision Variable Values at Optimum')
# loop over decision variable objects in model
for v in QEMCAProfitModel.component_objects(pyo.Var, active=True):
print ('Variable', v) # print variable name
for index in v: # loop over index of variable object
# print index/optimal values
print (' ', index, pyo.value(v[index]))
print('')
print ('Duals/Shadow Prices at Optimum')
# loop over constraint objects in model
for d in QEMCAProfitModel.component_objects(pyo.Constraint, active=True):
print ('Constraint',d) # print constraint name
for index in d: # loop over index of constraint object
# print dual value of constraint
print (' ', index, QEMCAProfitModel.dual[d[index]])
print('')
print ("Slack at Optimum")
# loop over constraint objects in model
for i in QEMCAProfitModel.component_objects(pyo.Constraint, active=True):
print (" Constraint",Ci) # print constraint name
for index in Ci: # loop over index of constraint object
# print constraint slack information
print (" ", index, Ci[index].lslack(), ' - ', Ci[index].uslack())
#Define Concrete model
QEMCAProfitModel = pyo.ConcreteModel
#Define variable dictionary for decision variable index
#Crop index
I = [1,2,3,4,5,6]
#Define parameters
#Define mean profit per crop - ETB
mPi = {1:15635.2, 2:9571.36, 3:13392.6, 4:39834.6, 5:49074.1, 6:11365.6}
#Define mean cost per hectar of crop - ETB/Hecatre
Ci = {1:10467.37, 2:8160.47, 3:12392.22, 4:5702.01, 5:8265.88, 6:8514.31}
#Define objective function
QEMCAProfitModel.L = pyo.Var(I,within=pyo.NonNegativeReals)
QEMCAProfitModel.Profit = pyo.Objective(expr=sum(mPi[i] * QEMCAProfitModel.L[i] for i `in I), sense=pyo.maximize)`
#Profit un EBT
#Define constraints
def Budget_rule(QEMCAProfitModel, i):
return sum(Ci[i] * QEMCAProfitModel.L[i] for i in I) <= 850636
QEMCAProfitModel.Budget_rule = pyo.Constraint(I, rule=Budget_rule)
def Land_rule(QEMCAProfitModel, i):
return sum(QEMCAProfitModel.L[i] for i in I) <= 47.77
QEMCAProfitModel.Land_rule = pyo.Constraint(I, rule=Land_rule)
def Land_rule_min(QEMCAProfitModel, i):
return sum(QEMCAProfitModel.L[i] for i in I) >= 0
QEMCAProfitModel.Land_rule_min = pyo.Constraint(I, rule=Land_rule_min)
def Consumption_rule_1(QEMCAProfitModel, i):
return 4560.64 * QEMCAProfitModel.L[1] >= 51250
QEMCAProfitModel.Consumption_rule_1 = pyo.Constraint(I, rule=Consumption_rule_1)
def Consumption_rule_2(QEMCAProfitModel, i):
return 5764.71 * QEMCAProfitModel.L[2] >= 36710
QEMCAProfitModel.Consumption_rule_2 = pyo.Constraint(I, rule=Consumption_rule_2)
def Consumption_rule_3(QEMCAProfitModel, i):
return 9908.3 * QEMCAProfitModel.L[3] >= 30316
QEMCAProfitModel.Consumption_rule_3 = pyo.Constraint(I, rule=Consumption_rule_3)
def Consumption_rule_4(QEMCAProfitModel, i):
return 16614.81 * QEMCAProfitModel.L[4] >= 4850
QEMCAProfitModel.Consumption_rule_4 = pyo.Constraint(I, rule=Consumption_rule_4)
def Consumption_rule_5(QEMCAProfitModel, i):
return 20323.81 * QEMCAProfitModel.L[5] >= 4450
QEMCAProfitModel.Consumption_rule_5 = pyo.Constraint(I, rule=Consumption_rule_5)
def Consumption_rule_6(QEMCAProfitModel, i):
return 4400 * QEMCAProfitModel.L[6] >= 7100
QEMCAProfitModel.Consumption_rule_6 = pyo.Constraint(I, rule=Consumption_rule_6)
QEMCAProfitModel.pprint()
QEMCAProfitModel.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
opt = pyo.SolverFactory('glpk')
results = opt.solve(QEMCAProfitModel)
QEMCAProfitModel.display()
QEMCAProfitModel.dual.display()
pyomoresults(QEMCAProfitModel)
'''

You are missing parens when defining the model object:
QEMCAProfitModel = pyo.ConcreteModel
should be
QEMCAProfitModel = pyo.ConcreteModel()
Without the parens, QEMCAProfitModel is the class ConcreteModel instead of an instance of the class. The "magic" that triggers component "construction" (the __setattr__ method on Block data instances) only works on Block instances (and a model is a block).
Note that the same method is also responsible for copying the attribute name to the component name. Since that is not being triggered, you are seeing the default component name (the class name, IndexedVar) in the error message.

Related

Change constraints based on variable value in Pyomo

Is there a way of changing the values of a constraint as the solver is running?
Basically, I have a constraint that depends on the value of a variable. The problem is that the constraint is evaluated based on the initial value of the variable, but isn't updated as the variable changes.
Here's a simple example:
from pyomo.environ import *
from pyomo.opt import SolverFactory
import numpy as np
# Setup
model = ConcreteModel()
model.A = Set(initialize = [0,1,2])
model.B = Set(initialize = [0,1,2])
model.x = Var(model.A, model.B, initialize=0)
# A constraint that I'd like to keep updating, based on the value of x
def changing_constraint_rule(model, a):
x_values = list((model.x[a, b].value for b in model.B))
if np.max(x_values) == 0:
return Constraint.Skip
else:
# Not really important what goes here, just as long as it updates the constraint list
if a == 1 : return sum(model.x[a,b] for b in model.B) == 0
else: return sum(model.x[a,b] for b in model.B) == 1
model.changing_constraint = Constraint(model.A, rule = changing_constraint_rule)
# Another constraint that changes the value of x
def bounding_constraint_rule(model, a):
return sum(model.x[a, b] for b in model.B) == 1
model.bounding_constraint = Constraint(
model.A,
rule = bounding_constraint_rule)
# Some objective function
def obj_rule(model):
return(sum(model.x[a,b] for a in model.A for b in model.B))
model.objective = Objective(rule=obj_rule)
# Results
opt = SolverFactory("glpk")
results = opt.solve(model)
results.write()
model.x.display()
If I run model.changing_constraint.pprint() I can see that no constraints have been made, since the initial value of the variable model.x was set to 0.
If it's not possible to change the constraint values while solving, how could I formulate this problem differently to achieve what I'm looking for? I've read this other post but couldn't figure it out from the instructions.
I am giving you the same answer in the other question by #Gabe:
Any if-logic you use inside of rules should not involve the values of
variables (unless it is based on the initial value of a variable, in
which case you would wrap the variable in value() wherever you use it
outside of the main expression that is returned).
for example:
model.x[a, b].value should be model.x[a, b].value()
But still this might not give you the solution what you are looking for.

Object not iterable when assigning to a list

I am coding a 2048 game via pygame. below is the relevant section of my code:
class Data():
def __init__(self):
self.data = getnull()
self.score = 0
def updatesprites(self): # EXP
spritelist = [[],[],[],[]]
for count in range(4): # for row loop
for i in range(4): # per column loop
if self.data[count][i] != 0:
spritelist[count]+= newSprite(str(self.data[count] [i])+".png") # error occurs here
spritelist[count][i].move(15 + i*115, 15 + count*115)
showSprite(spritelist[count][i])
class newSprite(pygame.sprite.Sprite):
def __init__(self,filename):
pygame.sprite.Sprite.__init__(self)
self.images=[]
self.images.append(loadImage(filename))
self.image = pygame.Surface.copy(self.images[0])
self.currentImage = 0
self.rect=self.image.get_rect()
self.rect.topleft=(0,0)
self.mask = pygame.mask.from_surface(self.image)
self.angle = 0
def addImage(self, filename):
self.images.append(loadImage(filename))
def move(self,xpos,ypos,centre=False):
if centre:
self.rect.center = [xpos,ypos]
else:
self.rect.topleft = [xpos,ypos]
----------------Main-------------------
from functions import *
from config import *
from pygame_functions import *
import pygame
screenSize(475,475) # call screen init
gameboard = newSprite("game board.png") # createboard
showSprite(gameboard)
game = Data()
game.updatesprites()
while True:
pass
when game.updatesprites() is called, "newSprite object is not iterable" error is raised in function Data.updatesprites
+ concatenates lists and strings, and adds numbers.
What you are trying to do, is to add an element to a list.
This is done as follows:
li.append(element) # adds the element to the end of the list
Or in your case:
spritelist[count].append(newSprite(str(self.data[count][i]) + ".png"))
Another solution: You could create a new type, that lets you add elements the way you were trying to:
class UglyList(list):
def __iadd__(self, other):
self.append(other)
You'd need to change another line here:
spritelist = [UglyList() for i in range(4)]

Pyomo: Extending the "car ampl example" with additional constraints

After having seen the nice implementation of the "ampl car example" in Pyomo repository, I would like to keep extending the problem with new features and constraints, but I have found the next problems during development. Is someone able of fix them?
1) Added new constraint "electric car": Now the acceleration is limited by adherence until a determined speed and then constant power model is used. I am not able of implement this constraint as i would think. It is commented in the, but Pyomo complains about that a constraint is related to a variable. (now Umax depends of the car speed).
2) Added new comfort acceleration and jerk constraints. It seems they are working right, but should be nice if a Pyomo guru supervise them and tell me if they are really implemented in the correct way.
3) About last one, in order of reducing verbosity. Is there any way of combine accelerationL and accelerationU in a unique constraint? Same for jerkL and jerkU.
4) The last feature is a speed limit constraint divided in two steps. Again, I am not able of getting it works, so it is commented in code. Does anybody dare to fix it?
# Ampl Car Example (Extended)
#
# Shows how to convert a minimize final time optimal control problem
# to a format pyomo.dae can handle by removing the time scaling from
# the ContinuousSet.
#
# min tf
# dx/dt = v
# dv/dt = u - R*v^2
# x(0)=0; x(tf)=L
# v(0)=0; v(tf)=0
# -3 <= u <= 1 (engine constraint)
#
# {v <= 7m/s ===> u < 1
# u <= { (electric car constraint)
# {v > 7m/s ===> u < 1*7/v
#
# -1.5 <= dv/dt <= 0.8 (comfort constraint -> smooth driving)
# -0.5 <= d2v/dt2 <= 0.5 (comfort constraint -> jerk)
# v <= Vmax (40 kmh[0-500m] + 25 kmh(500-1000m])
from pyomo.environ import *
from pyomo.dae import *
m = ConcreteModel()
m.R = Param(initialize=0.001) # Friction factor
m.L = Param(initialize=1000.0) # Final position
m.T = Param(initialize=50.0) # Estimated time
m.aU = Param(initialize=0.8) # Acceleration upper bound
m.aL = Param(initialize=-1.5) # Acceleration lower bound
m.jU = Param(initialize=0.5) # Jerk upper bound
m.jL = Param(initialize=-0.5) # Jerk lower bound
m.NFE = Param(initialize=100) # Number of finite elements
'''
def _initX(m, i):
return m.x[i] == i*m.L/m.NFE
def _initV(m):
return m.v[i] == m.L/50
'''
m.tf = Var()
m.tau = ContinuousSet(bounds=(0,1)) # Unscaled time
m.t = Var(m.tau) # Scaled time
m.x = Var(m.tau, bounds=(0,m.L))
m.v = Var(m.tau, bounds=(0,None))
m.u = Var(m.tau, bounds=(-3,1), initialize=0)
m.dt = DerivativeVar(m.t)
m.dx = DerivativeVar(m.x)
m.dv = DerivativeVar(m.v)
m.da = DerivativeVar(m.v, wrt=(m.tau, m.tau))
m.obj = Objective(expr=m.tf)
def _ode1(m, i):
if i==0:
return Constraint.Skip
return m.dt[i] == m.tf
m.ode1 = Constraint(m.tau, rule=_ode1)
def _ode2(m, i):
if i==0:
return Constraint.Skip
return m.dx[i] == m.tf * m.v[i]
m.ode2 = Constraint(m.tau, rule=_ode2)
def _ode3(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] == m.tf*(m.u[i] - m.R*m.v[i]**2)
m.ode3 = Constraint(m.tau, rule=_ode3)
def _accelerationL(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] >= m.aL*m.tf
m.accelerationL = Constraint(m.tau, rule=_accelerationL)
def _accelerationU(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] <= m.aU*m.tf
m.accelerationU = Constraint(m.tau, rule=_accelerationU)
def _jerkL(m, i):
if i==0:
return Constraint.Skip
return m.da[i] >= m.jL*m.tf**2
m.jerkL = Constraint(m.tau, rule=_jerkL)
def _jerkU(m, i):
if i==0:
return Constraint.Skip
return m.da[i] <= m.jU*m.tf**2
m.jerkU = Constraint(m.tau, rule=_jerkU)
'''
def _electric(m, i):
if i==0:
return Constraint.Skip
elif value(m.v[i])<=7:
return m.a[i] <= 1
else:
return m.v[i] <= 1*7/m.v[i]
m.electric = Constraint(m.tau, rule=_electric)
'''
'''
def _speed(m, i):
if i==0:
return Constraint.Skip
elif value(m.x[i])<=500:
return m.v[i] <= 40/3.6
else:
return m.v[i] <= 25/3.6
m.speed = Constraint(m.tau, rule=_speed)
'''
def _initial(m):
yield m.x[0] == 0
yield m.x[1] == m.L
yield m.v[0] == 0
yield m.v[1] == 0
yield m.t[0] == 0
m.initial = ConstraintList(rule=_initial)
discretizer = TransformationFactory('dae.finite_difference')
discretizer.apply_to(m, nfe=value(m.NFE), wrt=m.tau, scheme='BACKWARD')
#discretizer = TransformationFactory('dae.collocation')
#discretizer.apply_to(m, nfe=value(m.NFE), ncp=4, wrt=m.tau, scheme='LAGRANGE-RADAU')
solver = SolverFactory('ipopt')
solver.solve(m,tee=True)
print("final time = %6.2f" %(value(m.tf)))
t = []
x = []
v = []
a = []
u = []
for i in m.tau:
t.append(value(m.t[i]))
x.append(value(m.x[i]))
v.append(3.6*value(m.v[i]))
a.append(10*value(m.u[i] - m.R*m.v[i]**2))
u.append(10*value(m.u[i]))
import matplotlib.pyplot as plt
plt.plot(x, v, label='v (km/h)')
plt.plot(x, a, label='a (dm/s2)')
plt.plot(x, u, label='u (dm/s2)')
plt.xlabel('distance')
plt.grid('on')
plt.legend()
plt.show()
Thanks a lot in advance,
Pablo
(1) You should not think of Pyomo constraint rules as callbacks that are used by the solver. You should think of them more as a function to generate a container of constraint objects that gets called once for each index when the model is constructed. Meaning it is invalid to use a variable in an if statement unless you are really only using its initial value to define the constraint expression. There are ways to express what I think you are trying to do, but they involve introducing binary variables into the problem, in which case you can no longer use Ipopt.
(2) Can't really provide any help. Syntax looks fine.
(3) Pyomo allows you to return double-sided inequality expressions (e.g., L <= f(x) <= U) from constraint rules, but they can not involve variable expressions in the L and U locations. It doesn't look like the constraints you are referring to can be combined into this form.
(4) See (1)

Python: How to properly call a method?

I have this class:
class Tumor(object):
"""
Wrapper for the tumor data points.
Attributes:
idNum = ID number for the tumor (is unique) (int)
malignant = label for this tumor (either 'M' for malignant
or 'B' for benign) (string)
featureNames = names of all features used in this Tumor
instance (list of strings)
featureVals = values of all features used in this Tumor
instance, same order as featureNames (list of floats)
"""
def __init__(self, idNum, malignant, featureNames, featureVals):
self.idNum = idNum
self.label = malignant
self.featureNames = featureNames
self.featureVals = featureVals
def distance(self, other):
dist = 0.0
for i in range(len(self.featureVals)):
dist += abs(self.featureVals[i] - other.featureVals[i])**2
return dist**0.5
def getLabel(self):
return self.label
def getFeatures(self):
return self.featureVals
def getFeatureNames(self):
return self.featureNames
def __str__(self):
return str(self.idNum) + ', ' + str(self.label) + ', ' \
+ str(self.featureVals)
and I am trying to use an instance of it in another function later in my code:
def train_model(train_set):
"""
Trains a logistic regression model with the given dataset
train_set (list): list of data points of type Tumor
Returns a model of type sklearn.linear_model.LogisticRegression
fit to the training data
"""
tumor = Tumor()
features = tumor.getFeatures()
labels = tumor.getLabel()
log_reg = sklearn.linear_model.LogisticRegression(train_set)
model = log_reg.fit(features, labels)
return model
However, I keep getting this error when I test my code:
TypeError: __init__() takes exactly 5 arguments (1 given)
I understand that I am not using the five arguments when I create the instance of Tumor in train_model , but how can I do so?
Arguments to the __init__ (or __new__, if you're using that) just go, predictably, where you create the instance in train_model:
tumor = Tumor(idNum, malignant, featureNames, featureVals)
Of course, you actually need values for all of these, as they are all required arguments.
You don't need to include self, however, as that first argument is taken care of automatically.

why my function doesn't remove objects from final_list?

hey guys:)im sorry for all the code but i feel its necessary for u to see everything..
i tried everything... i hidden prints in the code, debugging for ten times, triple checked the built in methods, and still, the .crawl() method dosnt remove any object from the final_list.
the object of my assignment is to built two classes:
Web_page : holds data of a web page.(the pages come in the form of html files saved in a folder on my desktop. Crawler: compare between pages and hold a list of the uniqe pages---> final_list
import re
import os
def remove_html_tags(s):
tag = False
quote = False
out = ""
for c in s:
if c == '<' and not quote:
tag = True
elif c == '>' and not quote:
tag = False
elif (c == '"' or c == "'") and tag:
quote = not quote
elif not tag:
out = out + c
return out
def lev(s1, s2):
return lev_iter(s1, s2, dict())
def lev_iter(s1, s2, mem):
(i,j) = (len(s1), len(s2))
if (i,j) in mem:
return mem[(i,j)]
s1_low = s1.lower()
s2_low = s2.lower()
if len(s1_low) == 0 or len(s2_low) == 0:
return max(len(s1_low), len(s2_low))
d1 = lev_iter(s1_low[:-1], s2_low, mem) + 1
d2 = lev_iter(s1_low, s2_low[:-1], mem) + 1
last = 0 if s1_low[-1] == s2_low[-1] else 1
d3 = lev_iter(s1_low[:-1], s2_low[:-1], mem) + last
result = min(d1, d2, d3)
mem[(i,j)] = result
return result
def merge_spaces(content):
return re.sub('\s+', ' ', content).strip()
""" A Class that holds data on a Web page """
class WebPage:
def __init__(self, filename):
self.filename = filename
def process(self):
f = open(self.filename,'r')
LINE_lst = f.readlines()
self.info = {}
for i in range(len(LINE_lst)):
LINE_lst[i] = LINE_lst[i].strip(' \n\t')
LINE_lst[i] = remove_html_tags(LINE_lst[i])
lines = LINE_lst[:]
for line in lines:
if len(line) == 0:
LINE_lst.remove(line)
self.body = ' '.join(LINE_lst[1:])
self.title = LINE_lst[0]
f.close()
def __str__(self):
return self.title + '\n' + self.body
def __repr__(self):
return self.title
def __eq__(self,other):
n = lev(self.body,other.body)
k = len(self.body)
m = len(other.body)
return float(n)/max(k,m) <= 0.15
def __lt__(self,other):
return self.title < other.title
""" A Class that crawls the web """
class Crawler:
def __init__(self, directory):
self.folder = directory
def crawl(self):
pages = [f for f in os.listdir(self.folder) if f.endswith('.html')]
final_list = []
for i in range(len(pages)):
pages[i] = WebPage(self.folder + '\\' + pages[i])
pages[i].process()
for k in range(len(final_list)+1):
if k == len(final_list):
final_list.append(pages[i])
elif pages[i] == final_list[k]:
if pages[i] < final_list[k]:
final_list.append(pages[i])
final_list.remove(final_list[k])
break
print final_list
self.pages = final_list
everything works fine besides this freaking line final_list.remove(final_list[k]). help please? whats wrong here?
I'm not sure why your code doesn't work, it's difficult to test it because I don't know what kind of input should end up calling remove().
I suggest following these steps:
Make sure that remove() is called at some point.
remove() relies on your __eq__() method to find the item to remove, so make sure that __eq__() isn't the culprit.
As a side note, you will probably want to replace this:
self.folder + '\\' + pages[i]
with:
import os.path
# ...
os.path.join(self.folder, page[i])
This simple change should make your script work on all operating systems, rather than on Windows only. (GNU/Linux, Mac OS and other Unix-like OS use “/” as path separator.)
Please also consider replacing loops of this form:
for i in range(len(sequence)):
# Do something with sequence[i]
with:
for item in sequence:
# Do something with item
If you need the item index, use enumerate():
for i, item in enumerate(sequence):