How to convert value of pyomo variable from float to int?

Question:

I’m working on an Task Scheduling problem given in Table 3 of paper Holistic energy awareness for intelligent drones.

Table 3

In the 6th equation: N_d = E_d/B_d

I want to convert floating value of (E_d/B_d) to an integer value of N_d.
I’m using an Abstract model on pyomo (6.4.0) on python 3.7 and glpk 4.65 solver

The basic original code written is

model.Drones = Set() # List of drones
model.Battery_capacity = Param(model.Drones, within=NonNegativeReals) # =170
model.Energy_total = Var(model.Drones, within=NonNegativeReals, initialize=1)
model.Charging_sessions = Var(model.Drones, within=NonNegativeReals, initialize=1)

def battery_charging_sessions_rule(model, d):
    return model.Charging_sessions[d] == (model.Energy_total[d]/model.Battery_capacity[d])
model.battery_charging_sessions = Constraint(model.Drones, rule=battery_charging_sessions_rule)

In this case, model.battery_charging_sessions is a floating point value which can be less than 1 also. I’ve tried various options like

model.Charging_sessions = Var(model.Drones, within=Integers, initialize=1, bounds=(0,None))

and using the following return statement also instead of previous one

    return model.Charging_sessions[d] == floor(value((model.Energy_total[d]/model.Battery_capacity[d])))

However, this cause the model.Charging_sessions forced to be 0 and it wont even be generated in results file. Using the logs I found out with no change in original code,

Charging_sessions[d] - (0.0058823530*Energy_total[d]) 

is lower and upper bounded by 0,where 0.0058823530 = 1/170.

While with the changes the lower and upper bound of

Charging_sessions[d]

are 0. It seems that by using floor(value()) or int(value()) the term (0.0058823530*Energy_total[d]) is reduced to 0.

What are the ways I can get the integer value?

Asked By: rrsaxena92

||

Answers:

A lot of thanks to Erwin Kalvelagen for providing the solution.
This answer can work for both converting a float value to int or taking floor and taking ceil.
I’ve modified my code to take floor of the value. Here is the solution

model.Drones = Set() # List of drones
model.Battery_capacity = Param(model.Drones, within=NonNegativeReals) # =170
model.Energy_total = Var(model.Drones, within=NonNegativeReals, initialize=1)
model.Charging_sessions = Var(model.Drones, within=NonNegativeIntegers, initialize=0, bounds=(0,None))
model.Charging_sessionsTmp = Var(model.Drones, within=NonNegativeReals, initialize=1, bounds=(0,None))
        
def battery_charging_sessions_rule(model, d):
    return model.Charging_sessionsTmp[d] == model.Energy_total[d]/model.Battery_capacity[d])
model.battery_charging_sessions = Constraint(model.Drones, rule=battery_charging_sessions_rule)
    
def batt_charging_floor_val_rule_lb(model_in,d):
    return model_in.Charging_sessionsTmp[d] - 0.9999 <= model_in.Charging_sessions[d]
model.battery_charging_sessions_int_lb = Constraint(model.Drones, rule=batt_charging_floor_val_rule_lb)
    
def batt_charging_floor_val_rule_ub(model_in,d):
    return model_in.Charging_sessions[d] <= model_in.Charging_sessionsTmp[d]

The 3 constraints in the code basically implement following constraint

(E_d/B_d) – 0.9999 <= N_d <= (E_d/B_d)

Answered By: rrsaxena92