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)
Exemple #3
0
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