def is_empty_intersection(self, uncertain_params, nlp_solver): """ Determine if intersection is empty Args: uncertain_params: list of uncertain parameters nlp_solver: a Pyomo Solver object for solving NLPs """ # === Non-emptiness check for the set intersection is_empty_intersection = True if any(a_set.type == "discrete" for a_set in self.all_sets): disc_sets = (a_set for a_set in self.all_sets if a_set.type == "discrete") disc_set = min(disc_sets, key=lambda x: len(x.scenarios)) # minimum set of scenarios # === Ensure there is at least one scenario from this discrete set which is a member of all other sets for scenario in disc_set.scenarios: if all(a_set.point_in_set(point=scenario) for a_set in self.all_sets): is_empty_intersection = False break else: # === Compile constraints and solve NLP m = ConcreteModel() m.obj = Objective(expr=0) # dummy objective required if using baron m.param_vars = Var(uncertain_params.index_set()) for a_set in self.all_sets: m.add_component(a_set.type + "_constraints", a_set.set_as_constraint(uncertain_params=m.param_vars)) try: res = nlp_solver.solve(m) except: raise ValueError("Solver terminated with an error while checking set intersection non-emptiness.") if check_optimal_termination(res): is_empty_intersection = False return is_empty_intersection
def solve_master_feasibility_problem(model_data, config): """ Solve a slack variable based feasibility model for the master problem """ model = construct_master_feasibility_problem(model_data, config) if config.solve_master_globally: solver = config.global_solver else: solver = config.local_solver if not solver.available(): raise RuntimeError("NLP solver %s is not available." % config.solver) results = solver.solve(model, tee=config.tee, load_solutions=False) if check_optimal_termination(results): model.solutions.load_from(results) # load solution to master model for v in model.component_data_objects(Var): master_v = model_data.master_model.find_component(v) if master_v is not None: master_v.set_value(v.value, skip_validation=True) else: results.solver.termination_condition = tc.error results.solver.message = ("Cannot load a SolverResults object with " "bad status: error") return results
def solve_master_feasibility_problem(model_data, config): """ Solve a slack variable based feasibility model for the master problem """ model = model_data.master_model.clone() for o in model.component_data_objects(Objective): o.deactivate() TransformationFactory("core.add_slack_variables").apply_to(model) solver = config.global_solver if not solver.available(): raise RuntimeError("NLP solver %s is not available." % config.solver) try: results = solver.solve(model, tee=config.tee) except ValueError as err: if 'Cannot load a SolverResults object with bad status: error' in str( err): results.solver.termination_condition = tc.error results.solver.message = str(err) else: raise if check_optimal_termination(results) and value( model._core_add_slack_variables._slack_objective) <= 0: # If this led to a feasible solution, continue with this model # Load solution into master for v in model.component_data_objects(Var): master_v = model_data.master_model.find_component(v) if master_v is not None: master_v.set_value(v.value, skip_validation=True) return results
def is_bounded(self, config): """ Return True if the uncertainty set is bounded, else False. """ # === Determine bounds on all uncertain params bounding_model = ConcreteModel() bounding_model.util = Block() # So that boundedness checks work for Cardinality and FactorModel sets bounding_model.uncertain_param_vars = IndexedVar(range(len(config.uncertain_params)), initialize=1) for idx, param in enumerate(config.uncertain_params): bounding_model.uncertain_param_vars[idx].value = param.value bounding_model.add_component("uncertainty_set_constraint", config.uncertainty_set.set_as_constraint( uncertain_params=bounding_model.uncertain_param_vars, model=bounding_model, config=config )) for idx, param in enumerate(list(bounding_model.uncertain_param_vars.values())): bounding_model.add_component("lb_obj_" + str(idx), Objective(expr=param, sense=minimize)) bounding_model.add_component("ub_obj_" + str(idx), Objective(expr=param, sense=maximize)) for o in bounding_model.component_data_objects(Objective): o.deactivate() for i in range(len(bounding_model.uncertain_param_vars)): for limit in ("lb", "ub"): getattr(bounding_model, limit + "_obj_" + str(i)).activate() res = config.global_solver.solve(bounding_model, tee=False) getattr(bounding_model, limit + "_obj_" + str(i)).deactivate() if not check_optimal_termination(res): return False return True
def generate_report(model: CVRPModel, result: SolverResults): # noinspection PyUnresolvedReferences def place_rows(ctx): depot = ctx.get("network").depot demand_sum = 0 for i, place in enumerate(ctx.get("network").all_places): h = "E" if place.longitude > 0 else "W" v = "N" if place.latitude > 0 else "S" demand_sum += place.demand yield tr( td(strong(place.name) if place is depot else place.name), td("-" if place is depot else place.demand), td(f"{abs(place.longitude):.2f} {h}, {abs(place.latitude):.2f} {v}") ) yield tr( td(strong("SUMA")), td(f"{demand_sum:.2f}"), td("-") ) # noinspection PyUnresolvedReferences def vehicle_rows(ctx): max_cap_sum = 0 for i, vehicle in enumerate(ctx.get("network").vehicles): max_cap_sum += vehicle.max_capacity yield tr( td(vehicle.name), td(vehicle.max_capacity), ) yield tr( td(strong("SUMA")), td(f"{max_cap_sum:.2f}") ) # noinspection PyUnresolvedReferences def route_vehicles(ctx): network = ctx.get("network") routes = ctx.get("routes") for vehicle in network.vehicles: place_names = ["Wyjazd z magazynu"] vehicle_distance = 0 for vehicle_route in routes[vehicle.slug_name]: place_from = network.get_place(vehicle_route[0]) place_dest = network.get_place(vehicle_route[1]) route_name = place_dest.name if place_dest is network.depot: route_name = "Powrót do magazynu" distance = Place.distance(place_from, place_dest) vehicle_distance += distance place_names.append(f"{route_name} (+ {distance:.2f} km)") yield div( h2(f"{vehicle.name} ({vehicle_distance:.2f} km)"), ol(*[li(name) for name in place_names]), ) body_sections = [ section( h2("Dane wejściowe"), div( h3("Miejsca"), table( thead(td("Nazwa"), td("Zapotrzebowanie"), td("Położenie geo.")), tbody(place_rows) ) ), div( h3("Pojazdy"), table( thead(td("Nazwa"), td("Maks. pojemność")), tbody(vehicle_rows) ) ), ) ] if check_optimal_termination(result): body_sections.append( section( h2("Wybrane trasy"), div(route_vehicles), p(strong("Całkowita przebyta odległość: "), span(f"{model.obj_total_cost():.2f} km")) ) ) body_sections.append( section( h2("Wizualizacja"), lambda ctx: img(src=generate_network_vis(ctx.get("network"), ctx.get("routes"))) ) ) body_sections.append( section( h2("Solver"), div(table(tbody( tr(td(strong("Użyty solver:")), td(get_solvers()[0])), tr(td(strong("Czas rozwiązywania:")), td(result.solver.time)), tr(td(strong("Status:")), td(str(result.solver.status))), tr(td(strong("Stan zakończenia:")), td(str(result.solver.termination_condition))), tr(td(strong("Kod zwrotny:")), td(str(result.solver.return_code))), tr(td(strong("Wiadomość:")), td(str(result.solver.message))), ))), h2("Problem"), div(table(tbody(*[ tr(td(p(strong(k + ":")), td(v.value))) for k, v in result.problem[0].items() ]))) ) ) template = html( head( title("Problem marszrutyzacji - Raport"), style( "table, th, td { border: 1px solid black; border-collapse: collapse; }" + "section { margin-left: 2em; }" ), ), body( header(h1("Raport marszrutyzacji")), *body_sections, footer(hr, f"Wygenerowano: {datetime.now()}"), ), ) return template.render( network=model.network, routes=model.vehicle_routes(), result=result )