Pyomo constraint > 100000 OR 0

Viewed 385

All,

I am working on some code where there is a requirement to buy/sell a minimum of 100,000 packets. If not possible then this should be zeroed.

I have tried a number of things for things for this including:

def objective_rule(model):
      return sum(model.Prices[ProductCount]*model.Amount[ProductCount]*(model.Amount[ProductCount]>100000) for ProductCount in model.Products)

But this is slower than expected. I would like to put an explicit constraint in place. Something akin to:

def minTradesize_Constraint(model):
    return ((model.Amount[ProductCount]>=100000)| \
                   (model.Amount[ProductCount]==0.00) for ProductCount in model.Products)

I have looked at indicator functions but the Pyomo continuous approximations don't help. Any help/guidance appreciated.

2 Answers

Basically, what you are trying to achieve is make the model.Amount[ProductCount] terms take discontinuous values (zero or larger or equal to 100,000). To achieve that, first, you will basically need to define a binary variable: model.y = pyomo.Var(model.Products, within=pyomo.Binary).

Then you will need to add the following constraints:

def minTradesize_Constraint1(model):
    return (model.Amount[ProductCount] >= 100000 * y[ProductCount] for ProductCount in model.Products)

def minTradesize_Constraint2(model):
    return (model.Amount[ProductCount] <= M * y[ProductCount] for ProductCount in model.Products)

where M is a sufficiently large number (can be a realistic upper bound for your model.Amount[ProductCount] variable).

As a result of this formulation, if y[ProductCount] is zero, then the model.Amount[ProductCount] term will also be zero. If the model wants now to make model.Amount[ProductCount] variable take positive values, it will have to set the binary y[ProductCount] to 1, hence, forcing model.Amount[ProductCount] to become larger or equal to 100,000.

Note: I have formulated the constraints in the same style that you did in your answer. However, if I understand your model correctly, I would say that the first constraint, for instance, should be:

def minTradesize_Constraint1(model, ProductCount):
    return (model.Amount[ProductCount] >= 100000 * y[ProductCount]

and the for ProductCount in model.Products part should be added when you create the Pyomo constraint.

to simplify the solution even further. I added a variable called route_selected

 model.route_selected = pe.Var(<a set, for me its routes == r>, domain=pe.Binary, initialize=0, within=pe.Binary)

 model.route_selected = pe.Var(model.R, domain=pe.Binary, initialize=0, within=pe.Binary)

thats my dependent variable looks

# Variable to solve, this is the variable that will be changed by solver to find a solution
# for each route, port, cust, year combination what should be supplied amount
model.x_rpcy = pe.Var(self.model.R, self.model.P, self.model.C, self.model.Y, domain=pe.NonNegativeIntegers, initialize=0)

and then added this constraint

for y in self.model.Y:
    for r in self.model.R:
            lhs = sum(self.model.x_rpcy[r, p, c, y] for p in self.model.P for c in self.model.C)
                vessel_size = 1000
                self.model.const_route.add(lhs == vessel_size * self.model.route_selected[r])
                
    model.const_route.add(lhs == vessel_size * model.route_selected[r]) 
Related