Coverage for moptipyapps / prodsched / rop_experiment.py: 33%
67 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 04:40 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 04:40 +0000
1"""
2A small template for ROP-based experiments.
4This experiment uses the NSGA-II algorithm to optimize Re-Order-Points (ROPs)
5to achieve both a high worst-case fillrate and a low worst-case average stock
6level.
7"""
10import argparse
11from typing import Final
13from moptipy.algorithms.mo.nsga2 import NSGA2
14from moptipy.api.experiment import run_experiment
15from moptipy.api.mo_execution import MOExecution
16from moptipy.mo.problem.weighted_sum import WeightedSum
17from moptipy.operators.intspace.op0_random import Op0Random
18from moptipy.operators.intspace.op1_mnormal import Op1MNormal
19from moptipy.operators.intspace.op2_uniform import Op2Uniform
20from moptipy.spaces.intspace import IntSpace
21from pycommons.io.console import logger
22from pycommons.io.path import Path
23from pycommons.types import check_int_range
25from moptipyapps.prodsched.instance import Instance
26from moptipyapps.prodsched.instances import get_instances
27from moptipyapps.prodsched.multistatistics import MultiStatisticsSpace
28from moptipyapps.prodsched.objectives.max_stocklevel import MaxStockLevel
29from moptipyapps.prodsched.objectives.worst_and_mean_fill_rate import (
30 WorstAndMeanFillRate,
31)
32from moptipyapps.prodsched.rop_multisimulation import ROPMultiSimulation
33from moptipyapps.utils.shared import moptipyapps_argparser
36def run(dest: str, instances: str, n_inst: int, n_runs: int,
37 max_fes: int, ps: int) -> None:
38 """
39 Run the experiment.
41 :param dest: the destination directory
42 :param instances: the directory with the instances
43 :param n_inst: the number of instances
44 :param n_runs: the number of runs
45 :param max_fes: the maximum FEs
46 :param ps: the population size
47 """
48 logger(f"Beginning experiment with dest={dest!r}, instances={instances!r}"
49 f", n_inst={n_inst}, n_runs={n_runs}, and max_fes={max_fes}.")
50 use_dest: Final[Path] = Path(dest)
51 use_dest.ensure_dir_exists()
52 logger(f"Destination folder is {use_dest!r}.")
54 use_insts: Final[Path] = Path(instances)
55 use_insts.ensure_dir_exists()
56 logger(f"Instances folder is {use_insts!r}.")
58 check_int_range(n_inst, "n_inst", 1, 128)
59 check_int_range(max_fes, "max_fes", 10, 10 ** 10)
60 check_int_range(ps, "ps", 4, 16384)
62 logger(f"Loading {n_inst} instances from {use_insts!r}.")
63 insts: Final[tuple[Instance, ...]] = get_instances(n_inst, instances)
64 if tuple.__len__(insts) != n_inst:
65 raise ValueError("Could not load required instances.")
66 logger(f"Loaded {n_inst} instances from {use_insts!r}.")
68 n_prod: int | None = None
69 for inst in insts:
70 if n_prod is None:
71 n_prod = inst.n_products
72 elif n_prod != inst.n_products:
73 raise ValueError("Inconsistent number of products!")
74 if n_prod is None:
75 raise ValueError("No instances?")
77 search_space: Final[IntSpace] = IntSpace(n_prod, 0, 63)
78 op0: Final[Op0Random] = Op0Random(search_space)
79 op1: Final[Op1MNormal] = Op1MNormal(search_space, sd=2.5)
80 op2: Final = Op2Uniform()
81 algo: Final[NSGA2] = NSGA2(op0, op1, op2, ps, 1 / min(16, ps))
82 encoding: Final[ROPMultiSimulation] = ROPMultiSimulation(insts)
83 f1: Final[WorstAndMeanFillRate] = WorstAndMeanFillRate()
84 f2: Final[MaxStockLevel] = MaxStockLevel()
85 ws: Final[WeightedSum] = WeightedSum((f1, f2), (
86 (1 / (f1.upper_bound() - f1.lower_bound())), 1 / (2 * n_prod)))
87 solution_space: Final[MultiStatisticsSpace] = MultiStatisticsSpace(insts)
89 def __setup(_) -> MOExecution:
90 """
91 Set up the experiment.
93 :return: the execution
94 """
95 return (MOExecution()
96 .set_search_space(search_space)
97 .set_algorithm(algo)
98 .set_solution_space(solution_space)
99 .set_objective(ws)
100 .set_encoding(encoding)
101 .set_max_fes(max_fes)
102 .set_log_improvements(True))
104 run_experiment(base_dir=use_dest, instances=(lambda: "all", ),
105 setups=(__setup, ), n_runs=n_runs,
106 pre_warmup_fes=2, perform_warmup=False,
107 perform_pre_warmup=True)
110# Run the experiment from the command line
111if __name__ == "__main__":
112 parser: Final[argparse.ArgumentParser] = moptipyapps_argparser(
113 __file__, "ROP-based MFC Optimization",
114 "Run a small experiment with ROP-based MFC optimization.")
115 parser.add_argument(
116 "dest", help="the directory to store the experimental results under",
117 type=Path, nargs="?", default="./results/")
118 parser.add_argument(
119 "insts", help="the directory with the instances",
120 type=Path, nargs="?", default="./instances/")
121 parser.add_argument(
122 "n_inst", help="the number of instances",
123 type=int, nargs="?", default=11)
124 parser.add_argument(
125 "n_runs", help="the number of runs",
126 type=int, nargs="?", default=31)
127 parser.add_argument(
128 "max_fes", help="the number of FEs per run",
129 type=int, nargs="?", default=8192)
130 parser.add_argument(
131 "ps", help="the population size of NSGA-II",
132 type=int, nargs="?", default=64)
133 args: Final[argparse.Namespace] = parser.parse_args()
134 run(args.dest, args.insts, args.n_inst, args.n_runs, args.max_fes,
135 args.ps)