def test_diet_amplpy(self): dat = _diet_input_tdf.copy_to_ampl( _diet_dat, field_renamings={ ("foods", "Cost"): "cost", ("categories", "Min Nutrition"): "n_min", ("categories", "Max Nutrition"): "n_max", ("nutrition_quantities", "Quantity"): "amt", ("nutrition_quantities", "Other Quantity"): "other_amt" }) self.assertTrue({"n_min", "n_max"}.issubset(dat.categories.toPandas().columns)) ampl = amplpy.AMPL() ampl.setOption('solver', 'gurobi') ampl.eval(_diet_mod) _diet_input_tdf.set_ampl_data(dat, ampl, { "categories": "CAT", "foods": "FOOD" }) ampl.solve() sln = _diet_sln_tdf.copy_from_ampl_variables({ ("buy_food", "Quantity"): ampl.getVariable("Buy"), ("consume_nutrition", "Quantity"): ampl.getVariable("Consume") }) sln.parameters['Total Cost'] = ampl.getObjective('Total_Cost').value() diet_dat_two = _diet_input_tdf.copy_tic_dat(_diet_dat) for r in diet_dat_two.nutrition_quantities.values(): r["Quantity"], r["Other Quantity"] = [0.5 * r["Quantity"]] * 2 dat = _diet_input_tdf.copy_to_ampl( diet_dat_two, field_renamings={ ("foods", "Cost"): "cost", ("categories", "Min Nutrition"): "n_min", ("categories", "Max Nutrition"): "n_max", ("nutrition_quantities", "Quantity"): "amt", ("nutrition_quantities", "Other Quantity"): "other_amt" }) ampl = amplpy.AMPL() ampl.setOption('solver', 'gurobi') ampl.eval(_diet_mod) _diet_input_tdf.set_ampl_data(dat, ampl, { "categories": "CAT", "foods": "FOOD" }) ampl.solve() self.assertTrue("solved" == ampl.getValue("solve_result")) sln = _diet_sln_tdf.copy_from_ampl_variables({ ("buy_food", "Quantity"): ampl.getVariable("Buy"), ("consume_nutrition", "Quantity"): ampl.getVariable("Consume") }) sln.parameters['Total Cost'] = ampl.getObjective('Total_Cost').value() self.assertTrue(_nearly_same_dat(_diet_sln_tdf, sln, _diet_sln_ticdat)) dat = _diet_input_tdf.copy_to_ampl( _diet_dat, { ("foods", "Cost"): "cost", ("categories", "Min Nutrition"): "", ("categories", "Max Nutrition"): "n_max" }, ["nutrition_quantities"]) self.assertFalse(hasattr(dat, "nutrition_quantities")) self.assertTrue({"n_min", "n_max"}.intersection( dat.categories.toPandas().columns) == {"n_max"}) sln_tdf_2 = TicDatFactory(buy_food=[["Food"], ["Quantity"]], consume_nutrition=[["Category"], []]) sln_tdf_2.set_default_value("buy_food", "Quantity", 1) sln_2 = sln_tdf_2.copy_from_ampl_variables({ ("buy_food", False): ampl.getVariable("Buy"), ("consume_nutrition", False): (ampl.getVariable("Consume"), lambda x: x < 100) }) self.assertTrue( set(sln_2.buy_food) == set(sln.buy_food) and all(v["Quantity"] == 1 for v in sln_2.buy_food.values())) self.assertTrue(sln_2.consume_nutrition and set(sln_2.consume_nutrition) == { k for k, v in sln.consume_nutrition.items() if v["Quantity"] < 100 }) diet_dat_two = _diet_input_tdf.copy_tic_dat(_diet_dat) diet_dat_two.categories["calories"] = [0, 200] dat = _diet_input_tdf.copy_to_ampl( diet_dat_two, field_renamings={ ("foods", "Cost"): "cost", ("categories", "Min Nutrition"): "n_min", ("categories", "Max Nutrition"): "n_max", ("nutrition_quantities", "Quantity"): "amt", ("nutrition_quantities", "Other Quantity"): "other_amt" }) ampl = amplpy.AMPL() ampl.setOption('solver', 'gurobi') ampl.eval(_diet_mod) _diet_input_tdf.set_ampl_data(dat, ampl, { "categories": "CAT", "foods": "FOOD" }) ampl.solve() self.assertTrue("infeasible" == ampl.getValue("solve_result")) diet_dat_two = _diet_input_tdf.copy_tic_dat(_diet_dat) for v in diet_dat_two.categories.values(): v["Max Nutrition"] = float("inf") diet_dat_two.foods["hamburger"] = -1 dat = _diet_input_tdf.copy_to_ampl( diet_dat_two, field_renamings={ ("foods", "Cost"): "cost", ("categories", "Min Nutrition"): "n_min", ("categories", "Max Nutrition"): "n_max", ("nutrition_quantities", "Quantity"): "amt", ("nutrition_quantities", "Other Quantity"): "other_amt" }) ampl = amplpy.AMPL() ampl.setOption('solver', 'gurobi') ampl.eval(_diet_mod) _diet_input_tdf.set_ampl_data(dat, ampl, { "categories": "CAT", "foods": "FOOD" }) ampl.solve() self.assertTrue("unbounded" == ampl.getValue("solve_result"))
def _metro_solve(dat, sln_read_method="amplToDict", excluded_tables=frozenset( _metro_input_tdf.all_tables).difference({"load_amounts" })): assert sln_read_method in ["amplToDict", "ticdat"] input_schema = _metro_input_tdf ampl_format = utils.ampl_format AMPL = amplpy.AMPL default_parameters = { "One Way Price": 2.25, "Amount Leftover Constraint": "Upper Bound" } assert input_schema.good_tic_dat_object(dat) full_parameters = dict( default_parameters, **{k: v["Value"] for k, v in dat.parameters.items()}) sln = _metro_solution_tdf.TicDat() # create an empty solution ampl_dat = input_schema.copy_to_ampl(dat, excluded_tables=excluded_tables) # solve a distinct MIP for each pair of (# of one-way-trips, amount leftover) for number_trips, amount_leftover in product(dat.number_of_one_way_trips, dat.amount_leftover): ampl = AMPL() ampl.setOption('solver', 'gurobi') # use the ampl_format function for AMPL friendly key-named text substitutions ampl.eval( ampl_format(""" set LOAD_AMTS; var Num_Visits {LOAD_AMTS} integer >= 0; var Amt_Leftover >= {{amount_leftover_lb}}, <= {{amount_leftover_ub}}; minimize Total_Visits: sum {la in LOAD_AMTS} Num_Visits[la]; subj to Set_Amt_Leftover: Amt_Leftover = sum {la in LOAD_AMTS} la * Num_Visits[la] - {{one_way_price}} * {{number_trips}};""", number_trips=number_trips, one_way_price=full_parameters["One Way Price"], amount_leftover_lb=amount_leftover if full_parameters["Amount Leftover Constraint"] == "Equality" else 0, amount_leftover_ub=amount_leftover)) input_schema.set_ampl_data(ampl_dat, ampl, {"load_amounts": "LOAD_AMTS"}) ampl.solve() if ampl.getValue("solve_result") != "infeasible": # store the results if and only if the model is feasible if sln_read_method == "ticdat": temp_tdf = TicDatFactory( num_visits=[["Load Amount"], ["Number Of Visits"]]) temp_sln = temp_tdf.copy_from_ampl_variables({ ("num_visits", "Number Of Visits"): (ampl.getVariable("Num_Visits"), lambda _: round(_) > 0) }) for la, r in temp_sln.num_visits.items(): x = round(r["Number Of Visits"]) sln.load_amount_details[number_trips, amount_leftover, la] = round(x) sln.load_amount_summary[ number_trips, amount_leftover]["Number Of Visits"] += x else: for la, x in ampl.getVariable( "Num_Visits").getValues().toDict().items(): if round(x) > 0: sln.load_amount_details[number_trips, amount_leftover, la] = round(x) sln.load_amount_summary[number_trips, amount_leftover]["Number Of Visits"]\ += round(x) return sln