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_dag_gsm(supply_chain_name, ref_cost, ref_stock): supply_chain_filename = os.path.join(dirname, supply_chain_name) stages = read_supply_chain_from_txt(supply_chain_filename) print(supply_chain_name) gsm = dag_gsm.GuaranteedServiceModelDAG(stages) solution = gsm.find_optimal_solution() base_stocks = tree_gsm.compute_base_stocks(solution.policy, stages) print(sum(i for i in base_stocks.values()), ref_stock) print(solution.cost, ref_cost, ref_cost / solution.cost) print()
def run_gsm(path, network, figpath, run_gsm_optimiser, plotting=True): # Load data supply_chain_filename = os.path.join(path, network) stages = read_supply_chain_from_txt(supply_chain_filename) # Run GSM gsm = GuaranteedServiceModelDAG(stages) if not run_gsm_optimiser: solution = None base_stocks = None else: solution = gsm.find_optimal_solution() base_stocks = tree_gsm.compute_base_stocks(solution.policy, stages) if plotting: plot_gsm(args.network, filename=os.path.join(figpath, network), stages=stages, base_stocks=base_stocks, solution=solution.serialize(), do_save=True) return gsm
def _run_branch_and_bound( self, root_stage_id: Optional[str] = None, constraints: Optional[GSM_Constraints] = None, init_with_basic_solution: bool = False) -> GSM_Solution: """ Main method that runs the iterative analogue of branch and bound. It corresponds to Routine R of GNA on page 783 in the main reference, but instead of using recursive calls to this subroutine it uses stack to process spanning sub_problems """ problem_counter = 0 initial_problem_constraints = {} # type: GSM_Constraints if constraints is not None: initial_problem_constraints = constraints global_min_cost = np.inf global_min_policy = {} # type: GSM_Policy if init_with_basic_solution: global_min_cost = compute_basic_solution_cost(self.stages) global_min_policy = { stage_id: { "s": 0, "si": 0 } for stage_id in self.stages } init_log2_complexity_bound = self._compute_log2_complexity_bound( initial_problem_constraints) removed_problems = 0 stack = [(problem_counter, initial_problem_constraints)] while stack: _, problem_constraints = stack.pop() log2_complexity_bound = self._compute_log2_complexity_bound( problem_constraints) assert log2_complexity_bound <= init_log2_complexity_bound, log2_complexity_bound #step 2 of routine R solution = self.tree_gsm.find_optimal_solution( root_stage_id=root_stage_id, constraints=problem_constraints) #step 3 of routine R if np.isinf(solution.cost): removed_problems += np.exp2(log2_complexity_bound) self._print_progress(init_log2_complexity_bound, problem_counter + 1, removed_problems) continue if solution.cost >= global_min_cost: removed_problems += np.exp2(log2_complexity_bound) self._print_progress(init_log2_complexity_bound, problem_counter + 1, removed_problems) continue #step 4 of routine R broken_constraints = find_unsatisfied_constraints( solution.policy, self.stages) if not broken_constraints: global_min_cost = solution.cost global_min_policy = solution.policy removed_problems += np.exp2(log2_complexity_bound) self._print_progress(init_log2_complexity_bound, problem_counter + 1, removed_problems) continue #step 5 of routine R corrected_solution_policy = correct_policy_downstream( solution.policy, self.stages) corrected_solution_cost = compute_total_inventory_cost( corrected_solution_policy, self.stages) if corrected_solution_cost < global_min_cost: global_min_cost = corrected_solution_cost global_min_policy = corrected_solution_policy #step 5(a) if self._use_random_ST: broken_link = list(broken_constraints.keys())[0] else: broken_link = min(broken_constraints.keys(), key=self._get_link_cost) u_stage_id, d_stage_id = broken_link s_value, si_value = broken_constraints[broken_link] assert s_value > si_value new_level = si_value + int((s_value - si_value) / 2.) #step 5(b) lowerbound_problem_constraints = {**problem_constraints} for d_stage_id in self.stages[u_stage_id].down_stages: lowerbound_problem_constraints[( d_stage_id, "min_si")] = new_level + 1 # higher than problem_counter += 1 stack.append((problem_counter, lowerbound_problem_constraints)) upperbound_problem_constraints = {**problem_constraints} upperbound_problem_constraints[( u_stage_id, "max_s")] = new_level # lower than or equal problem_counter += 1 stack.append((problem_counter, upperbound_problem_constraints)) base_stocks = compute_base_stocks(global_min_policy, self.stages) solution = GSM_Solution(cost=global_min_cost, policy=global_min_policy, base_stocks=base_stocks) return solution