def construct_model(): try: model.build_model(data=Data.INPUT_DATA, parameters=Data.PARAMETERS) mc.mcprint(text="Model has been constructed successfully", color=mc.Color.GREEN) mc.mcprint(text="\nThe instance is ready to be optimized", color=mc.Color.GREEN) except Exception as e: mc.register_error(error_string="There was an error generating the model") mc.register_error(error_string=e)
def initialize_directories(): current_directories = os.listdir() for directory_name in ConfigFiles.DIRECTORIES: if directory_name not in current_directories: directory_path = os.path.join(os.getcwd(), directory_name) mc.mcprint(text="The directory '{}' doesn't exists.".format(directory_path), color=mc.Color.ORANGE) os.mkdir(directory_name) mc.mcprint(text="Created '{}' successfully".format(directory_path), color=mc.Color.GREEN)
def check_argument(): if len(sys.argv) == 2: arg = sys.argv[-1] arg = os.path.join(os.getcwd(), arg) if os.path.isdir(arg): mc.mcprint(text="Input Data Directory: ({})".format(arg), color=mc.Color.GREEN) ConfigFiles.DIRECTORIES["input_data"] = arg else: mc.register_error(error_string="The path '{}' doesn't exist".format(arg)) mc.mcprint(text="Using default directory ({})".format(ConfigFiles.DIRECTORIES["input_data"]), color=mc.Color.YELLOW) elif len(sys.argv) > 2: mc.register_error(error_string="Solver doesn't accept more than 1 argument") mc.exit_application(enter_quit=True)
def import_input_data(select_new_folder=False): try: select_input_data_folder() if select_new_folder else None mc.mcprint(text="Importing raw data", color=mc.Color.ORANGE) import_data() mc.mcprint(text="The data has been imported successfully", color=mc.Color.GREEN) mc.mcprint(text="Generating parameters from input data", color=mc.Color.ORANGE) create_parameters() mc.mcprint(text="Parameters has been generated successfully", color=mc.Color.GREEN) mc.mcprint(text="Constructing Model", color=mc.Color.ORANGE) construct_model() except Exception as e: clear_all_data() mc.register_error(error_string="The input directory doesn't contain a valid structure") mc.register_error(error_string=e) return
def select_input_data_folder(): list_dir = os.listdir(os.getcwd()) excluded_dirs = ['output', '__pycache__', 'mcutils'] menu_list = [] for directory in list_dir: if not os.path.isfile(directory) and directory not in excluded_dirs: menu_list.append(directory) mc_import_data = mc.Menu(title="Import Input Data", subtitle="Select the directory to import", options=menu_list, back=False) selected_index = int(mc_import_data.show()) selected_folder = menu_list[selected_index - 1] ConfigFiles.DIRECTORIES["input_data"] = os.path.join(os.getcwd(), selected_folder) mc.mcprint(ConfigFiles.DIRECTORIES["input_data"], color=mc.Color.GREEN) return selected_folder
def import_data(): mc.mcprint(text="Importing from data input directory", color=mc.Color.ORANGE) mc.mcprint(text="The current directory is ({})".format(ConfigFiles.DIRECTORIES["input_data"]), color=mc.Color.ORANGE) path_dirs = {} input_data_path = ConfigFiles.DIRECTORIES["input_data"] for directory in os.listdir(input_data_path): path_dirs[directory] = os.path.join(input_data_path, directory) exclude = ['corridor.csv', 'surcharge.csv', 'route_supplier.csv'] for file_name in path_dirs: path = path_dirs[file_name] with open(path) as file: object_data = {} first_line = True headers = [] for line in file: if line.strip() == "": continue if first_line: if file_name in exclude: headers = line.strip().split(";") else: headers = line.strip().split(";")[1:] first_line = False continue if file_name not in exclude: split = line.strip().split(";") object_data[split[0]] = {} for index, attribute in enumerate(split[1:]): object_data[split[0]][headers[index]] = attribute else: split = line.strip().split(";") object_data["_".join([file_name.split(".")[0]] + split[:2])] = {} for index, attribute in enumerate(split): object_data["_".join([file_name.split(".")[0]] + split[:2])][headers[index]] = attribute Data.INPUT_DATA[file_name.split(".")[0]] = object_data if len(Data.INPUT_DATA) == 0: raise Exception("No compatible data has been found. " "Please please insert valid data or change the input data directory")
def display_optimal_information(): model = Model.model mc.mcprint(text=model.getStatus(), color=mc.Color.YELLOW) if model.getStatus() != "infeasible": for var in model.getVars(): value = int(model.getVal(var)) print("{}:\t{}".format(value, var)) if value != 0 else None if model.getStatus() == "optimal": mc.mcprint(text="Found the optimal solution successfully", color=mc.Color.GREEN) else: mc.mcprint(text="The instance is INFEASIBLE", color=mc.Color.RED)
def initialize(): mc.mcprint(text="Initializing Solver...") check_argument() initialize_directories() import_input_data()
def clear_all_data(): mc.mcprint(text="Applying Rollback...", color=mc.Color.ORANGE) Data.INPUT_DATA = {} Data.PARAMETERS = {} model.reset_model()
def create_parameters(): data = Data.INPUT_DATA if len(data.keys()) == 0: raise Exception("There is no data") # Generating: Plants mc.mcprint(text="Generating Plants") ra_a = {} for plant in data['plants']: ra_a[plant] = data['plants'][plant]['RegionID'] # Generating: Suppliers mc.mcprint(text="Generating Suppliers") rs_s = {} for supplier in data['suppliers']: rs_s[supplier] = data['suppliers'][supplier]['RegionID'] # Generating: Region of Reception (assuming region of reception == region of closest plant) mc.mcprint(text="Generating Region of Reception") rr_r = {} pl_ra = {} for reception in data['receptions']: closest_plant = data['receptions'][reception]['ClosestAssemblyPlant'] for plant in data['plants']: pl_ra[(reception, plant)] = 0 if plant == closest_plant: rr_r[reception] = data['plants'][plant]['RegionID'] pl_ra[(reception, plant)] = 1 # Generating: Supplier Stock mc.mcprint(text="Generating Supplier Stock") s_s = {} for supplier in data['suppliers']: s_s[supplier] = int(data['suppliers'][supplier]['ItemAvailability']) # Generating: Demand mc.mcprint(text="Generating Demand") m_ap = {} for order_id in data['orders']: order = data['orders'][order_id] item_id = order['ItemID'] if item_id in data['items'].keys(): m_ap[(order['PlantID'], item_id)] = int(order['NumItemsOrdered']) else: error_message = "{} includes {} but this item has not been declared in the input file".format(order_id, item_id) raise Exception(error_message) # Generating: Tax Supplier -> Reception (changing region) mc.mcprint(text="Generating Tax Supplier -> Reception (changing region)") t_sd = {} for supplier in rs_s: for reception in rr_r: coordinate = [rr_r[reception], rs_s[supplier]] id_ = "_".join(['surcharge'] + coordinate) if id_ in data['surcharge'].keys(): t_sd[(supplier, reception)] = float(data['surcharge'][id_]['TaxPerContainer'].replace(",", ".")) else: t_sd[(supplier, reception)] = 0 # Generating: Cost of Item (in supplier) mc.mcprint(text="Generating Cost of Item (in supplier)") cs_sp = {} for supplier in data['suppliers']: item = data['suppliers'][supplier]['ItemProduced'] cs_sp[(supplier, item)] = int(data['suppliers'][supplier]['UnitItemCost']) # Generating: Cost from Reception -> Supplier (includes taxes) mc.mcprint(text="Generating Cost from Reception -> Supplier (includes taxes)") corridor_types = [ 'Automatic', 'Manual', 'Subcontractor', ] cor = corridor_types k_daj = {} for corridor in data['corridor']: if not len(corridor.split("_")) > 1: continue reception, plant = corridor.split("_")[1:] for corridor_type in corridor_types: corridor_real_type = corridor_type corridor_type = "TransportationCostPerContainer" + corridor_type total_cost = int(data['corridor'][corridor][corridor_type]) if corridor_type == corridor_types[2]: total_cost += float(data['corridor'][corridor]['TaxPerContainer'].replace(",", ".")) k_daj[(reception, plant, corridor_real_type)] = total_cost # Generating: Handling Cost at Plant mc.mcprint(text="Generating Handling Cost at Plant") cd_aj = {} for plant in data['plants']: for corridor_type in corridor_types: id_ = "PlantHandlingCostPerContainer" + corridor_type cd_aj[(plant, corridor_type)] = 0 if id_ in data['plants'][plant].keys(): cd_aj[(plant, corridor_type)] = float(data['plants'][plant][id_].replace(",", ".")) # Generating: Handling Cost at Reception mc.mcprint(text="Generating Handling Cost at Reception") cd_dj = {} for reception in data['receptions']: for corridor_type in corridor_types: cd_dj[(reception, corridor_type)] = 0 id_ = "ReceptionHandlingCostPerContainer" + corridor_type if id_ in data['receptions'][reception].keys(): cd_dj[(reception, corridor_type)] = float(data['receptions'][reception][id_].replace(",", ".")) # Generating: Transportation Cost from Supplier -> Reception mc.mcprint(text="Generating Transportation Cost from Supplier -> Reception") ld_sd = {} for supplier in data['suppliers']: for reception in data['receptions']: id_ = "_".join(["route_supplier"] + [supplier, reception]) if id_ not in data['route_supplier'].keys(): continue ld_sd[(supplier, reception)] = int(data['route_supplier'][id_]['TransportationCostPerContainer']) # Generating: Weight for Item mc.mcprint(text="Generating Weight for Item") f_p = {} for item in data['items']: f_p[item] = float(data['items'][item]['UnitWeight']) # Generating: Max Number of Items per Container mc.mcprint(text="Generating Max Number of Items per Container") w_p = {} for item in data['items']: w_p[item] = int(data['items'][item]['MaximumNumPerContainer']) # Generating: Max Number of Container from reception -> Pant (using automatic corridor) mc.mcprint(text="Generating Max Number of Container from reception -> Pant (using automatic corridor)") rca_d = {} for reception in data['receptions']: rca_d[reception] = int(data['receptions'][reception]['ReceptionMaxNumOfContainersAutomatic']) # Generating: Max Weight from Reception -> Plant (using corridor automatic) mc.mcprint(text="Generating Max Weight from Reception -> Plant (using corridor automatic)") rwa_d = {} for reception in data['receptions']: rwa_d[reception] = float(data['receptions'][reception]['ReceptionMaxSumOfWeightsAutomatic'].replace(",", ".")) # Generating: Max Number of Container from Reception -> Plant (using corridor manual) mc.mcprint(text="Generating Max Number of Container from Reception -> Plant (using corridor manual)") rcm_d = {} for reception in data['receptions']: rcm_d[reception] = int(data['receptions'][reception]['ReceptionMaxNumOfContainersManual']) # Generating: Max Number of Items from Reception -> Plant (using corridor manual) mc.mcprint(text="Generating Max Number of Items from Reception -> Plant (using corridor manual)") rim_d = {} for reception in data['receptions']: rim_d[reception] = int(data['receptions'][reception]['ReceptionMaxNumOfItemsManual']) # Generating: Binary can send from Reception -> Plant (using corridor ?) mc.mcprint(text="Generating Binary can send from Reception -> Plant (using corridor ?)") e_da = {} for reception in data['receptions']: for plant in data['plants']: e_da[(reception, plant)] = 0 for reception in data['receptions']: plant = data['receptions'][reception]['ClosestAssemblyPlant'].replace("Assembly", "") e_da[(reception, plant)] = 1 # Generating: Binary can Item use Corridor automatic? mc.mcprint(text="Generating Binary can Item use Corridor automatic?") i_i = {} for item in data['items']: is_automatic_compatible = int(data['items'][item]['IsAutomaticCompatible']) i_i[item] = 1 if is_automatic_compatible > 0 else 0 Data.PARAMETERS = { 'RAa': ra_a, # Region of plant a 'RRr': rr_r, # Region of reception r 'RSs': rs_s, # Region of supplier s 'PLra': pl_ra, 'Ss': s_s, 'Map': m_ap, 'Tsd': t_sd, 'CSsp': cs_sp, 'Kdaj': k_daj, 'CDaj': cd_aj, 'CDdj': cd_dj, 'LDsd': ld_sd, 'Fp': f_p, 'Wp': w_p, 'RCAd': rca_d, 'RWAd': rwa_d, 'RCMd': rcm_d, 'RIMd': rim_d, 'Eda': e_da, 'COR': cor, 'Ii': i_i, }
def build_model(data, parameters): Model.model = pyscipopt.Model("Model_Team_8") model = Model.model # Aux big_m = 9999999 pa = parameters # Variable Declarations x_srpic = {} p_srpic = {} mc.mcprint(text="Constructing Variable X & P") for supplier in data['suppliers']: for reception in data['receptions']: for plant in data['plants']: for item in data['items']: for corridor in parameters['COR']: variable_x_name = "X[{}][{}][{}][{}][{}]".format( supplier, reception, item, plant, corridor) variable_p_name = "P[{}][{}][{}][{}][{}]".format( supplier, reception, item, plant, corridor) if (supplier, reception) in pa['LDsd'].keys() \ and (supplier, item) in pa['CSsp'].keys(): x_srpic[supplier, reception, plant, item, corridor] = model.addVar( lb=0, ub=None, name=variable_x_name, vtype="INTEGER") p_srpic[supplier, reception, plant, item, corridor] = model.addVar( lb=0, ub=None, name=variable_p_name, vtype="INTEGER") mc.mcprint(text="Constructing Objective Function") objective_function = model.addVar(name="objective function", lb=None) model.addCons(objective_function == ( pyscipopt.quicksum( (pa['Tsd'][s, r] * pa['PLra'][r, p] + pa['CDdj'][r, c] + pa['LDsd'][s, r]) * x_srpic[s, r, p, i, c] + pa['CSsp'][s, i] * p_srpic[s, r, p, i, c] for s in data['suppliers'] for r in data['receptions'] for p in data['plants'] for i in data['items'] for c in parameters['COR'] if (s, r, p, i, c) in x_srpic.keys()) + pyscipopt.quicksum( (pa['Kdaj'][r, p, c] + pa['CDaj'][p, c]) * x_srpic[s, r, p, i, c] for s in data['suppliers'] for r in data['receptions'] for p in data['plants'] for i in data['items'] for c in parameters['COR'] if (s, r, p, i, c) in p_srpic.keys()))) model.setObjective(objective_function, "minimize") # Constraint: Demand mc.mcprint(text="Cons: Demand") for p in data['plants']: for i in data['items']: if (p, i) in parameters['Map'].keys(): # mc.mcprint(text=parameters['Map'][p,i], color=mc.Color.RED) model.addCons( pyscipopt.quicksum( p_srpic[s, r, p, i, c] for s in data['suppliers'] for r in data['receptions'] for c in parameters['COR'] if (s, r, p, i, c) in p_srpic.keys()) == (parameters['Map'][p, i])) else: model.addCons( pyscipopt.quicksum(p_srpic[s, r, p, i, c] for s in data['suppliers'] for r in data['receptions'] for c in parameters['COR'] if (s, r, p, i, c) in p_srpic.keys()) == 0) # Constraint: Divide Items in Containers mc.mcprint(text="Cons: Distribute P in X") for s in data['suppliers']: for r in data['receptions']: for p in data['plants']: for i in data['items']: for c in parameters['COR']: if (s, r, p, i, c) in p_srpic.keys(): model.addCons( p_srpic[s, r, p, i, c] <= x_srpic[s, r, p, i, c] * parameters['Wp'][i]) # Constraint: Max Container from R -> P (automatic) mc.mcprint(text="Cons: Max Container from R -> P (automatic)") c = "Automatic" for r in data['receptions']: for p in data['plants']: model.addCons( pyscipopt.quicksum( x_srpic[s, r, p, i, c] for i in data['items'] for s in data['suppliers'] if (s, r, p, i, c) in x_srpic.keys()) <= parameters['RCAd'][r]) # Constraint: Cons: Max Container from R -> P (manual) mc.mcprint(text="Cons: Max Container from R -> P (manual)") c = "Manual" for r in data['receptions']: for p in data['plants']: model.addCons( pyscipopt.quicksum( x_srpic[s, r, p, i, c] for i in data['items'] for s in data['suppliers'] if (s, r, p, i, c) in x_srpic.keys()) <= parameters['RCMd'][r]) # Constraint: Max Weight from R -> P (automatic) mc.mcprint(text="Cons: Max Weight from R -> P (automatic)") c = "Automatic" for r in data['receptions']: for p in data['plants']: model.addCons( pyscipopt.quicksum( p_srpic[s, r, p, i, c] * parameters['Fp'][i] for s in data['suppliers'] for i in data['items'] if (s, r, p, i, c) in p_srpic.keys()) <= parameters['RWAd'][r]) # Constraint: Max Items from R-> P (manual) mc.mcprint(text="Cons: Max Items from R -> P (manual)") c = "Manual" for r in data['receptions']: model.addCons( pyscipopt.quicksum( p_srpic[s, r, p, i, c] for s in data['suppliers'] for p in data['plants'] for i in data['items'] if (s, r, p, i, c) in p_srpic.keys()) <= parameters['RIMd'][r]) # Constraint: Check if Item can go through corridor (automatic) mc.mcprint(text="Cons: Check if Item can go through corridor (automatic)") c = "Automatic" for s in data['suppliers']: for r in data['receptions']: for p in data['plants']: for i in data['items']: if (s, r, p, i, c) in x_srpic.keys(): model.addCons( x_srpic[s, r, p, i, c] <= big_m * pa['Ii'][i]) # Constraint: Don't surpass Supplier Stock mc.mcprint(text="Cons: Don't surpass Supplier Stock") for s in data['suppliers']: model.addCons( pyscipopt.quicksum( p_srpic[s, r, p, i, c] for r in data['receptions'] for p in data['plants'] for i in data['items'] for c in parameters['COR'] if (s, r, p, i, c) in p_srpic.keys()) <= parameters['Ss'][s]) # Constraint: Manual Corridor can only send to closest plant mc.mcprint(text="Cons: Manual Corridor can only send to closest plant") c = "Manual" for r in data['receptions']: for p in data['plants']: model.addCons( pyscipopt.quicksum(x_srpic[s, r, p, i, c] for i in data['items'] for s in data['suppliers'] if (s, r, p, i, c) in x_srpic.keys()) <= parameters['Eda'][(r, p)] * big_m)