def run_gsm_with_timeout(data_set_filename: str, gsm_type: GSM, timeout: int = 15) \ -> Optional[Dict]: """ Run the specified version of gsm """ execution_start_time = datetime.utcnow() _, gsm = create_gsm_instance(gsm_type, data_set_filename) signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) results = None try: solution = gsm.find_optimal_solution() # type: GSM_Solution signal.alarm(0) # Cancel timeout execution_time = (datetime.utcnow() - execution_start_time).total_seconds() safety_stocks = compute_expected_inventories(solution.policy, gsm.stages) base_stocks = compute_base_stocks(solution.policy, gsm.stages) results = dict(execution_time=execution_time, solution_cost=solution.cost, solution=solution.serialize(), safety_stocks=safety_stocks, base_stocks=base_stocks) except GSMException: print("The {} version of GSM timed out for {}".format( gsm_type, data_set_filename)) return results
def test_expected_inventories_and_basestocks_computations(): stages, gsm = create_gsm_instance(GSM.Tree, os.path.join(dirname, "bulldozer.txt")) sol = gsm.find_optimal_solution() expected_inventories = tree_gsm.compute_expected_inventories( sol.policy, stages) base_stocks = tree_gsm.compute_base_stocks(sol.policy, stages) assert len(stages) == len(base_stocks) assert len(base_stocks) == len(expected_inventories)
def test_against_basic_serial_network_experiment(): """ Hand coded answers were taken from Graves and Schoenmeyr 2016 (Table 5, No constraint row) """ stages = create_serial_stages(added_cost_prof="constant", lead_time_prof="upstream_heavy") gsm = GuaranteedServiceModelTree(stages) solution = gsm.find_optimal_solution(root_stage_id="4") # there is another policy with the same cost # it just happens that lead time and cost numbers add up this way assert int(solution.cost) == 368 safety_stocks = tree_gsm.compute_expected_inventories( solution.policy, stages) assert int(safety_stocks["5"]) == 240 assert int(safety_stocks["1"]) == 320
def test_against_gound_truth_camera(scenario, service_time_constraints, correct_cost): inventory_holding_rate = 0.24 stages, gsm = create_gsm_instance( GSM.Tree, os.path.join(dirname, "digital_camera.txt")) for stage_id, max_s_time in service_time_constraints: gsm.stages[stage_id].max_s_time = max_s_time sol = gsm.find_optimal_solution() sol = sol.serialize() solution_cost = sol["cost"] * inventory_holding_rate assert abs(solution_cost - correct_cost) / correct_cost < 0.01 policy = sol["policy"] inventories = tree_gsm.compute_expected_inventories(policy, gsm.stages) if scenario == 2: for stage_id in stages: if stage_id in [ "Camera", "Imager", "Circuit_Board", "Other_Parts_L_60", "Other_Parts_M_60", "Build_Test_Pack" ]: assert policy[stage_id]["s"] == 0 assert inventories[stage_id] > 0 else: assert inventories[stage_id] == 0 if stage_id == "Transfer": assert policy[stage_id]["s"] == 2 elif stage_id == "Ship": assert policy[stage_id]["s"] == 5 elif scenario == 4: for stage_id in stages: if stage_id in ["Build_Test_Pack", "Ship"]: assert inventories[stage_id] == 0 else: assert inventories[stage_id] > 0
def test_against_basic_serial_network_experiments_cap_location( added_cost_prof, lead_time_prof, cap_loc, cap_cost, exp_safety_stocks): """ Hand coded answers were taken from Graves and Schoenmeyr 2016 (Table 5) """ stages = create_serial_stages(added_cost_prof=added_cost_prof, lead_time_prof=lead_time_prof) stages[cap_loc].cap_constraint = 45 gsm = GuaranteedServiceModelTree(stages, propagate_bounds=True) solution = gsm.find_optimal_solution() safety_stocks = tree_gsm.compute_expected_inventories( solution.policy, stages) print(tree_gsm.compute_replenishment_times(solution.policy, stages)) assert abs(int(solution.cost) - cap_cost) <= 1 for stage_id in exp_safety_stocks: assert abs(safety_stocks[stage_id] - exp_safety_stocks[stage_id]) <= 1