From 19fa10f98bf16c25a132830149a5717329dc4f22 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 22 Mar 2023 17:22:24 +0100 Subject: [PATCH 01/44] Package upgrade & gymnasium interface update --- Makefile | 107 ++ build/lib/dacbench/__init__.py | 8 + build/lib/dacbench/abstract_agent.py | 57 ++ build/lib/dacbench/abstract_benchmark.py | 567 +++++++++++ build/lib/dacbench/abstract_env.py | 374 +++++++ build/lib/dacbench/agents/__init__.py | 5 + .../dacbench/agents/dynamic_random_agent.py | 30 + build/lib/dacbench/agents/generic_agent.py | 16 + build/lib/dacbench/agents/simple_agents.py | 36 + build/lib/dacbench/argument_parsing.py | 69 ++ build/lib/dacbench/benchmarks/__init__.py | 73 ++ .../lib/dacbench/benchmarks/cma_benchmark.py | 162 ++++ .../benchmarks/fast_downward_benchmark.py | 192 ++++ .../benchmarks/geometric_benchmark.py | 304 ++++++ .../lib/dacbench/benchmarks/luby_benchmark.py | 189 ++++ .../dacbench/benchmarks/modcma_benchmark.py | 134 +++ .../dacbench}/benchmarks/modea_benchmark.py | 0 .../lib/dacbench/benchmarks/sgd_benchmark.py | 219 +++++ .../dacbench/benchmarks/sigmoid_benchmark.py | 254 +++++ .../dacbench/benchmarks/theory_benchmark.py | 169 ++++ .../dacbench/benchmarks/toysgd_benchmark.py | 122 +++ build/lib/dacbench/container/__init__.py | 0 .../lib/dacbench/container/container_utils.py | 191 ++++ build/lib/dacbench/container/remote_env.py | 81 ++ build/lib/dacbench/container/remote_runner.py | 278 ++++++ build/lib/dacbench/envs/__init__.py | 81 ++ build/lib/dacbench/envs/cma_es.py | 255 +++++ build/lib/dacbench/envs/cma_step_size.py | 54 ++ build/lib/dacbench/envs/fast_downward.py | 452 +++++++++ build/lib/dacbench/envs/geometric.py | 665 +++++++++++++ build/lib/dacbench/envs/luby.py | 180 ++++ build/lib/dacbench/envs/modcma.py | 60 ++ .../lib/dacbench}/envs/modea.py | 11 +- build/lib/dacbench/envs/policies/__init__.py | 14 + build/lib/dacbench/envs/policies/csa_cma.py | 7 + .../lib/dacbench/envs/policies/optimal_fd.py | 8 + .../dacbench/envs/policies/optimal_luby.py | 14 + .../dacbench/envs/policies/optimal_sigmoid.py | 25 + build/lib/dacbench/envs/policies/sgd_ca.py | 33 + build/lib/dacbench/envs/sgd.py | 891 +++++++++++++++++ build/lib/dacbench/envs/sigmoid.py | 325 +++++++ build/lib/dacbench/envs/theory.py | 574 +++++++++++ build/lib/dacbench/envs/toysgd.py | 234 +++++ build/lib/dacbench/logger.py | 915 ++++++++++++++++++ build/lib/dacbench/plotting.py | 557 +++++++++++ build/lib/dacbench/run_baselines.py | 248 +++++ build/lib/dacbench/runner.py | 94 ++ build/lib/dacbench/wrappers/__init__.py | 20 + .../wrappers/action_tracking_wrapper.py | 259 +++++ .../dacbench/wrappers/episode_time_tracker.py | 243 +++++ .../wrappers/instance_sampling_wrapper.py | 112 +++ .../dacbench/wrappers/observation_wrapper.py | 106 ++ .../wrappers/performance_tracking_wrapper.py | 204 ++++ .../wrappers/policy_progress_wrapper.py | 107 ++ .../dacbench/wrappers/reward_noise_wrapper.py | 119 +++ .../wrappers/state_tracking_wrapper.py | 289 ++++++ dacbench/abstract_benchmark.py | 19 +- dacbench/abstract_env.py | 29 +- dacbench/agents/dynamic_random_agent.py | 2 +- dacbench/agents/simple_agents.py | 2 +- dacbench/benchmarks/__init__.py | 11 - dacbench/benchmarks/cma_benchmark.py | 2 +- dacbench/benchmarks/sgd_benchmark.py | 2 +- dacbench/benchmarks/theory_benchmark.py | 2 +- dacbench/benchmarks/toysgd_benchmark.py | 2 +- dacbench/container/container_utils.py | 40 +- .../container/singularity_recipes/cma.def | 2 +- .../singularity_recipes/dacbench.def | 2 +- .../singularity_recipes/geometric.def | 2 +- .../container/singularity_recipes/modcma.def | 2 +- .../container/singularity_recipes/modea.def | 2 +- .../singularity_recipes/recipe_template | 2 +- .../container/singularity_recipes/sgd.def | 2 +- .../container/singularity_recipes/theory.def | 2 +- dacbench/envs/__init__.py | 11 - dacbench/envs/cma_es.py | 16 +- dacbench/envs/cma_step_size.py | 12 +- dacbench/envs/fast_downward.py | 22 +- dacbench/envs/geometric.py | 22 +- dacbench/envs/luby.py | 12 +- dacbench/envs/modcma.py | 12 +- dacbench/envs/sgd.py | 26 +- dacbench/envs/sigmoid.py | 12 +- dacbench/envs/theory.py | 22 +- dacbench/envs/toysgd.py | 17 +- dacbench/runner.py | 8 +- dacbench/wrappers/action_tracking_wrapper.py | 8 +- dacbench/wrappers/episode_time_tracker.py | 12 +- dacbench/wrappers/observation_wrapper.py | 16 +- .../wrappers/performance_tracking_wrapper.py | 6 +- dacbench/wrappers/policy_progress_wrapper.py | 10 +- dacbench/wrappers/reward_noise_wrapper.py | 8 +- dacbench/wrappers/state_tracking_wrapper.py | 21 +- other_requirements/cma.json | 4 +- other_requirements/geometric.json | 6 +- other_requirements/modcma.json | 6 +- other_requirements/modea.json | 8 +- other_requirements/sgd.json | 7 +- other_requirements/theory.json | 4 +- requirements.txt | 15 - setup.cfg | 129 ++- tests/agents/test_dynamic_random_agent.py | 9 +- tests/benchmarks/test_fd_benchmark.py | 5 +- tests/benchmarks/test_luby_benchmark.py | 7 +- tests/benchmarks/test_modea_benchmark.py | 48 - tests/benchmarks/test_sigmoid_benchmark.py | 5 +- tests/container/test_container_utils.py | 16 +- tests/envs/test_cma.py | 11 +- tests/envs/test_deterministic.py | 29 +- tests/envs/test_fd.py | 5 +- tests/envs/test_geometric.py | 8 +- tests/envs/test_luby.py | 13 +- tests/envs/test_modcma.py | 15 +- tests/envs/test_modea.py | 48 - tests/envs/test_sgd.py | 33 +- tests/envs/test_sigmoid.py | 8 +- tests/envs/test_theory_env.py | 10 +- tests/test_abstract_benchmark.py | 2 +- tests/test_abstract_env.py | 10 +- tests/test_logger.py | 16 +- tests/test_runner.py | 2 +- .../wrappers/test_action_tracking_wrapper.py | 281 +----- tests/wrappers/test_observation_wrapper.py | 14 +- .../test_performance_tracking_wrapper.py | 66 +- .../wrappers/test_policy_progress_wrapper.py | 12 +- tests/wrappers/test_reward_noise_wrapper.py | 10 +- tests/wrappers/test_state_tracking_wrapper.py | 30 +- tests/wrappers/test_time_tracking_wrapper.py | 8 +- 128 files changed, 11284 insertions(+), 809 deletions(-) create mode 100644 Makefile create mode 100644 build/lib/dacbench/__init__.py create mode 100644 build/lib/dacbench/abstract_agent.py create mode 100644 build/lib/dacbench/abstract_benchmark.py create mode 100644 build/lib/dacbench/abstract_env.py create mode 100644 build/lib/dacbench/agents/__init__.py create mode 100644 build/lib/dacbench/agents/dynamic_random_agent.py create mode 100644 build/lib/dacbench/agents/generic_agent.py create mode 100644 build/lib/dacbench/agents/simple_agents.py create mode 100644 build/lib/dacbench/argument_parsing.py create mode 100644 build/lib/dacbench/benchmarks/__init__.py create mode 100644 build/lib/dacbench/benchmarks/cma_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/fast_downward_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/geometric_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/luby_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/modcma_benchmark.py rename {dacbench => build/lib/dacbench}/benchmarks/modea_benchmark.py (100%) create mode 100644 build/lib/dacbench/benchmarks/sgd_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/sigmoid_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/theory_benchmark.py create mode 100644 build/lib/dacbench/benchmarks/toysgd_benchmark.py create mode 100644 build/lib/dacbench/container/__init__.py create mode 100644 build/lib/dacbench/container/container_utils.py create mode 100644 build/lib/dacbench/container/remote_env.py create mode 100644 build/lib/dacbench/container/remote_runner.py create mode 100644 build/lib/dacbench/envs/__init__.py create mode 100644 build/lib/dacbench/envs/cma_es.py create mode 100644 build/lib/dacbench/envs/cma_step_size.py create mode 100644 build/lib/dacbench/envs/fast_downward.py create mode 100644 build/lib/dacbench/envs/geometric.py create mode 100644 build/lib/dacbench/envs/luby.py create mode 100644 build/lib/dacbench/envs/modcma.py rename {dacbench => build/lib/dacbench}/envs/modea.py (97%) create mode 100644 build/lib/dacbench/envs/policies/__init__.py create mode 100644 build/lib/dacbench/envs/policies/csa_cma.py create mode 100644 build/lib/dacbench/envs/policies/optimal_fd.py create mode 100644 build/lib/dacbench/envs/policies/optimal_luby.py create mode 100644 build/lib/dacbench/envs/policies/optimal_sigmoid.py create mode 100644 build/lib/dacbench/envs/policies/sgd_ca.py create mode 100644 build/lib/dacbench/envs/sgd.py create mode 100644 build/lib/dacbench/envs/sigmoid.py create mode 100644 build/lib/dacbench/envs/theory.py create mode 100644 build/lib/dacbench/envs/toysgd.py create mode 100644 build/lib/dacbench/logger.py create mode 100644 build/lib/dacbench/plotting.py create mode 100644 build/lib/dacbench/run_baselines.py create mode 100644 build/lib/dacbench/runner.py create mode 100644 build/lib/dacbench/wrappers/__init__.py create mode 100644 build/lib/dacbench/wrappers/action_tracking_wrapper.py create mode 100644 build/lib/dacbench/wrappers/episode_time_tracker.py create mode 100644 build/lib/dacbench/wrappers/instance_sampling_wrapper.py create mode 100644 build/lib/dacbench/wrappers/observation_wrapper.py create mode 100644 build/lib/dacbench/wrappers/performance_tracking_wrapper.py create mode 100644 build/lib/dacbench/wrappers/policy_progress_wrapper.py create mode 100644 build/lib/dacbench/wrappers/reward_noise_wrapper.py create mode 100644 build/lib/dacbench/wrappers/state_tracking_wrapper.py delete mode 100644 requirements.txt delete mode 100644 tests/benchmarks/test_modea_benchmark.py delete mode 100644 tests/envs/test_modea.py diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..5cd960663 --- /dev/null +++ b/Makefile @@ -0,0 +1,107 @@ +# NOTE: Used on linux, limited support outside of Linux +# +# A simple makefile to help with small tasks related to development of CARL +# These have been configured to only really run short tasks. Longer form tasks +# are usually completed in github actions. + +.PHONY: help install-dev check format pre-commit clean build clean-doc clean-build test doc publish + +help: + @echo "Makefile DACBench" + @echo "* install-dev to install all dev requirements and install pre-commit" + @echo "* check to check the source code for issues" + @echo "* format to format the code with black and isort" + @echo "* pre-commit to run the pre-commit check" + @echo "* clean to clean the dist and doc build files" + @echo "* build to build a dist" + @echo "* test to run the tests" + @echo "* doc to generate and view the html files" + @echo "* publish to help publish the current branch to pypi" + +PYTHON ?= python +CYTHON ?= cython +PYTEST ?= python -m pytest +CTAGS ?= ctags +PIP ?= python -m pip +MAKE ?= make +BLACK ?= black +ISORT ?= isort +PYDOCSTYLE ?= pydocstyle +MYPY ?= mypy +PRECOMMIT ?= pre-commit +FLAKE8 ?= flake8 + +DIR := ${CURDIR} +DIST := ${CURDIR}/dist +DOCDIR := ${DIR}/docs +INDEX_HTML := file://${DOCDIR}/html/build/index.html + +install-dev: + $(PIP) install -e ".[dev, docs, all, examples]" + pre-commit install + +check-black: + $(BLACK) dacbench tests --check || : + +check-isort: + $(ISORT) dacbench tests --check || : + +check-pydocstyle: + $(PYDOCSTYLE) dacbench || : + +check-mypy: + $(MYPY) dacbench || : + +check-flake8: + $(FLAKE8) dacbench || : + $(FLAKE8) tests || : + +# pydocstyle does not have easy ignore rules, instead, we include as they are covered +check: check-black check-isort check-mypy check-flake8 # check-pydocstyle + +pre-commit: + $(PRECOMMIT) run --all-files + +format-black: + $(BLACK) dacbench tests + +format-isort: + $(ISORT) dacbench tests + +format: format-black format-isort + +test: + $(PYTEST) tests + +clean-doc: + $(MAKE) -C ${DOCDIR} clean + +clean-build: + $(PYTHON) setup.py clean + rm -rf ${DIST} + +# Clean up any builds in ./dist as well as doc +clean: clean-doc clean-build + +# Build a distribution in ./dist +build: + $(PYTHON) setup.py sdist + +doc: + $(MAKE) -C ${DOCDIR} all + @echo + @echo "View docs at:" + @echo ${INDEX_HTML} + +# Publish to testpypi +# Will echo the commands to actually publish to be run to publish to actual PyPi +# This is done to prevent accidental publishing but provide the same conveniences +publish: clean-build build + $(PIP) install twine + $(PYTHON) -m twine upload --repository testpypi ${DIST}/* + @echo + @echo "Test with the following line:" + @echo "pip install --index-url https://test.pypi.org/simple/ dacbench" + @echo + @echo "Once you have decided it works, publish to actual pypi with" + @echo "python -m twine upload dist/*" \ No newline at end of file diff --git a/build/lib/dacbench/__init__.py b/build/lib/dacbench/__init__.py new file mode 100644 index 000000000..08e6071b6 --- /dev/null +++ b/build/lib/dacbench/__init__.py @@ -0,0 +1,8 @@ +"""DACBench: a benchmark library for Dynamic Algorithm Configuration""" +__version__ = "0.0.1" +__contact__ = "automl.org" + +from dacbench.abstract_env import AbstractEnv +from dacbench.abstract_benchmark import AbstractBenchmark + +__all__ = ["AbstractEnv", "AbstractBenchmark"] diff --git a/build/lib/dacbench/abstract_agent.py b/build/lib/dacbench/abstract_agent.py new file mode 100644 index 000000000..58016ca13 --- /dev/null +++ b/build/lib/dacbench/abstract_agent.py @@ -0,0 +1,57 @@ +class AbstractDACBenchAgent: + """ Abstract class to implement for use with the runner function """ + + def __init__(self, env): + """ + Initialize agent + + Parameters + ------- + env : gym.Env + Environment to train on + """ + pass + + def act(self, state, reward): + """ + Compute and return environment action + + Parameters + ------- + state + Environment state + reward + Environment reward + + Returns + ------- + action + Action to take + """ + raise NotImplementedError + + def train(self, next_state, reward): + """ + Train during episode if needed (pass if not) + + Parameters + ------- + next_state + Environment state after step + reward + Environment reward + """ + raise NotImplementedError + + def end_episode(self, state, reward): + """ + End of episode training if needed (pass if not) + + Parameters + ------- + state + Environment state + reward + Environment reward + """ + raise NotImplementedError diff --git a/build/lib/dacbench/abstract_benchmark.py b/build/lib/dacbench/abstract_benchmark.py new file mode 100644 index 000000000..679b37be8 --- /dev/null +++ b/build/lib/dacbench/abstract_benchmark.py @@ -0,0 +1,567 @@ +import json +from types import FunctionType + +import numpy as np +from gymnasium import spaces +from functools import partial +from dacbench import wrappers + +# from dacbench import ModuleLogger + + +class AbstractBenchmark: + """ + Abstract template for benchmark classes + """ + + def __init__(self, config_path=None, config: "objdict" = None): + """ + Initialize benchmark class + + Parameters + ------- + config_path : str + Path to load configuration from (if read from file) + config : objdict + Object dict containing the config + """ + if config is not None and config_path is not None: + raise ValueError("Both path to config and config where provided") + self.wrap_funcs = [] + if config_path: + self.config_path = config_path + self.read_config_file(self.config_path) + elif config: + self.load_config(config) + else: + self.config = None + + def get_config(self): + """ + Return current configuration + + Returns + ------- + dict + Current config + """ + return self.config + + def serialize_config(self): + """ + Save configuration to json + + Parameters + ---------- + path : str + File to save config to + """ + conf = self.config.copy() + if "observation_space_type" in self.config: + conf["observation_space_type"] = f"{self.config['observation_space_type']}" + if isinstance(conf["observation_space_args"][0], dict): + conf["observation_space_args"] = self.jsonify_dict_space( + conf["observation_space_args"][0] + ) + elif "observation_space" in self.config: + conf["observation_space"] = self.space_to_list(conf["observation_space"]) + + if "action_space" in self.config: + conf["action_space"] = self.space_to_list(conf["action_space"]) + + # TODO: how can we use the built in serialization of configspace here? + if "config_space" in self.config: + conf["config_space"] = self.process_configspace(self.config.config_space) + + conf = AbstractBenchmark.__stringify_functions(conf) + + for k in self.config.keys(): + if isinstance(self.config[k], np.ndarray) or isinstance( + self.config[k], list + ): + if type(self.config[k][0]) == np.ndarray: + conf[k] = list(map(list, conf[k])) + for i in range(len(conf[k])): + if ( + not type(conf[k][i][0]) == float + and np.inf not in conf[k][i] + and -np.inf not in conf[k][i] + ): + conf[k][i] = list(map(int, conf[k][i])) + elif isinstance(conf[k], np.ndarray): + conf[k] = conf[k].tolist() + + conf["wrappers"] = self.jsonify_wrappers() + + # can be recovered from instance_set_path, and could contain function that are not serializable + if "instance_set" in conf: + del conf["instance_set"] + + return conf + + def process_configspace(self, configuration_space): + """ + This is largely the builting cs.json.write method, but doesn't save the result directly + If this is ever implemented in cs, we can replace this method + """ + from ConfigSpace.configuration_space import ConfigurationSpace + from ConfigSpace.hyperparameters import ( + CategoricalHyperparameter, + UniformIntegerHyperparameter, + UniformFloatHyperparameter, + NormalIntegerHyperparameter, + NormalFloatHyperparameter, + OrdinalHyperparameter, + Constant, + UnParametrizedHyperparameter, + ) + from ConfigSpace.read_and_write.json import ( + _build_constant, + _build_condition, + _build_ordinal, + _build_forbidden, + _build_categorical, + _build_normal_int, + _build_normal_float, + _build_uniform_float, + _build_uniform_int, + _build_unparametrized_hyperparameter, + ) + + if not isinstance(configuration_space, ConfigurationSpace): + raise TypeError( + "pcs_parser.write expects an instance of %s, " + "you provided '%s'" % (ConfigurationSpace, type(configuration_space)) + ) + + hyperparameters = [] + conditions = [] + forbiddens = [] + + for hyperparameter in configuration_space.get_hyperparameters(): + + if isinstance(hyperparameter, Constant): + hyperparameters.append(_build_constant(hyperparameter)) + elif isinstance(hyperparameter, UnParametrizedHyperparameter): + hyperparameters.append( + _build_unparametrized_hyperparameter(hyperparameter) + ) + elif isinstance(hyperparameter, UniformFloatHyperparameter): + hyperparameters.append(_build_uniform_float(hyperparameter)) + elif isinstance(hyperparameter, NormalFloatHyperparameter): + hyperparameters.append(_build_normal_float(hyperparameter)) + elif isinstance(hyperparameter, UniformIntegerHyperparameter): + hyperparameters.append(_build_uniform_int(hyperparameter)) + elif isinstance(hyperparameter, NormalIntegerHyperparameter): + hyperparameters.append(_build_normal_int(hyperparameter)) + elif isinstance(hyperparameter, CategoricalHyperparameter): + hyperparameters.append(_build_categorical(hyperparameter)) + elif isinstance(hyperparameter, OrdinalHyperparameter): + hyperparameters.append(_build_ordinal(hyperparameter)) + else: + raise TypeError( + "Unknown type: %s (%s)" % (type(hyperparameter), hyperparameter,) + ) + + for condition in configuration_space.get_conditions(): + conditions.append(_build_condition(condition)) + + for forbidden_clause in configuration_space.get_forbiddens(): + forbiddens.append(_build_forbidden(forbidden_clause)) + + rval = {} + if configuration_space.name is not None: + rval["name"] = configuration_space.name + rval["hyperparameters"] = hyperparameters + rval["conditions"] = conditions + rval["forbiddens"] = forbiddens + + return rval + + @classmethod + def from_json(cls, json_config): + config = objdict(json.loads(json_config)) + if "config_space" in config.keys(): + from ConfigSpace import ConfigurationSpace + from ConfigSpace.read_and_write.json import ( + _construct_hyperparameter, + _construct_forbidden, + _construct_condition, + ) + + if "name" in config.config_space: + configuration_space = ConfigurationSpace( + name=config.config_space["name"] + ) + else: + configuration_space = ConfigurationSpace() + + for hyperparameter in config.config_space["hyperparameters"]: + configuration_space.add_hyperparameter( + _construct_hyperparameter(hyperparameter,) + ) + + for condition in config.config_space["conditions"]: + configuration_space.add_condition( + _construct_condition(condition, configuration_space,) + ) + + for forbidden in config.config_space["forbiddens"]: + configuration_space.add_forbidden_clause( + _construct_forbidden(forbidden, configuration_space,) + ) + config.config_space = configuration_space + + return cls(config=config) + + def to_json(self): + conf = self.serialize_config() + return json.dumps(conf) + + def save_config(self, path): + conf = self.serialize_config() + with open(path, "w") as fp: + json.dump(conf, fp, default=lambda o: "not serializable") + + def jsonify_wrappers(self): + wrappers = [] + for func in self.wrap_funcs: + args = func.args + arg_descriptions = [] + contains_func = False + func_dict = {} + for i in range(len(args)): + if callable(args[i]): + contains_func = True + func_dict[f"{args[i]}"] = [args[i].__module__, args[i].__name__] + arg_descriptions.append(["function", f"{args[i]}"]) + # elif isinstance(args[i], ModuleLogger): + # pass + else: + arg_descriptions.append({args[i]}) + function = func.func.__name__ + if contains_func: + wrappers.append([function, arg_descriptions, func_dict]) + else: + wrappers.append([function, arg_descriptions]) + return wrappers + + def dejson_wrappers(self, wrapper_list): + for i in range(len(wrapper_list)): + import importlib + + func = getattr(wrappers, wrapper_list[i][0]) + arg_descriptions = wrapper_list[i][1] + args = [] + for a in arg_descriptions: + if a[0] == "function": + module = importlib.import_module(wrapper_list[i][2][a[1]][0]) + name = wrapper_list[i][2][a[1]][0] + func = getattr(module, name) + args.append(func) + # elif a[0] == "logger": + # pass + else: + args.append(a) + + self.wrap_funcs.append(partial(func, *args)) + + @staticmethod + def __import_from(module: str, name: str): + """ + Imports the class / function / ... with name from module + Parameters + ---------- + module + name + + Returns + ------- + the imported object + """ + module = __import__(module, fromlist=[name]) + return getattr(module, name) + + @classmethod + def class_to_str(cls): + return cls.__module__, cls.__name__ + + @staticmethod + def __decorate_config_with_functions(conf: dict): + """ + Replaced the stringified functions with the callable objects + Parameters + ---------- + config + + Returns + ------- + + """ + for key, value in { + k: v + for k, v in conf.items() + if isinstance(v, list) and len(v) == 3 and v[0] == "function" + }.items(): + _, module_name, function_name = value + conf[key] = AbstractBenchmark.__import_from(module_name, function_name) + return conf + + @staticmethod + def __stringify_functions(conf: dict) -> dict: + """ + Replaced all callables in the config with a + triple ('function', module_name, function_name) + + Parameters + ---------- + config + + Returns + ------- + modified dict + """ + for key, value in { + k: v for k, v in conf.items() if isinstance(v, FunctionType) + }.items(): + conf[key] = ["function", conf[key].__module__, conf[key].__name__] + return conf + + def space_to_list(self, space): + res = [] + if isinstance(space, spaces.Box): + res.append("Box") + res.append([space.low.tolist(), space.high.tolist()]) + res.append("numpy.float32") + elif isinstance(space, spaces.Discrete): + res.append("Discrete") + res.append([space.n]) + elif isinstance(space, spaces.Dict): + res.append("Dict") + res.append(self.jsonify_dict_space(space.spaces)) + elif isinstance(space, spaces.MultiDiscrete): + res.append("MultiDiscrete") + res.append([space.nvec]) + elif isinstance(space, spaces.MultiBinary): + res.append("MultiBinary") + res.append([space.n]) + return res + + def list_to_space(self, space_list): + if space_list[0] == "Dict": + args = self.dictify_json(space_list[1]) + space = getattr(spaces, space_list[0])(args) + elif len(space_list) == 2: + space = getattr(spaces, space_list[0])(*space_list[1]) + else: + typestring = space_list[2].split(".")[1] + dt = getattr(np, typestring) + args = [np.array(arg) for arg in space_list[1]] + space = getattr(spaces, space_list[0])(*args, dtype=dt) + return space + + def jsonify_dict_space(self, dict_space): + keys = [] + types = [] + arguments = [] + for k in dict_space.keys(): + keys.append(k) + value = dict_space[k] + if not isinstance(value, (spaces.Box, spaces.Discrete)): + raise ValueError( + f"Only Dict spaces made up of Box spaces or discrete spaces are supported but got {type(value)}" + ) + + if isinstance(value, spaces.Box): + types.append("box") + low = value.low.tolist() + high = value.high.tolist() + arguments.append([low, high]) + + if isinstance(value, spaces.Discrete): + types.append("discrete") + n = value.n + arguments.append([n]) + return [keys, types, arguments] + + def dictify_json(self, dict_list): + dict_space = {} + keys, types, args = dict_list + for k, type, args_ in zip(keys, types, args): + prepared_args = map(np.array, args_) + if type == "box": + dict_space[k] = spaces.Box(*prepared_args, dtype=np.float32) + elif type == "discrete": + dict_space[k] = spaces.Discrete(*prepared_args) + else: + raise TypeError( + f"Currently only Discrete and Box spaces are allowed in Dict spaces, got {type}" + ) + return dict_space + + def load_config(self, config: "objdict"): + self.config = config + if "observation_space_type" in self.config: + # Types have to be numpy dtype (for gym spaces)s + if type(self.config["observation_space_type"]) == str: + if self.config["observation_space_type"] == "None": + self.config["observation_space_type"] = None + else: + typestring = self.config["observation_space_type"].split(" ")[1][ + :-2 + ] + typestring = typestring.split(".")[1] + self.config["observation_space_type"] = getattr(np, typestring) + + if "observation_space" in self.config: + self.config["observation_space"] = self.list_to_space( + self.config["observation_space"] + ) + + elif "observation_space_class" in config.keys(): + if config.observation_space_class == "Dict": + self.config["observation_space_args"] = [ + self.dictify_json(self.config["observation_space_args"]) + ] + + if "action_space" in self.config: + self.config["action_space"] = self.list_to_space( + self.config["action_space"] + ) + + if "wrappers" in self.config: + self.dejson_wrappers(self.config["wrappers"]) + del self.config["wrappers"] + + self.config = AbstractBenchmark.__decorate_config_with_functions(self.config) + + for k in self.config.keys(): + if type(self.config[k]) == list: + if type(self.config[k][0]) == list: + map(np.array, self.config[k]) + self.config[k] = np.array(self.config[k]) + + def read_config_file(self, path): + """ + Read configuration from file + + Parameters + ---------- + path : str + Path to config file + """ + with open(path, "r") as fp: + config = objdict(json.load(fp)) + + self.load_config(config) + + def get_environment(self): + """ + Make benchmark environment + + Returns + ------- + env : gym.Env + Benchmark environment + """ + raise NotImplementedError + + def set_seed(self, seed): + """ + Set environment seed + + Parameters + ---------- + seed : int + New seed + """ + self.config["seed"] = seed + + def set_action_space(self, kind, args): + """ + Change action space + + Parameters + ---------- + kind : str + Name of action space class + args: list + List of arguments to pass to action space class + """ + self.config["action_space"] = kind + self.config["action_space_args"] = args + + def set_observation_space(self, kind, args, data_type): + """ + Change observation_space + + Parameters + ---------- + kind : str + Name of observation space class + args : list + List of arguments to pass to observation space class + data_type : type + Data type of observation space + """ + self.config["observation_space"] = kind + self.config["observation_space_args"] = args + self.config["observation_space_type"] = data_type + + def register_wrapper(self, wrap_func): + if isinstance(wrap_func, list): + self.wrap_funcs.append(*wrap_func) + else: + self.wrap_funcs.append(wrap_func) + + def __eq__(self, other): + return type(self) == type(other) and self.config == other.config + + +# This code is taken from https://goodcode.io/articles/python-dict-object/ +class objdict(dict): + """ + Modified dict to make config changes more flexible + """ + + def __getattr__(self, name): + if name in self: + return self[name] + else: + raise AttributeError("No such attribute: " + name) + + def __setattr__(self, name, value): + self[name] = value + + def __delattr__(self, name): + if name in self: + del self[name] + else: + raise AttributeError("No such attribute: " + name) + + def copy(self): + return objdict(**super().copy()) + + def __eq__(self, other): + """return isinstance(other, dict) \ + and set(other.keys()) == set(self.keys()) \ + and all( + np.array_equal(self[key], other[key]) + if any(isinstance(obj[key], np.ndarray) for obj in (self, other)) + else other[key] == self[key] + for key in self.keys() + )""" + if not isinstance(other, dict): + return False + if not set(other.keys()) == set(self.keys()): + return False + truth = [] + for key in self.keys(): + if any(isinstance(obj[key], np.ndarray) for obj in (self, other)): + truth.append(np.array_equal(self[key], other[key])) + else: + truth.append(other[key] == self[key]) + return all(truth) + + def __ne__(self, other): + return not self == other diff --git a/build/lib/dacbench/abstract_env.py b/build/lib/dacbench/abstract_env.py new file mode 100644 index 000000000..373259a14 --- /dev/null +++ b/build/lib/dacbench/abstract_env.py @@ -0,0 +1,374 @@ +import random + +import gymnasium as gym +from gymnasium.utils import seeding +import numpy as np + + +class AbstractEnv(gym.Env): + """ + Abstract template for environments + """ + + def __init__(self, config): + """ + Initialize environment + + Parameters + ------- + config : dict + Environment configuration + If to seed the action space as well + """ + super(AbstractEnv, self).__init__() + self.config = config + if "instance_update_func" in self.config.keys(): + self.instance_updates = self.config["instance_update_func"] + else: + self.instance_updates = "round_robin" + self.instance_set = config["instance_set"] + self.instance_id_list = sorted(list(self.instance_set.keys())) + self.instance_index = 0 + self.inst_id = self.instance_id_list[self.instance_index] + self.instance = self.instance_set[self.inst_id] + + self.test = False + if "test_set" in self.config.keys(): + self.test_set = config["test_set"] + self.test_instance_id_list = sorted(list(self.test_set.keys())) + self.test_instance_index = 0 + self.test_inst_id = self.test_instance_id_list[self.test_instance_index] + self.test_instance = self.test_set[self.test_inst_id] + + self.training_set = self.instance_set + self.training_id_list = self.instance_id_list + self.training_inst_id = self.inst_id + self.training_instance = self.instance + else: + self.test_set = None + + self.benchmark_info = config["benchmark_info"] + self.initial_seed = None + self.np_random = None + + self.n_steps = config["cutoff"] + self.c_step = 0 + + self.reward_range = config["reward_range"] + + if "observation_space" in config.keys(): + self.observation_space = config["observation_space"] + else: + if not config["observation_space_class"] == "Dict": + try: + self.observation_space = getattr( + gym.spaces, config["observation_space_class"] + )( + *config["observation_space_args"], + dtype=config["observation_space_type"], + ) + except KeyError: + print( + "Either submit a predefined gym.space 'observation_space' or an 'observation_space_class' as well as a list of 'observation_space_args' and the 'observation_space_type' in the configuration." + ) + print("Tuple observation_spaces are currently not supported.") + raise KeyError + + else: + try: + self.observation_space = getattr( + gym.spaces, config["observation_space_class"] + )(*config["observation_space_args"]) + except TypeError: + print( + "To use a Dict observation space, the 'observation_space_args' in the configuration should be a list containing a Dict of gym.Spaces" + ) + raise TypeError + + # TODO: use dicts by default for actions and observations + # The config could change this for RL purposes + if "config_space" in config.keys(): + actions = config["config_space"].get_hyperparameters() + action_types = [type(a).__name__ for a in actions] + + # Uniform action space + if all(t == action_types[0] for t in action_types): + if "Float" in action_types[0]: + low = np.array([a.lower for a in actions]) + high = np.array([a.upper for a in actions]) + self.action_space = gym.spaces.Box(low=low, high=high) + elif "Integer" in action_types[0] or "Categorical" in action_types[0]: + if len(action_types) == 1: + try: + n = actions[0].upper - actions[0].lower + except: + n = len(actions[0].choices) + self.action_space = gym.spaces.Discrete(n) + else: + ns = [] + for a in actions: + try: + ns.append(a.upper - a.lower) + except: + ns.append(len(a.choices)) + self.action_space = gym.spaces.MultiDiscrete(np.array(ns)) + else: + raise ValueError( + "Only float, integer and categorical hyperparameters are supported as of now" + ) + # Mixed action space + # TODO: implement this + else: + raise ValueError("Mixed type config spaces are currently not supported") + elif "action_space" in config.keys(): + self.action_space = config["action_space"] + else: + try: + self.action_space = getattr(gym.spaces, config["action_space_class"])( + *config["action_space_args"] + ) + except KeyError: + print( + "Either submit a predefined gym.space 'action_space' or an 'action_space_class' as well as a list of 'action_space_args' in the configuration" + ) + raise KeyError + + except TypeError: + print("Tuple and Dict action spaces are currently not supported") + raise TypeError + + # seeding the environment after initialising action space + self.seed(config.get("seed", None), config.get("seed_action_space", False)) + + def step_(self): + """ + Pre-step function for step count and cutoff + + Returns + ------- + bool + End of episode + """ + trucated = False + self.c_step += 1 + if self.c_step >= self.n_steps: + truncated = True + return truncated + + def reset_(self, instance=None, instance_id=None, scheme=None): + """ + Pre-reset function for progressing through the instance set + Will either use round robin, random or no progression scheme + """ + self.c_step = 0 + if scheme is None: + scheme = self.instance_updates + self.use_next_instance(instance, instance_id, scheme=scheme) + + def use_next_instance(self, instance=None, instance_id=None, scheme=None): + """ + Changes instance according to chosen instance progession + + Parameters + ------- + instance + Instance specification for potentional new instances + instance_id + ID of the instance to switch to + scheme + Update scheme for this progression step (either round robin, random or no progression) + """ + if instance is not None: + self.instance = instance + elif instance_id is not None: + self.inst_id = instance_id + self.instance = self.instance_set[self.inst_id] + elif scheme == "round_robin": + self.instance_index = (self.instance_index + 1) % len(self.instance_id_list) + self.inst_id = self.instance_id_list[self.instance_index] + self.instance = self.instance_set[self.inst_id] + elif scheme == "random": + self.inst_id = np.random.choice(self.instance_id_list) + self.instance = self.instance_set[self.inst_id] + + def step(self, action): + """ + Execute environment step + + Parameters + ------- + action + Action to take + + Returns + ------- + state + Environment state + reward + Environment reward + terminated: bool + Run finished flag + truncated: bool + Run timed out flag + info : dict + Additional metainfo + """ + raise NotImplementedError + + def reset(self): + """ + Reset environment + + Returns + ------- + state + Environment state + info: dict + Additional metainfo + """ + raise NotImplementedError + + def get_inst_id(self): + """ + Return instance ID + + Returns + ------- + int + ID of current instance + """ + return self.inst_id + + def get_instance_set(self): + """ + Return instance set + + Returns + ------- + list + List of instances + + """ + return self.instance_set + + def get_instance(self): + """ + Return current instance + + Returns + ------- + type flexible + Currently used instance + """ + return self.instance + + def set_inst_id(self, inst_id): + """ + Change current instance ID + + Parameters + ---------- + inst_id : int + New instance index + """ + self.inst_id = inst_id + self.instance_index = self.instance_id_list.index(self.inst_id) + + def set_instance_set(self, inst_set): + """ + Change instance set + + Parameters + ---------- + inst_set: list + New instance set + """ + self.instance_set = inst_set + self.instance_id_list = sorted(list(self.instance_set.keys())) + + def set_instance(self, instance): + """ + Change currently used instance + + Parameters + ---------- + instance: + New instance + """ + self.instance = instance + + def seed_action_space(self, seed=None): + """ + Seeds the action space. + Parameters + ---------- + seed : int, default None + if None self.initial_seed is be used + + Returns + ------- + + """ + if seed is None: + seed = self.initial_seed + + self.action_space.seed(seed) + + def seed(self, seed=None, seed_action_space=False): + """ + Set rng seed + + Parameters + ---------- + seed: + seed for rng + seed_action_space: bool, default False + if to seed the action space as well + """ + + self.initial_seed = seed + # maybe one should use the seed generated by seeding.np_random(seed) but it can be to large see issue https://github.com/openai/gym/issues/2210 + random.seed(seed) + np.random.seed(seed) + self.np_random, seed = seeding.np_random(seed) + # uses the uncorrelated seed from seeding but makes sure that no randomness is introduces. + + if seed_action_space: + self.seed_action_space() + + return [seed] + + def use_test_set(self): + """ + Change to test instance set + """ + if self.test_set is None: + raise ValueError( + "No test set was provided, please check your benchmark config." + ) + + self.test = True + self.training_set = self.instance_set + self.training_id_list = self.instance_id_list + self.training_inst_id = self.inst_id + self.training_instance = self.instance + + self.instance_set = self.test_set + self.instance_id_list = self.test_instance_id_list + self.inst_id = self.test_inst_id + self.instance = self.test_instance + + def use_training_set(self): + """ + Change to training instance set + """ + self.test = False + self.test_set = self.instance_set + self.test_instance_id_list = self.instance_id_list + self.test_inst_id = self.inst_id + self.test_instance = self.instance + + self.instance_set = self.training_set + self.instance_id_list = self.training_id_list + self.inst_id = self.training_inst_id + self.instance = self.training_instance diff --git a/build/lib/dacbench/agents/__init__.py b/build/lib/dacbench/agents/__init__.py new file mode 100644 index 000000000..caabeed61 --- /dev/null +++ b/build/lib/dacbench/agents/__init__.py @@ -0,0 +1,5 @@ +from dacbench.agents.generic_agent import GenericAgent +from dacbench.agents.simple_agents import RandomAgent, StaticAgent +from dacbench.agents.dynamic_random_agent import DynamicRandomAgent + +__all__ = ["StaticAgent", "RandomAgent", "GenericAgent", "DynamicRandomAgent"] diff --git a/build/lib/dacbench/agents/dynamic_random_agent.py b/build/lib/dacbench/agents/dynamic_random_agent.py new file mode 100644 index 000000000..2f312834b --- /dev/null +++ b/build/lib/dacbench/agents/dynamic_random_agent.py @@ -0,0 +1,30 @@ +from dacbench.abstract_agent import AbstractDACBenchAgent +from gymnasium import spaces + + +class DynamicRandomAgent(AbstractDACBenchAgent): + def __init__(self, env, switching_interval): + self.sample_action = env.action_space.sample + self.switching_interval = switching_interval + self.count = 0 + self.action = self.sample_action() + self.shortbox = ( + isinstance(env.action_space, spaces.Box) and len(env.action_space.low) == 1 + ) + + def act(self, state, reward): + if self.count >= self.switching_interval: + self.action = self.sample_action() + self.count = 0 + self.count += 1 + + if self.shortbox: + return self.action[0] + else: + return self.action + + def train(self, next_state, reward): + pass + + def end_episode(self, state, reward): + pass diff --git a/build/lib/dacbench/agents/generic_agent.py b/build/lib/dacbench/agents/generic_agent.py new file mode 100644 index 000000000..bc16b0b06 --- /dev/null +++ b/build/lib/dacbench/agents/generic_agent.py @@ -0,0 +1,16 @@ +from dacbench.abstract_agent import AbstractDACBenchAgent + + +class GenericAgent(AbstractDACBenchAgent): + def __init__(self, env, policy): + self.policy = policy + self.env = env + + def act(self, state, reward): + return self.policy(self.env, state) + + def train(self, next_state, reward): + pass + + def end_episode(self, state, reward): + pass diff --git a/build/lib/dacbench/agents/simple_agents.py b/build/lib/dacbench/agents/simple_agents.py new file mode 100644 index 000000000..3fc6a7f0c --- /dev/null +++ b/build/lib/dacbench/agents/simple_agents.py @@ -0,0 +1,36 @@ +from dacbench.abstract_agent import AbstractDACBenchAgent +from gymnasium import spaces + + +class RandomAgent(AbstractDACBenchAgent): + def __init__(self, env): + self.sample_action = env.action_space.sample + self.shortbox = isinstance(env.action_space, spaces.Box) + if self.shortbox: + self.shortbox = self.shortbox and len(env.action_space.low) == 1 + + def act(self, state, reward): + if self.shortbox: + return self.sample_action()[0] + else: + return self.sample_action() + + def train(self, next_state, reward): + pass + + def end_episode(self, state, reward): + pass + + +class StaticAgent(AbstractDACBenchAgent): + def __init__(self, env, action): + self.action = action + + def act(self, state, reward): + return self.action + + def train(self, next_state, reward): + pass + + def end_episode(self, state, reward): + pass diff --git a/build/lib/dacbench/argument_parsing.py b/build/lib/dacbench/argument_parsing.py new file mode 100644 index 000000000..c1a1e7c9c --- /dev/null +++ b/build/lib/dacbench/argument_parsing.py @@ -0,0 +1,69 @@ +from argparse import ArgumentTypeError as err +from pathlib import Path + + +class PathType(object): + """ + Custom argument type for path validation. + + Adapted from: https://stackoverflow.com/questions/11415570/directory-path-types-with-argparse + """ + + def __init__(self, exists=True, type='file', dash_ok=True): + ''' + + Parameters + ---------- + + exists : bool + True: a path that does exist + False: a path that does not exist, in a valid parent directory + None: don't care + type : str + file, dir, symlink, socket, None, or a function returning True for valid paths + None: don't care + dash_ok: whether to allow "-" as stdin/stdout + + ''' + + assert exists in (True, False, None) + assert type in ('file', 'dir', 'symlink', 'socket', None) or hasattr(type, '__call__') + + self._exists = exists + self._type = type + self._dash_ok = dash_ok + + def __call__(self, string: str): + if string == '-': + # the special argument "-" means sys.std{in,out} + if self._type == 'dir': + raise err('standard input/output (-) not allowed as directory path') + elif self._type == 'symlink': + raise err('standard input/output (-) not allowed as symlink path') + elif not self._dash_ok: + raise err('standard input/output (-) not allowed') + + path = Path(string) + + # existence + if self._exists is None: + pass + elif not self._exists == path.exists(): + negate = '' if self._exists else 'not' + positive = '' if not self._exists else 'not' + raise err(f"{self._type.capitalize()} should {negate} exist but does {positive}") + + # type + if self._type is None: + pass + elif isinstance(self._type, str): + check = getattr(path, f'is_{self._type}') + if not check(): + raise err(f"Path is not {self._type}") + elif isinstance(self._type, callable): + if not self._type(path): + raise err("Callable type check failed") + else: + raise err("invalid type to check for") + + return path diff --git a/build/lib/dacbench/benchmarks/__init__.py b/build/lib/dacbench/benchmarks/__init__.py new file mode 100644 index 000000000..50d412a0f --- /dev/null +++ b/build/lib/dacbench/benchmarks/__init__.py @@ -0,0 +1,73 @@ +# flake8: noqa: F401 +from dacbench.benchmarks.luby_benchmark import LubyBenchmark +from dacbench.benchmarks.sigmoid_benchmark import SigmoidBenchmark +from dacbench.benchmarks.toysgd_benchmark import ToySGDBenchmark +from dacbench.benchmarks.geometric_benchmark import GeometricBenchmark + +from dacbench.benchmarks.fast_downward_benchmark import FastDownwardBenchmark + +__all__ = [ + "LubyBenchmark", + "SigmoidBenchmark", + "ToySGDBenchmark", + "GeometricBenchmark", + "FastDownwardBenchmark", +] + +import importlib +import warnings + +cma_spec = importlib.util.find_spec("cma") +found = cma_spec is not None +if found: + from dacbench.benchmarks.cma_benchmark import CMAESBenchmark + + __all__.append("CMAESBenchmark") +else: + warnings.warn( + "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +modea_spec = importlib.util.find_spec("modea") +found = modea_spec is not None +if found: + from dacbench.benchmarks.modea_benchmark import ModeaBenchmark + + __all__.append("ModeaBenchmark") +else: + warnings.warn( + "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +modcma_spec = importlib.util.find_spec("modcma") +found = modcma_spec is not None +if found: + from dacbench.benchmarks.modcma_benchmark import ModCMABenchmark + + __all__.append("ModCMABenchmark") +else: + warnings.warn( + "ModCMA Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +sgd_spec = importlib.util.find_spec("backpack") +found = sgd_spec is not None +if found: + from dacbench.benchmarks.sgd_benchmark import SGDBenchmark + + __all__.append("SGDBenchmark") +else: + warnings.warn( + "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +theory_spec = importlib.util.find_spec("uuid") +found = theory_spec is not None +if found: + from dacbench.benchmarks.theory_benchmark import TheoryBenchmark + + __all__.append("TheoryBenchmark") +else: + warnings.warn( + "Theory Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) diff --git a/build/lib/dacbench/benchmarks/cma_benchmark.py b/build/lib/dacbench/benchmarks/cma_benchmark.py new file mode 100644 index 000000000..a22e393ee --- /dev/null +++ b/build/lib/dacbench/benchmarks/cma_benchmark.py @@ -0,0 +1,162 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import CMAESEnv +from gymnasium import spaces +import numpy as np +import os +import csv +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +HISTORY_LENGTH = 40 +INPUT_DIM = 10 + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +STEP_SIZE = CSH.UniformFloatHyperparameter(name='Step_size', lower=0, upper=10) +DEFAULT_CFG_SPACE.add_hyperparameter(STEP_SIZE) + +INFO = { + "identifier": "CMA-ES", + "name": "Step-size adaption in CMA-ES", + "reward": "Negative best function value", + "state_description": [ + "Loc", + "Past Deltas", + "Population Size", + "Sigma", + "History Deltas", + "Past Sigma Deltas", + ], +} + +CMAES_DEFAULTS = objdict( + { + "action_space_class": "Box", + "action_space_args": [np.array([0]), np.array([10])], + "config_space": DEFAULT_CFG_SPACE, + "observation_space_class": "Dict", + "observation_space_type": None, + "observation_space_args": [ + { + "current_loc": spaces.Box( + low=-np.inf, high=np.inf, shape=np.arange(INPUT_DIM).shape + ), + "past_deltas": spaces.Box( + low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH).shape + ), + "current_ps": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), + "current_sigma": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), + "history_deltas": spaces.Box( + low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH * 2).shape + ), + "past_sigma_deltas": spaces.Box( + low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH).shape + ), + } + ], + "reward_range": (-(10 ** 9), 0), + "cutoff": 1e6, + "hist_length": HISTORY_LENGTH, + "popsize": 10, + "seed": 0, + "instance_set_path": "../instance_sets/cma/cma_train.csv", + "test_set_path": "../instance_sets/cma/cma_test.csv", + "benchmark_info": INFO, + } +) + + +class CMAESBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for CMA-ES + """ + + def __init__(self, config_path=None, config=None): + """ + Initialize CMA Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(CMAESBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(CMAES_DEFAULTS.copy()) + + for key in CMAES_DEFAULTS: + if key not in self.config: + self.config[key] = CMAES_DEFAULTS[key] + + def get_environment(self): + """ + Return CMAESEnv env with current configuration + + Returns + ------- + CMAESEnv + CMAES environment + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + #Read test set if path is specified + if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + self.read_instance_set(test=True) + + env = CMAESEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self, test=False): + """ + Read path of instances from config into list + """ + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + + self.config[keyword] = {} + with open(path, "r") as fh: + reader = csv.DictReader(fh) + for row in reader: + init_locs = [float(row[f"init_loc{i}"]) for i in range(int(row["dim"]))] + instance = [ + int(row["fcn_index"]), + int(row["dim"]), + float(row["init_sigma"]), + init_locs, + ] + self.config[keyword][int(row["ID"])] = instance + + def get_benchmark(self, seed=0): + """ + Get benchmark from the LTO paper + + Parameters + ------- + seed : int + Environment seed + + Returns + ------- + env : CMAESEnv + CMAES environment + """ + self.config = objdict(CMAES_DEFAULTS.copy()) + self.config.seed = seed + self.read_instance_set() + self.read_instance_set(test=True) + return CMAESEnv(self.config) diff --git a/build/lib/dacbench/benchmarks/fast_downward_benchmark.py b/build/lib/dacbench/benchmarks/fast_downward_benchmark.py new file mode 100644 index 000000000..3d526450d --- /dev/null +++ b/build/lib/dacbench/benchmarks/fast_downward_benchmark.py @@ -0,0 +1,192 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import FastDownwardEnv + +import numpy as np +import os +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +HEURISTICS = [ + "tiebreaking([pdb(pattern=manual_pattern([0,1])),weight(g(),-1)])", + "tiebreaking([pdb(pattern=manual_pattern([0,2])),weight(g(),-1)])", +] + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +HEURISTIC = CSH.CategoricalHyperparameter(name='heuristic', choices=["toy1", "toy2"]) +DEFAULT_CFG_SPACE.add_hyperparameter(HEURISTIC) + +INFO = { + "identifier": "FastDownward", + "name": "Heuristic Selection for the FastDownward Planner", + "reward": "Negative Runtime (-1 per step)", + "state_description": [ + "Average Value (heuristic 1)", + "Max Value (heuristic 1)", + "Min Value (heuristic 1)", + "Open List Entries (heuristic 1)", + "Variance (heuristic 1)", + "Average Value (heuristic 2)", + "Max Value (heuristic 2)", + "Min Value (heuristic 2)", + "Open List Entries (heuristic 2)", + "Variance (heuristic 2)", + ], +} + +FD_DEFAULTS = objdict( + { + "heuristics": HEURISTICS, + "config_space": DEFAULT_CFG_SPACE, + "observation_space_class": "Box", + "observation_space_type": np.float32, + "observation_space_args": [ + np.array([-np.inf for _ in range(5 * len(HEURISTICS))]), + np.array([np.inf for _ in range(5 * len(HEURISTICS))]), + ], + "reward_range": (-np.inf, 0), + "cutoff": 1e6, + "use_general_state_info": True, + "host": "", + "port": 54322, + "control_interval": 0, + "fd_seed": 0, + "num_steps": None, + "state_type": 2, + "config_dir": ".", + "port_file_id": None, + "seed": 0, + "max_rand_steps": 0, + "instance_set_path": "../instance_sets/fast_downward/train", + "test_set_path": "../instance_sets/fast_downward/test", + "fd_path": os.path.dirname(os.path.abspath(__file__)) + + "/../envs/rl-plan/fast-downward/fast-downward.py", + "parallel": True, + "fd_logs": None, + "benchmark_info": INFO, + } +) + + +class FastDownwardBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for Sigmoid + """ + + def __init__(self, config_path=None, config=None): + """ + Initialize FD Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(FastDownwardBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(FD_DEFAULTS.copy()) + + for key in FD_DEFAULTS: + if key not in self.config: + self.config[key] = FD_DEFAULTS[key] + + def get_environment(self): + """ + Return Luby env with current configuration + + Returns + ------- + LubyEnv + Luby environment + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + # Read test set if path is specified + if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + self.read_instance_set(test=True) + + env = FastDownwardEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self, test=False): + """ + Read paths of instances from config into list + """ + instances = {} + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + import re + + for root, dirs, files in os.walk(path): + for f in files: + if (f.endswith(".pddl") or f.endswith(".sas")) and not f.startswith( + "domain" + ): + p = os.path.join(root, f) + if f.endswith(".pddl"): + index = p.split("/")[-1].split(".")[0] + else: + index = p.split("/")[-2] + index = int(re.sub("[^0-9]", "", index)) + instances[index] = p + if len(instances) == 0: + for f in os.listdir(path): + f = f.strip() + if (f.endswith(".pddl") or f.endswith(".sas")) and not f.startswith( + "domain" + ): + p = os.path.join(path, f) + if f.endswith(".pddl"): + index = p.split("/")[-1].split(".")[0] + else: + index = p.split("/")[-2] + index = re.sub("[^0-9]", "", index) + instances[index] = p + self.config[keyword] = instances + + if instances[list(instances.keys())[0]].endswith(".pddl"): + self.config.domain_file = os.path.join(path + "/domain.pddl") + + def set_heuristics(self, heuristics): + self.config.heuristics = heuristics + self.config.action_space_args = [len(heuristics)] + self.config.observation_space_args = [ + np.array([-np.inf for _ in range(5 * len(heuristics))]), + np.array([np.inf for _ in range(5 * len(heuristics))]), + ] + + def get_benchmark(self, seed=0): + """ + Get published benchmark + + Parameters + ------- + seed : int + Environment seed + + Returns + ------- + env : FastDownwardEnv + FD environment + """ + self.config = objdict(FD_DEFAULTS.copy()) + self.read_instance_set() + self.read_instance_set(test=True) + self.config.seed = seed + env = FastDownwardEnv(self.config) + return env diff --git a/build/lib/dacbench/benchmarks/geometric_benchmark.py b/build/lib/dacbench/benchmarks/geometric_benchmark.py new file mode 100644 index 000000000..4db8224e4 --- /dev/null +++ b/build/lib/dacbench/benchmarks/geometric_benchmark.py @@ -0,0 +1,304 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import GeometricEnv + +import numpy as np +import os +import csv + +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +FILE_PATH = os.path.dirname(__file__) +ACTION_VALUES = (5, 10) + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() + +INFO = { + "identifier": "Geometric", + "name": "High Dimensional Geometric Curve Approximation. Curves are geometrical orthogonal.", + "reward": "Overall Euclidean Distance between Point on Curve and Action Vector for all Dimensions", + "state_description": ["Remaining Budget", "Dimensions",], +} + +GEOMETRIC_DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "observation_space_class": "Box", + "observation_space_type": np.float32, + "observation_space_args": [], + "reward_range": (0, 1), + "seed": 0, + "cutoff": 10, + "action_values": [], + "action_value_default": 4, + # if action_values_variable True action_value_mapping will be used instead of action_value_default to define action values + # action_value_mapping defines number of action values for differnet functions + # sigmoid is split in 3 actions, cubic in 7 etc. + "action_values_variable": False, + "action_value_mapping": { + "sigmoid": 3, + "linear": 3, + "parabel": 5, + "cubic": 7, + "logarithmic": 4, + "constant": 1, + "sinus": 9, + }, + "action_interval_mapping": {}, # maps actions to equally sized intervalls in interval [-1, 1] + "derivative_interval": 3, # defines how many values are used for derivative calculation + "realistic_trajectory": True, # True: coordiantes are used as trajectory, False: Actions are used as trajectories + "instance_set_path": os.path.join( + FILE_PATH, "../instance_sets/geometric/geometric_test.csv" + ), + # correlation table to chain dimensions -> if dim x changes dim y changes as well + # either assign numpy array to correlation table or use create_correlation_table() + "correlation_active": False, + "correlation_table": None, + "correlation_info": { + "high": [(1, 2, "+"), (2, 3, "-"), (1, 5, "+")], + "middle": [(4, 5, "-")], + "low": [(4, 6, "+"), (2, 3, "+"), (0, 2, "-")], + }, + "correlation_mapping": { + "high": (0.5, 1), + "middle": (0.1, 0.5), + "low": (0, 0.1), + }, + "correlation_depth": 4, + "benchmark_info": INFO, + } +) + + +class GeometricBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for Geometric + """ + + def __init__(self, config_path=None): + """ + Initialize Geometric Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(GeometricBenchmark, self).__init__(config_path) + if not self.config: + self.config = objdict(GEOMETRIC_DEFAULTS.copy()) + + for key in GEOMETRIC_DEFAULTS: + if key not in self.config: + self.config[key] = GEOMETRIC_DEFAULTS[key] + + if not self.config["observation_space_type"]: + self.config["observation_space_type"] = np.float32 + + def get_environment(self): + """ + Return Geometric env with current configuration + + Returns + ------- + GeometricEnv + Geometric environment + + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + self.set_action_values() + self.set_action_description() + + if ( + self.config.correlation_active + and not type(self.config.correlation_table) == np.ndarray + ): + self.create_correlation_table() + + env = GeometricEnv(self.config) + + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self): + """ + Read instance set from file + Creates a nested List for every Intance. + The List contains all functions with their respective values. + """ + path = os.path.join(FILE_PATH, self.config.instance_set_path) + self.config["instance_set"] = {} + with open(path, "r") as fh: + + known_ids = [] + reader = csv.DictReader(fh) + + for row in reader: + function_list = [] + id = int(row["ID"]) + + if id not in known_ids: + self.config.instance_set[id] = [] + known_ids.append(id) + + for index, element in enumerate(row.values()): + # if element == "0" and index != 0: + # break + + # read numbers from csv as floats + element = float(element) if index != 1 else element + + function_list.append(element) + + self.config.instance_set[id].append(function_list) + + def get_benchmark(self, dimension=None, seed=0): + """ + [summary] + + Parameters + ---------- + dimension : [type], optional + [description], by default None + seed : int, optional + [description], by default 0 + + Returns + ------- + [type] + [description] + """ + self.config = objdict(GEOMETRIC_DEFAULTS.copy()) + + self.config.benchmark_info["state_description"] = [ + "Remaining Budget", + "Dimensions", + ] + + self.config.seed = seed + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + self.set_action_values() + self.set_action_description() + + if ( + self.config.correlation_active + and not type(self.config.correlation_table) == np.ndarray + ): + self.create_correlation_table() + + env = GeometricEnv(self.config) + return env + + def set_action_values(self): + """ + Adapt action values and update dependencies + Number of actions can differ between functions if configured in DefaultDict + Set observation space args. + """ + + map_action_number = {} + if self.config.action_values_variable: + map_action_number = self.config.action_value_mapping + + values = [] + for function_info in self.config.instance_set[0]: + function_name = function_info[1] + + value = map_action_number.get( + function_name, self.config.action_value_default + ) + values.append(value) + + # map intervall [-1, 1] to action values + if function_name not in self.config.action_interval_mapping: + action_interval = [] + step_size = 2 / value + + for step in np.arange(-1, 1, step_size): + lower_bound = step + upper_bound = step + step_size + middle = (lower_bound + upper_bound) / 2 + + action_interval.append(middle) + + self.config.action_interval_mapping[function_name] = np.round( + action_interval, 3 + ) + + self.config.action_values = values + cs = CS.ConfigurationSpace() + actions = CSH.UniformIntegerHyperparameter( + name="curve_values", lower=0, upper=int(np.prod(values)) + ) + cs.add_hyperparameter(actions) + self.config.config_space = cs + + num_info = 2 + self.config.observation_space_args = [ + np.array([-1 for _ in range(num_info + 2 * len(values))]), + np.array( + [self.config["cutoff"] for _ in range(num_info + 2 * len(values))] + ), + ] + + def set_action_description(self): + """ + Add Information about Derivative and Coordinate to Description. + """ + if "Coordinate" in self.config.benchmark_info["state_description"]: + return + + for index in range(len(self.config.action_values)): + self.config.benchmark_info["state_description"].append(f"Derivative{index}") + + for index in range(len(self.config.action_values)): + self.config.benchmark_info["state_description"].append(f"Coordinate{index}") + + def create_correlation_table(self): + """ + Create correlation table from Config infos + """ + n_dimensions = len(self.config.instance_set[0]) + corr_table = np.zeros((n_dimensions, n_dimensions)) + + for corr_level, corr_info in self.config.correlation_info.items(): + for dim1, dim2, signum in corr_info: + low, high = self.config.correlation_mapping[corr_level] + value = np.random.uniform(low, high) + try: + corr_table[dim1, dim2] = value if signum == "+" else value * -1 + except IndexError: + print( + "Check your correlation_info dict. Does it have more dimensions than the instance_set?" + ) + + self.config.correlation_table = corr_table + + +if __name__ == "__main__": + from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import ( + quadratic_euclidean_distance_reward_geometric, + ) + + geo_bench = GeometricBenchmark() + geo_bench.config["correlation_active"] = True + geo_bench.config["reward_function"] = quadratic_euclidean_distance_reward_geometric + + env = geo_bench.get_environment() + + opt_policy = env.get_optimal_policy() + # env.render_dimensions([0, 1, 2, 3, 4, 5, 6], "/home/vonglahn/tmp/MultiDAC") + env.render_3d_dimensions([1, 3], "/home/eimer/tmp") + + while True: + env.reset() + done = False + while not done: + state, reward, done, info = env.step(np.random.randint(env.action_space.n)) + print(reward) diff --git a/build/lib/dacbench/benchmarks/luby_benchmark.py b/build/lib/dacbench/benchmarks/luby_benchmark.py new file mode 100644 index 000000000..b209fc103 --- /dev/null +++ b/build/lib/dacbench/benchmarks/luby_benchmark.py @@ -0,0 +1,189 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import LubyEnv, luby_gen +from dacbench.wrappers import RewardNoiseWrapper + +import numpy as np +import os +import csv +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +MAX_STEPS = 2 ** 6 +LUBY_SEQUENCE = np.log2([next(luby_gen(i)) for i in range(1, 2 * MAX_STEPS + 2)]) +HISTORY_LENGTH = 5 + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +SEQ = CSH.UniformIntegerHyperparameter(name='sequence_element', lower=0, upper=np.log2(MAX_STEPS)) +DEFAULT_CFG_SPACE.add_hyperparameter(SEQ) + +INFO = { + "identifier": "Luby", + "name": "Luby Sequence Approximation", + "reward": "Boolean sucess indication", + "state_description": [ + "Action t-2", + "Step t-2", + "Action t-1", + "Step t-1", + "Action t (current)", + "Step t (current)", + ], +} + +LUBY_DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "observation_space_class": "Box", + "observation_space_type": np.float32, + "observation_space_args": [ + np.array([-1 for _ in range(HISTORY_LENGTH + 1)]), + np.array([2 ** max(LUBY_SEQUENCE + 1) for _ in range(HISTORY_LENGTH + 1)]), + ], + "reward_range": (-1, 0), + "cutoff": MAX_STEPS, + "hist_length": HISTORY_LENGTH, + "min_steps": 2 ** 3, + "seed": 0, + "instance_set_path": "../instance_sets/luby/luby_default.csv", + "benchmark_info": INFO, + } +) + + +class LubyBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for Sigmoid + """ + + def __init__(self, config_path=None, config=None): + """ + Initialize Luby Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(LubyBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(LUBY_DEFAULTS.copy()) + + for key in LUBY_DEFAULTS: + if key not in self.config: + self.config[key] = LUBY_DEFAULTS[key] + + def get_environment(self): + """ + Return Luby env with current configuration + + Returns + ------- + LubyEnv + Luby environment + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + # Read test set if path is specified + if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + self.read_instance_set(test=True) + + env = LubyEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def set_cutoff(self, steps): + """ + Set cutoff and adapt dependencies + + Parameters + ------- + int + Maximum number of steps + """ + self.config.cutoff = steps + self.config.action_space_args = [int(np.log2(steps))] + LUBY_SEQUENCE = np.log2([next(luby_gen(i)) for i in range(1, 2 * steps + 2)]) + self.config.observation_space_args = [ + np.array([-1 for _ in range(self.config.hist_length + 1)]), + np.array( + [ + 2 ** max(LUBY_SEQUENCE + 1) + for _ in range(self.config.hist_length + 1) + ] + ), + ] + + def set_history_length(self, length): + """ + Set history length and adapt dependencies + + Parameters + ------- + int + History length + """ + self.config.hist_length = length + self.config.observation_space_args = [ + np.array([-1 for _ in range(length + 1)]), + np.array([2 ** max(LUBY_SEQUENCE + 1) for _ in range(length + 1)]), + ] + + def read_instance_set(self, test=False): + """Read instance set from file""" + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + + self.config[keyword] = {} + with open(path, "r") as fh: + reader = csv.DictReader(fh) + for row in reader: + self.config[keyword][int(row["ID"])] = [ + float(shift) for shift in row["start"].split(",") + ] + [float(slope) for slope in row["sticky"].split(",")] + + def get_benchmark(self, L=8, fuzziness=1.5, seed=0): + """ + Get Benchmark from DAC paper + + Parameters + ------- + L : int + Minimum sequence lenght, was 8, 16 or 32 in the paper + fuzziness : float + Amount of noise applied. Was 1.5 for most of the experiments + seed : int + Environment seed + + Returns + ------- + env : LubyEnv + Luby environment + """ + self.config = objdict(LUBY_DEFAULTS.copy()) + self.config.min_steps = L + self.config.seed = seed + self.config.instance_set = {0: [0, 0]} + self.config.reward_range = (-10, 10) + env = LubyEnv(self.config) + rng = np.random.RandomState(self.config.seed) + + def fuzz(): + return rng.normal(-1, fuzziness) + + fuzzy_env = RewardNoiseWrapper(env, noise_function=fuzz) + return fuzzy_env diff --git a/build/lib/dacbench/benchmarks/modcma_benchmark.py b/build/lib/dacbench/benchmarks/modcma_benchmark.py new file mode 100644 index 000000000..16c2dc10b --- /dev/null +++ b/build/lib/dacbench/benchmarks/modcma_benchmark.py @@ -0,0 +1,134 @@ +import os +import itertools + +import numpy as np +from modcma import Parameters + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import ModCMAEnv, CMAStepSizeEnv + +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +ACTIVE = CSH.CategoricalHyperparameter(name='0_active', choices=[True, False]) +ELITIST = CSH.CategoricalHyperparameter(name='1_elitist', choices=[True, False]) +ORTHOGONAL = CSH.CategoricalHyperparameter(name='2_orthogonal', choices=[True, False]) +SEQUENTIAL = CSH.CategoricalHyperparameter(name='3_sequential', choices=[True, False]) +THRESHOLD_CONVERGENCE = CSH.CategoricalHyperparameter(name='4_threshold_convergence', choices=[True, False]) +STEP_SIZE_ADAPTION = CSH.CategoricalHyperparameter(name='5_step_size_adaption', choices=["csa", "tpa", "msr", "xnes", "m-xnes", "lp-xnes", "psr"]) +MIRRORED = CSH.CategoricalHyperparameter(name='6_mirrored', choices=["None", "mirrored", "mirrored pairwise"]) +BASE_SAMPLER = CSH.CategoricalHyperparameter(name='7_base_sampler', choices=["gaussian", "sobol", "halton"]) +WEIGHTS_OPTION = CSH.CategoricalHyperparameter(name='8_weights_option', choices=["default", "equal", "1/2^lambda"]) +LOCAL_RESTART = CSH.CategoricalHyperparameter(name='90_local_restart', choices=["None", "IPOP", "BIPOP"]) +BOUND_CORRECTION = CSH.CategoricalHyperparameter(name='91_bound_correction', choices=["None", "saturate", "unif_resample", "COTN", "toroidal", "mirror"]) + +DEFAULT_CFG_SPACE.add_hyperparameter(ACTIVE) +DEFAULT_CFG_SPACE.add_hyperparameter(ELITIST) +DEFAULT_CFG_SPACE.add_hyperparameter(ORTHOGONAL) +DEFAULT_CFG_SPACE.add_hyperparameter(SEQUENTIAL) +DEFAULT_CFG_SPACE.add_hyperparameter(THRESHOLD_CONVERGENCE) +DEFAULT_CFG_SPACE.add_hyperparameter(STEP_SIZE_ADAPTION) +DEFAULT_CFG_SPACE.add_hyperparameter(MIRRORED) +DEFAULT_CFG_SPACE.add_hyperparameter(BASE_SAMPLER) +DEFAULT_CFG_SPACE.add_hyperparameter(WEIGHTS_OPTION) +DEFAULT_CFG_SPACE.add_hyperparameter(LOCAL_RESTART) +DEFAULT_CFG_SPACE.add_hyperparameter(BOUND_CORRECTION) + +INFO = { + "identifier": "ModCMA", + "name": "Online Selection of CMA-ES Variants", + "reward": "Negative best function value", + "state_description": [ + "Generation Size", + "Sigma", + "Remaining Budget", + "Function ID", + "Instance ID", + ], +} + + +MODCMA_DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "action_space_class": "MultiDiscrete", + "action_space_args": [ + list( + map( + lambda m: len( + getattr(getattr(Parameters, m), "options", [False, True]) + ), + Parameters.__modules__, + ) + ) + ], + "observation_space_class": "Box", + "observation_space_args": [-np.inf * np.ones(5), np.inf * np.ones(5)], + "observation_space_type": np.float32, + "reward_range": (-(10 ** 12), 0), + "budget": 100, + "cutoff": 1e6, + "seed": 0, + "instance_set_path": os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "../instance_sets/modea/modea_train.csv", + ), + "test_set_path": os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "../instance_sets/modea/modea_train.csv", + ), + "benchmark_info": INFO, + } +) + + +class ModCMABenchmark(AbstractBenchmark): + def __init__(self, config_path: str = None, step_size=False, config=None): + super().__init__(config_path, config) + self.config = objdict(MODCMA_DEFAULTS.copy(), **(self.config or dict())) + self.step_size = step_size + + def get_environment(self): + if "instance_set" not in self.config: + self.read_instance_set() + + # Read test set if path is specified + if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + self.read_instance_set(test=True) + + if self.step_size: + self.config.action_space_class = "Box" + self.config.action_space_args = [np.array([0]), np.array([10])] + env = CMAStepSizeEnv(self.config) + else: + env = ModCMAEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + return env + + def read_instance_set(self, test=False): + if test: + path = self.config.test_set_path + keyword = "test_set" + else: + path = self.config.instance_set_path + keyword = "instance_set" + + self.config[keyword] = dict() + with open(path, "r") as fh: + for line in itertools.islice(fh, 1, None): + _id, dim, fid, iid, *representation = line.strip().split(",") + self.config[keyword][int(_id)] = [ + int(dim), + int(fid), + int(iid), + list(map(int, representation)), + ] + + def get_benchmark(self, seed: int = 0): + self.config = MODCMA_DEFAULTS.copy() + self.config.seed = seed + self.read_instance_set() + self.read_instance_set(test=True) + return ModCMAEnv(self.config) diff --git a/dacbench/benchmarks/modea_benchmark.py b/build/lib/dacbench/benchmarks/modea_benchmark.py similarity index 100% rename from dacbench/benchmarks/modea_benchmark.py rename to build/lib/dacbench/benchmarks/modea_benchmark.py diff --git a/build/lib/dacbench/benchmarks/sgd_benchmark.py b/build/lib/dacbench/benchmarks/sgd_benchmark.py new file mode 100644 index 000000000..1122ae9a1 --- /dev/null +++ b/build/lib/dacbench/benchmarks/sgd_benchmark.py @@ -0,0 +1,219 @@ +import csv +import os + +import numpy as np +from gymnasium import spaces +from torch.nn import NLLLoss + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import SGDEnv +from dacbench.envs.sgd import Reward + +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +LR = CSH.UniformIntegerHyperparameter(name="learning_rate", lower=0, upper=10) +DEFAULT_CFG_SPACE.add_hyperparameter(LR) + + +def __default_loss_function(**kwargs): + return NLLLoss(reduction="none", **kwargs) + + +INFO = { + "identifier": "LR", + "name": "Learning Rate Adaption for Neural Networks", + "reward": "Negative Log Differential Validation Loss", + "state_description": [ + "Predictive Change Variance (Discounted Average)", + "Predictive Change Variance (Uncertainty)", + "Loss Variance (Discounted Average)", + "Loss Variance (Uncertainty)", + "Current Learning Rate", + "Training Loss", + "Validation Loss", + "Step", + "Alignment", + "Crashed", + ], +} + + +SGD_DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "action_space_class": "Box", + "action_space_args": [np.array([0]), np.array([10])], + "observation_space_class": "Dict", + "observation_space_type": None, + "observation_space_args": [ + { + "predictiveChangeVarDiscountedAverage": spaces.Box( + low=-np.inf, high=np.inf, shape=(1,) + ), + "predictiveChangeVarUncertainty": spaces.Box( + low=0, high=np.inf, shape=(1,) + ), + "lossVarDiscountedAverage": spaces.Box( + low=-np.inf, high=np.inf, shape=(1,) + ), + "lossVarUncertainty": spaces.Box(low=0, high=np.inf, shape=(1,)), + "currentLR": spaces.Box(low=0, high=1, shape=(1,)), + "trainingLoss": spaces.Box(low=0, high=np.inf, shape=(1,)), + "validationLoss": spaces.Box(low=0, high=np.inf, shape=(1,)), + "step": spaces.Box(low=0, high=np.inf, shape=(1,)), + "alignment": spaces.Box(low=0, high=1, shape=(1,)), + "crashed": spaces.Discrete(2), + } + ], + "reward_type": Reward.LogDiffTraining, + "cutoff": 1e3, + "lr": 1e-3, + "discount_factor": 0.9, + "optimizer": "rmsprop", + "loss_function": __default_loss_function, + "loss_function_kwargs": {}, + "val_loss_function": __default_loss_function, + "val_loss_function_kwargs": {}, + "training_batch_size": 64, + "validation_batch_size": 64, + "train_validation_ratio": 0.8, + "dataloader_shuffle": True, + "no_cuda": False, + "beta1": 0.9, + "beta2": 0.9, + "epsilon": 1.0e-06, + "clip_grad": (-1.0, 1.0), + "seed": 0, + "cd_paper_reconstruction": False, + "cd_bias_correction": True, + "terminate_on_crash": False, + "crash_penalty": 0.0, + "instance_set_path": "../instance_sets/sgd/sgd_train_100instances.csv", + "benchmark_info": INFO, + "features": [ + "predictiveChangeVarDiscountedAverage", + "predictiveChangeVarUncertainty", + "lossVarDiscountedAverage", + "lossVarUncertainty", + "currentLR", + "trainingLoss", + "validationLoss", + "step", + "alignment", + "crashed", + ], + } +) + +# Set reward range based on the chosen reward type +SGD_DEFAULTS.reward_range = SGD_DEFAULTS["reward_type"].func.frange + + +class SGDBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for SGD + """ + + def __init__(self, config_path=None, config=None): + """ + Initialize SGD Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(SGDBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(SGD_DEFAULTS.copy()) + + for key in SGD_DEFAULTS: + if key not in self.config: + self.config[key] = SGD_DEFAULTS[key] + + def get_environment(self): + """ + Return SGDEnv env with current configuration + + Returns + ------- + SGDEnv + SGD environment + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + # Read test set if path is specified + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): + self.read_instance_set(test=True) + + env = SGDEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self, test=False): + """ + Read path of instances from config into list + """ + + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + self.config[keyword] = {} + with open(path, "r") as fh: + reader = csv.DictReader(fh, delimiter=";") + for row in reader: + if "_" in row["dataset"]: + dataset_info = row["dataset"].split("_") + dataset_name = dataset_info[0] + dataset_size = int(dataset_info[1]) + else: + dataset_name = row["dataset"] + dataset_size = None + instance = [ + dataset_name, + int(row["seed"]), + row["architecture"], + int(row["steps"]), + dataset_size, + ] + self.config[keyword][int(row["ID"])] = instance + + def get_benchmark(self, instance_set_path=None, seed=0): + """ + Get benchmark from the LTO paper + + Parameters + ------- + seed : int + Environment seed + + Returns + ------- + env : SGDEnv + SGD environment + """ + self.config = objdict(SGD_DEFAULTS.copy()) + if instance_set_path is not None: + self.config["instance_set_path"] = instance_set_path + self.config.seed = seed + self.read_instance_set() + return SGDEnv(self.config) diff --git a/build/lib/dacbench/benchmarks/sigmoid_benchmark.py b/build/lib/dacbench/benchmarks/sigmoid_benchmark.py new file mode 100644 index 000000000..a6a9366e6 --- /dev/null +++ b/build/lib/dacbench/benchmarks/sigmoid_benchmark.py @@ -0,0 +1,254 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import SigmoidEnv, ContinuousSigmoidEnv, ContinuousStateSigmoidEnv + +import numpy as np +import os +import csv +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +ACTION_VALUES = (5, 10) + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +X = CSH.UniformIntegerHyperparameter(name='value_index', lower=0, upper=int(np.prod(ACTION_VALUES))) +DEFAULT_CFG_SPACE.add_hyperparameter(X) + +INFO = { + "identifier": "Sigmoid", + "name": "Sigmoid Function Approximation", + "reward": "Multiplied Differences between Function and Action in each Dimension", + "state_description": [ + "Remaining Budget", + "Shift (dimension 1)", + "Slope (dimension 1)", + "Shift (dimension 2)", + "Slope (dimension 2)", + "Action 1", + "Action 2", + ], +} + +SIGMOID_DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "action_space_class": "Discrete", + "action_space_args": [int(np.prod(ACTION_VALUES))], + "observation_space_class": "Box", + "observation_space_type": np.float32, + "observation_space_args": [ + np.array([-np.inf for _ in range(1 + len(ACTION_VALUES) * 3)]), + np.array([np.inf for _ in range(1 + len(ACTION_VALUES) * 3)]), + ], + "reward_range": (0, 1), + "cutoff": 10, + "action_values": ACTION_VALUES, + "slope_multiplier": 2.0, + "seed": 0, + "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", + "test_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_test.csv", + "benchmark_info": INFO, + } +) + + +class SigmoidBenchmark(AbstractBenchmark): + """ + Benchmark with default configuration & relevant functions for Sigmoid + """ + + def __init__(self, config_path=None, config=None): + """ + Initialize Sigmoid Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(SigmoidBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(SIGMOID_DEFAULTS.copy()) + + for key in SIGMOID_DEFAULTS: + if key not in self.config: + self.config[key] = SIGMOID_DEFAULTS[key] + + def get_environment(self): + """ + Return Sigmoid env with current configuration + + Returns + ------- + SigmoidEnv + Sigmoid environment + + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + # Read test set if path is specified + if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + self.read_instance_set(test=True) + + if ( + "env_type" in self.config + ): # The env_type determines which Sigmoid environment to use. + if self.config["env_type"].lower() in [ + "continuous", + "cont", + ]: # Either continuous ... + if ( + self.config["action_space"] == "Box" + ): # ... in both actions and x-axis state, only ... + env = ContinuousSigmoidEnv(self.config) + elif ( + self.config["action_space"] == "Discrete" + ): # ... continuous in the x-axis state or ... + env = ContinuousStateSigmoidEnv(self.config) + else: + raise Exception( + f'The given environment type "{self.config["env_type"]}" does not support the' + f' chosen action_space "{self.config["action_space"]}". The action space has to' + f' be either of type "Box" for continuous actions or "Discrete".' + ) + else: # ... discrete. + env = SigmoidEnv(self.config) + else: # If the type is not specified we the simplest, fully discrete version. + env = SigmoidEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def set_action_values(self, values): + """ + Adapt action values and update dependencies + + Parameters + ---------- + values: list + A list of possible actions per dimension + """ + self.config.action_values = values + self.config.action_space_args = [int(np.prod(values))] + self.config.observation_space_args = [ + np.array([-np.inf for _ in range(1 + len(values) * 3)]), + np.array([np.inf for _ in range(1 + len(values) * 3)]), + ] + + def read_instance_set(self, test=False): + """Read instance set from file""" + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + + self.config[keyword] = {} + with open(path, "r") as f: + reader = csv.reader(f) + for row in reader: + f = [] + inst_id = None + for i in range(len(row)): + if i == 0: + try: + inst_id = int(row[i]) + except Exception: + continue + else: + try: + f.append(float(row[i])) + except Exception: + continue + + if not len(f) == 0: + self.config[keyword][inst_id] = f + + def get_benchmark(self, dimension=None, seed=0): + """ + Get Benchmark from DAC paper + + Parameters + ------- + dimension : int + Sigmoid dimension, was 1, 2, 3 or 5 in the paper + seed : int + Environment seed + + Returns + ------- + env : SigmoidEnv + Sigmoid environment + """ + self.config = objdict(SIGMOID_DEFAULTS.copy()) + if dimension == 1: + self.set_action_values([3]) + self.config.instance_set_path = ( + "../instance_sets/sigmoid/sigmoid_1D3M_train.csv" + ) + self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_1D3M_test.csv" + self.config.benchmark_info["state_description"] = [ + "Remaining Budget", + "Shift (dimension 1)", + "Slope (dimension 1)", + "Action", + ] + if dimension == 2: + self.set_action_values([3, 3]) + if dimension == 3: + self.set_action_values((3, 3, 3)) + self.config.instance_set_path = ( + "../instance_sets/sigmoid/sigmoid_3D3M_train.csv" + ) + self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_3D3M_test.csv" + self.config.benchmark_info["state_description"] = [ + "Remaining Budget", + "Shift (dimension 1)", + "Slope (dimension 1)", + "Shift (dimension 2)", + "Slope (dimension 2)", + "Shift (dimension 3)", + "Slope (dimension 3)", + "Action 1", + "Action 2", + "Action 3", + ] + if dimension == 5: + self.set_action_values((3, 3, 3, 3, 3)) + self.config.instance_set_path = ( + "../instance_sets/sigmoid/sigmoid_5D3M_train.csv" + ) + self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_5D3M_test.csv" + self.config.benchmark_info["state_description"] = [ + "Remaining Budget", + "Shift (dimension 1)", + "Slope (dimension 1)", + "Shift (dimension 2)", + "Slope (dimension 2)", + "Shift (dimension 3)", + "Slope (dimension 3)", + "Shift (dimension 4)", + "Slope (dimension 4)", + "Shift (dimension 5)", + "Slope (dimension 5)", + "Action 1", + "Action 2", + "Action 3", + "Action 4", + "Action 5", + ] + self.config.seed = seed + self.read_instance_set() + self.read_instance_set(test=True) + env = SigmoidEnv(self.config) + return env diff --git a/build/lib/dacbench/benchmarks/theory_benchmark.py b/build/lib/dacbench/benchmarks/theory_benchmark.py new file mode 100644 index 000000000..2f48b031b --- /dev/null +++ b/build/lib/dacbench/benchmarks/theory_benchmark.py @@ -0,0 +1,169 @@ +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv + +import numpy as np +import os +import pandas as pd +import gymnasium as gym + +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +INFO = { + "identifier": "Theory", + "name": "DAC benchmark with RLS algorithm and LeadingOne problem", + "reward": "Negative number of iterations until solution", + "state_description": "specified by user", +} + +THEORY_DEFAULTS = { + "observation_description": "n, f(x)", # examples: n, f(x), delta_f(x), optimal_k, k, k_{t-0..4}, f(x)_{t-1}, f(x)_{t-0..4} + "reward_range": [-np.inf, np.inf], # the true reward range is instance dependent + "reward_choice": "imp_minus_evals", # possible values: see envs/theory.py for more details + "cutoff": 1e6, # if using as a "train" environment, a cutoff of 0.8*n^2 where n is problem size will be used (for more details, please see https://arxiv.org/abs/2202.03259) + # see get_environment function of TheoryBenchmark on how to specify a train/test environment + "seed": 0, + "seed_action_space": False, # set this one to True for reproducibility when random action is sampled in the action space with gym.action_space.sample() + "problem": "LeadingOne", # possible values: "LeadingOne" + "instance_set_path": "lo_rls_50.csv", # if the instance list file cannot be found in the running directory, it will be looked up in /dacbench/instance_sets/theory/ + "discrete_action": True, # action space is discrete + "action_choices": [1, 2, 4, 8, 16], # portfolio of k values + "benchmark_info": INFO, + "name": "LeadingOnesDAC", +} + + +class TheoryBenchmark(AbstractBenchmark): + """ + Benchmark with various settings for (1+(lbd, lbd))-GA and RLS + """ + + def __init__(self, config=None): + """ + Initialize a theory benchmark + + Parameters + ------- + base_config_name: str + OneLL's config name + possible values: see ../additional_configs/onell/configs.py + config : str + a dictionary, all options specified in this argument will override the one in base_config_name + + """ + super(TheoryBenchmark, self).__init__() + + self.config = objdict(THEORY_DEFAULTS) + + if config: + for key, val in config.items(): + self.config[key] = val + + self.read_instance_set() + + # initialise action space and environment class + cfg_space = CS.ConfigurationSpace() + if self.config.discrete_action: + assert ( + "action_choices" in self.config + ), "ERROR: action_choices must be specified" + assert ("min_action" not in self.config) and ( + "max_action" not in self.config + ), "ERROR: min_action and max_action should not be used for discrete action space" + assert ( + "max_action" not in self.config + ), "ERROR: max_action should not be used for discrete action space" + self.config.env_class = "RLSEnvDiscrete" + n_acts = len(self.config["action_choices"]) + action = CSH.UniformIntegerHyperparameter(name="", lower=0, upper=n_acts) + else: + assert ( + "action_chocies" not in self.config + ), "ERROR: action_choices is only used for discrete action space" + assert ("min_action" in self.config) and ( + "max_action" in self.config + ), "ERROR: min_action and max_action must be specified" + self.config.env_class = "RLSEnv" + action = CSH.UniformFloatHyperparameter( + name="Step_size", + lower=self.config["min_action"], + upper=self.config["max_action"], + ) + + cfg_space.add_hyperparameter(action) + self.config["config_space"] = cfg_space + + # create observation space + self.env_class = globals()[self.config.env_class] + assert self.env_class == RLSEnv or self.env_class == RLSEnvDiscrete + + self.config[ + "observation_space" + ] = self.create_observation_space_from_description( + self.config["observation_description"], self.env_class + ) + + def create_observation_space_from_description( + self, obs_description, env_class=RLSEnvDiscrete + ): + """ + Create a gym observation space (Box only) based on a string containing observation variable names, e.g. "n, f(x), k, k_{t-1}" + Return: + A gym.spaces.Box observation space + """ + obs_var_names = [s.strip() for s in obs_description.split(",")] + low = [] + high = [] + for var_name in obs_var_names: + l, h = env_class.get_obs_domain_from_name(var_name) + low.append(l) + high.append(h) + obs_space = gym.spaces.Box(low=np.array(low), high=np.array(high)) + return obs_space + + def get_environment(self, test_env=False): + """ + Return an environment with current configuration + + Parameters: + test_env: whether the enviroment is used for train an agent or for testing. + if test_env=False: + cutoff time for an episode is set to 0.8*n^2 (n: problem size) + if an action is out of range, stop the episode immediately and return a large negative reward (see envs/theory.py for more details) + otherwise: benchmark's original cutoff time is used, and out-of-range action will be clipped to nearest valid value and the episode will continue. + """ + + env = self.env_class(self.config, test_env) + + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self): + """ + Read instance set from file + we look at the current directory first, if the file doesn't exist, we look in /dacbench/instance_sets/theory/ + """ + assert self.config.instance_set_path + if os.path.isfile(self.config.instance_set_path): + path = self.config.instance_set_path + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/../instance_sets/theory/" + + self.config.instance_set_path + ) + + self.config["instance_set"] = pd.read_csv(path, index_col=0).to_dict("id") + + assert len(self.config["instance_set"].items()) > 0, "ERROR: empty instance set" + assert ( + "initObj" in self.config["instance_set"][0].keys() + ), "ERROR: initial solution (initObj) must be specified in instance set" + assert ( + "size" in self.config["instance_set"][0].keys() + ), "ERROR: problem size must be specified in instance set" + + for key, val in self.config["instance_set"].items(): + self.config["instance_set"][key] = objdict(val) diff --git a/build/lib/dacbench/benchmarks/toysgd_benchmark.py b/build/lib/dacbench/benchmarks/toysgd_benchmark.py new file mode 100644 index 000000000..716a4f9c4 --- /dev/null +++ b/build/lib/dacbench/benchmarks/toysgd_benchmark.py @@ -0,0 +1,122 @@ +import os + +import numpy as np +import pandas as pd +from gymnasium import spaces + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import ToySGDEnv + +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH + +DEFAULT_CFG_SPACE = CS.ConfigurationSpace() +LR = CSH.UniformFloatHyperparameter(name="0_log_learning_rate", lower=-10, upper=0) +MOMENTUM = CSH.UniformFloatHyperparameter(name="1_log_momentum", lower=-10, upper=0) +DEFAULT_CFG_SPACE.add_hyperparameter(LR) +DEFAULT_CFG_SPACE.add_hyperparameter(MOMENTUM) + + +INFO = { + "identifier": "toy_sgd", + "name": "Learning Rate and Momentum Adaption for SGD on Toy Functions", + "reward": "Negative Log Regret", + "state_description": [ + "Remaining Budget", + "Gradient", + "Current Learning Rate", + "Current Momentum", + ], + "action_description": ["Log Learning Rate", "Log Momentum"], +} + +DEFAULTS = objdict( + { + "config_space": DEFAULT_CFG_SPACE, + "observation_space_class": "Dict", + "observation_space_type": None, + "observation_space_args": [ + { + "remaining_budget": spaces.Box(low=0, high=np.inf, shape=(1,)), + "gradient": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), + "learning_rate": spaces.Box(low=0, high=1, shape=(1,)), + "momentum": spaces.Box(low=0, high=1, shape=(1,)), + } + ], + "reward_range": (-np.inf, np.inf), + "cutoff": 10, + "seed": 0, + "instance_set_path": "../instance_sets/toysgd/toysgd_default.csv", + "benchmark_info": INFO, + } +) + + +class ToySGDBenchmark(AbstractBenchmark): + def __init__(self, config_path=None, config=None): + """ + Initialize SGD Benchmark + + Parameters + ------- + config_path : str + Path to config file (optional) + """ + super(ToySGDBenchmark, self).__init__(config_path, config) + if not self.config: + self.config = objdict(DEFAULTS.copy()) + + for key in DEFAULTS: + if key not in self.config: + self.config[key] = DEFAULTS[key] + + def get_environment(self): + """ + Return SGDEnv env with current configuration + + Returns + ------- + SGDEnv + SGD environment + """ + if "instance_set" not in self.config.keys(): + self.read_instance_set() + + # Read test set if path is specified + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): + self.read_instance_set(test=True) + + env = ToySGDEnv(self.config) + for func in self.wrap_funcs: + env = func(env) + + return env + + def read_instance_set(self, test=False): + """ + Read path of instances from config into list + """ + if test: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.test_set_path + ) + keyword = "test_set" + else: + path = ( + os.path.dirname(os.path.abspath(__file__)) + + "/" + + self.config.instance_set_path + ) + keyword = "instance_set" + + self.config[keyword] = {} + with open(path, "r") as fh: + # reader = csv.DictReader(fh, delimiter=";") + df = pd.read_csv(fh, sep=";") + for index, instance in df.iterrows(): + self.config[keyword][int(instance["ID"])] = instance diff --git a/build/lib/dacbench/container/__init__.py b/build/lib/dacbench/container/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/build/lib/dacbench/container/container_utils.py b/build/lib/dacbench/container/container_utils.py new file mode 100644 index 000000000..3f13df81c --- /dev/null +++ b/build/lib/dacbench/container/container_utils.py @@ -0,0 +1,191 @@ +import enum +import json +import os +import socket +import time +from typing import Any, Union, Tuple, List, Dict + +import gym +import numpy as np + + +class Encoder(json.JSONEncoder): + """ Json Encoder to save tuple and or numpy arrays | numpy floats / integer. + Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py + Serializing tuple/numpy array may not work. We need to annotate those types, to reconstruct them correctly. + """ + + @staticmethod + def hint(item): + # Annotate the different item types + if isinstance(item, tuple): + return {'__type__': 'tuple', '__items__': [Encoder.hint(e) for e in item]} + if isinstance(item, np.ndarray): + return {'__type__': 'np.ndarray', '__items__': item.tolist()} + if isinstance(item, np.floating): + return {'__type__': 'np.float', '__items__': float(item)} + if isinstance(item, np.integer): + return {'__type__': 'np.int', '__items__': item.tolist()} + if isinstance(item, enum.Enum): + return str(item) + if isinstance(item, np.random.RandomState): + return serialize_random_state(item) + if isinstance(item, gym.Space): + return Encoder.encode_space(item) + if isinstance(item, np.dtype): + return {'__type__': 'np.dtype', '__items__': str(item)} + + # If it is a container data structure, go also through the items. + if isinstance(item, list): + return [Encoder.hint(e) for e in item] + if isinstance(item, dict): + return {key: Encoder.hint(value) for key, value in item.items()} + return item + # pylint: disable=arguments-differ + def encode(self, obj): + return super(Encoder, self).encode(Encoder.hint(obj)) + + @staticmethod + def encode_space(space_obj : gym.Space): + properties = [( + '__type__', + '.'.join([space_obj.__class__.__module__, space_obj.__class__.__name__] + ) + )] + + if not isinstance(space_obj, (gym.spaces.Dict, gym.spaces.Tuple)): + properties.append(('np_random', serialize_random_state(space_obj.np_random))) + + if isinstance(space_obj, (gym.spaces.Box, gym.spaces.Discrete, gym.spaces.MultiDiscrete, gym.spaces.MultiBinary)): + # by default assume all constrcutor arguments are stored under the same name + # for box we need to drop shape, since either shape or a array for low and height is required + __init__ = space_obj.__init__.__func__.__code__ + local_vars = __init__.co_varnames + + # drop self and non-args (self, arg1, arg2, ..., local_var1, local_var2, ...) + arguments = local_vars[1:__init__.co_argcount] + attributes_to_serialize = list(filter(lambda att: att not in ['shape'], arguments)) + + for attribute in attributes_to_serialize: + if hasattr(space_obj, attribute): + properties.append((attribute, Encoder.hint(getattr(space_obj, attribute)))) + elif isinstance(space_obj, gym.spaces.Tuple): + properties.append(('spaces', [Encoder.encode_space(space) for space in space_obj.spaces])) + elif isinstance(space_obj, gym.spaces.Dict): + properties.append(('spaces', {name:Encoder.encode_space(space) for name, space in space_obj.spaces.items()})) + else: + raise NotImplemented(f"Serialisation for type {properties['__type__']} not implemented") + + return dict(properties) + +class Decoder(json.JSONDecoder): + """ + Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py + + """ + def __init__(self, *args, **kwargs): + json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) + + def object_hook(self, obj: Any) -> Union[Union[tuple, np.ndarray, float, float, int], Any]: + if '__type__' in obj: + __type = obj['__type__'] + if __type == 'tuple': + return tuple(obj['__items__']) + if __type == 'np.ndarray': + return np.array(obj['__items__']) + if __type == 'np.float': + return np.float(obj['__items__']) + if __type == 'np.int': + return np.int(obj['__items__']) + if __type == 'random_state': + return deserialize_random_state(obj) + if __type == 'np.dtype': + return np.dtype(obj['__items__']) + if __type.startswith('gym.spaces.'): + return self.decode_space(obj) + return obj + + + def decode_space(self, space_dict: Dict) -> gym.Space: + __type = space_dict['__type__'] + __class = getattr(gym.spaces, __type.split('.')[-1]) + + args = {name:value for name, value in space_dict.items() if name not in ['__type__', 'np_random', 'shape']} + + # temporally remove subspace since constructor reseeds them + if issubclass(__class,(gym.spaces.Tuple, gym.spaces.Dict)): + spaces = args['spaces'] + args['spaces'] = type(args['spaces'])() + + space_object = __class(**args) + + # re-insert afterwards + if issubclass(__class, (gym.spaces.Tuple, gym.spaces.Dict)): + space_object.spaces = spaces + + if isinstance(space_object, gym.spaces.Tuple): + space_object.spaces = tuple(space_object.spaces) + + if not isinstance(space_object, (gym.spaces.Dict, gym.spaces.Tuple)): + space_object.np_random = space_dict['np_random'] + + return space_object + + +def deserialize_random_state(random_state_dict: Dict) -> np.random.RandomState: + (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state_dict['__items__'] + rnd1 = np.array(rnd1, dtype=np.uint32) + random_state = np.random.RandomState() + random_state.set_state((rnd0, rnd1, rnd2, rnd3, rnd4)) + return random_state + +def serialize_random_state(random_state: np.random.RandomState) -> Tuple[int, List, int, int, int]: + (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state.get_state() + rnd1 = rnd1.tolist() + return {'__type__': 'random_state', '__items__': [rnd0, rnd1, rnd2, rnd3, rnd4]} + + +def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: + """ + Wait for a UNIX socket to be created. + + :param path: path to the socket + :param timeout: timeout in seconds + :return: + """ + start = time.time() + while not os.path.exists(path): + if time.time() - start > timeout: + raise TimeoutError(f"Timeout ({timeout}s) waiting for UNIX socket {path} to be created") + time.sleep(0.1) + +def wait_for_port(port, host='localhost', timeout=5.0): + """ + Taken from https://gist.github.com/butla/2d9a4c0f35ea47b7452156c96a4e7b12 + Wait until a port starts accepting TCP connections. + + Parameters + ---------- + port : int + Port number to check. + host : str + Host to check. + timeout : float + Timeout in seconds. + + Raises: + ------ + TimeoutError: The port isn't accepting connection after time specified in `timeout`. + """ + start_time = time.perf_counter() + while True: + try: + with socket.create_connection((host, port), timeout=timeout): + break + except OSError as ex: + time.sleep(0.01) + if time.perf_counter() - start_time >= timeout: + raise TimeoutError('Waited too long for the port {} on host {} to start accepting ' + 'connections.'.format(port, host)) from ex + + diff --git a/build/lib/dacbench/container/remote_env.py b/build/lib/dacbench/container/remote_env.py new file mode 100644 index 000000000..60381d44f --- /dev/null +++ b/build/lib/dacbench/container/remote_env.py @@ -0,0 +1,81 @@ +import json +from numbers import Number + +from typing import Dict, Union, List, Tuple + +import Pyro4 +import numpy as np + + +from dacbench.abstract_env import AbstractEnv +from dacbench.container.container_utils import Encoder, Decoder + +NumpyTypes = Union[np.ndarray, np.int, np.float, np.random.RandomState] +DefaultJsonable = Union[ + bool, None, Dict[str, 'DefaultJsonable'], List['DefaultJsonable'], Tuple['DefaultJsonable'], str, float, int] +Jsonable = Union[List['Jsonable'], Dict[str, 'Jsonable'], Tuple['Jsonable'], DefaultJsonable, NumpyTypes] + + +def json_encode(obj: Jsonable) -> str: + return json.dumps(obj, indent=None, cls=Encoder) + + +def json_decode(json_str: str) -> Jsonable: + return json.loads(json_str, cls=Decoder) + + +@Pyro4.expose +class RemoteEnvironmentServer: + + def __init__(self, env): + self.__env: AbstractEnv = env + + def step(self, action: Union[Dict[str, List[Number]], List[Number]]): + action = json_decode(action) + json_str = json_encode(self.__env.step(action)) + return json_str + + def reset(self): + state = self.__env.reset() + state = json_encode(state) + return state + + def render(self, mode="human"): + # ever used? + pass + + def close(self): + self.__env.close() + + @property + def action_space(self): + return json_encode(self.__env.action_space) + + + +class RemoteEnvironmentClient: + + def __init__(self, env: RemoteEnvironmentServer): + self.__env = env + + def step(self, action: Union[Dict[str, np.ndarray], np.ndarray]) \ + -> Tuple[Union[Dict[str, np.ndarray], np.ndarray], Number, bool, dict]: + action = json_encode(action) + + json_str = self.__env.step(action) + + state, reward, done, info = json_decode(json_str) + + return state, reward, done, info + + def reset(self) -> Union[Dict[str, np.ndarray], np.ndarray]: + state = self.__env.reset() + state = json_decode(state) + return state + + def close(self): + self.__env.close() + + @property + def action_space(self): + return json_decode(self.__env.action_space) diff --git a/build/lib/dacbench/container/remote_runner.py b/build/lib/dacbench/container/remote_runner.py new file mode 100644 index 000000000..1be5919df --- /dev/null +++ b/build/lib/dacbench/container/remote_runner.py @@ -0,0 +1,278 @@ +""" +This is strongly guided and partially copy from +https://github.com/automl/HPOBench/blob/master/hpobench/container/client_abstract_benchmark.py +""" +import argparse +import logging +import os +import subprocess +import sys +from pathlib import Path +from typing import Tuple, Optional, Union +from uuid import uuid1 + +import Pyro4 +import Pyro4.naming + +from dacbench.abstract_agent import AbstractDACBenchAgent +from dacbench.abstract_benchmark import AbstractBenchmark +from dacbench.argument_parsing import PathType +from dacbench.container.container_utils import wait_for_unixsocket +from dacbench.container.remote_env import RemoteEnvironmentServer, RemoteEnvironmentClient + +# Needed in order to combine event loops of name_server and daemon +Pyro4.config.SERVERTYPE = "multiplex" + +# Read in the verbosity level from the environment variable +log_level_str = os.environ.get('DACBENCH_DEBUG', 'false') + +LOG_LEVEL = logging.INFO +LOG_LEVEL = logging.DEBUG if log_level_str == 'true' else logging.INFO + +root = logging.getLogger() +root.setLevel(level=LOG_LEVEL) + +logger = logging.getLogger(__name__) +logger.setLevel(level=LOG_LEVEL) + +# This option improves the quality of stacktraces if a container crashes +sys.excepthook = Pyro4.util.excepthook +# os.environ["PYRO_LOGFILE"] = "pyro.log" +# os.environ["PYRO_LOGLEVEL"] = "DEBUG" + +# Number of tries to connect to server +MAX_TRIES = 5 + +SOCKET_PATH = Path('/tmp/dacbench/sockets') + + +@Pyro4.expose +class RemoteRunnerServer: + def __init__(self, pyro_demon): + self.benchmark = None + self.pyro_demon = pyro_demon + + def start(self, config: str, benchmark: Tuple[str, str]): + benchmark = AbstractBenchmark.import_from(*benchmark) + + self.benchmark = benchmark.from_json(config) + + def get_environment(self) -> str: + env = self.benchmark.get_environment() + + # set up logger and stuff + + self.env = RemoteEnvironmentServer(env) + uri = self.pyro_demon.register(self.env) + return uri + + +class RemoteRunner: + FACTORY_NAME: str = "RemoteRunnerServerFactory" + + def __init__(self, benchmark: AbstractBenchmark, container_name: str = None, container_source: Optional[str] = None, + container_tag: str = 'latest', env_str: Optional[str] = '', bind_str: Optional[str] = '', + gpu: Optional[bool] = False, socket_id=None): + """ + + Parameters: + ---------------- + + benchmark: AbstractBenchmark + The benchmark to run + container_source : Optional[str] + Path to the container. Either local path or url to a hosting + platform, e.g. singularity hub. + container_tag : str + Singularity containers are specified by an address as well as a container tag. We use the tag as a version + number. By default the tag is set to `latest`, which then pulls the latest container from the container + source. The tag-versioning allows the users to rerun an experiment, which was performed with an older + container version. Take a look in the container_source to find the right tag to use. + bind_str : Optional[str] + Defaults to ''. You can bind further directories into the container. + This string have the form src[:dest[:opts]]. + For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html + env_str : Optional[str] + Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some + environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. + For more information, see + https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview + gpu : bool + If True, the container has access to the local cuda-drivers. + (Not tested) + socket_id : Optional[str] + Setting up the container is done in two steps: + 1) Start the benchmark on a random generated socket id. + 2) Create a proxy connection to the container via this socket id. + + When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is + stored in the class attribute Benchmark.socket_id + + When a `socket_id` is given, instead of creating a new container, connect only to the container that is + reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. + + """ + logger.info(f'Logging level: {logger.level}') + # connect to already running server if a socket_id is given. In this case, skip the init of + # the benchmark + self.__proxy_only = socket_id is not None + self.__socket_path = SOCKET_PATH + + if not self.__proxy_only: + self.__socket_id = self.id_generator() + # todo for now only work with given container source (local) + self.load_benchmark(benchmark=benchmark, container_name=container_name, + container_source=container_source, container_tag=container_tag,) + self.__start_server(env_str=env_str, bind_str=bind_str, gpu=gpu) + else: + self.__socket_id = socket_id + + self.__connect_to_server(benchmark) + + @property + def socket(self) -> Path: + return self.socket_from_id(self.__socket_id) + + @staticmethod + def id_generator() -> str: + """ Helper function: Creates unique socket ids for the benchmark server """ + return str(uuid1()) + + @staticmethod + def socket_from_id(socket_id: str) -> Path: + return Path(SOCKET_PATH) / f'{socket_id}.unixsock' + + def __start_server(self, env_str, bind_str, gpu): + """ + Starts container and the pyro server + + Parameters + ---------- + env_str : str + Environment string for the container + bind_str : str + Bind string for the container + gpu : bool + True if the container should use gpu, False otherwise + """ + # start container + logger.debug(f'Starting server on {self.socket}') + + # todo add mechanism to to retry if failing + self.daemon_process = subprocess.Popen( + [ + "singularity", + "run", + "-e", + str(self.container_source), + "-u", + str(self.socket) + ] + ) + + # todo should be configurable + wait_for_unixsocket(self.socket, 10) + + def __connect_to_server(self, benchmark: AbstractBenchmark): + """ + Connects to the server and initializes the benchmark + """ + # Pyro4.config.REQUIRE_EXPOSE = False + # Generate Pyro 4 URI for connecting to client + ns = Pyro4.Proxy(f"PYRO:Pyro.NameServer@./u:{self.socket}") + factory_uri = ns.lookup(self.FACTORY_NAME) + + factory = Pyro4.Proxy(factory_uri) + remote_runner_uri = factory.create() + self.remote_runner: RemoteRunnerServer = Pyro4.Proxy(remote_runner_uri) + + serialized_config = benchmark.to_json() + serialized_type = benchmark.class_to_str() + self.remote_runner.start(serialized_config, serialized_type) + self.env = None + + def get_environment(self): + if self.env is None: + env_uri = self.remote_runner.get_environment() + remote_env_server = Pyro4.Proxy(env_uri) + self.env = RemoteEnvironmentClient(remote_env_server) + return self.env + + def run(self, agent: AbstractDACBenchAgent, number_of_episodes: int): + # todo: seeding + env = self.get_environment() + + for _ in range(number_of_episodes): + state = env.reset() + done = False + reward = 0 + while not done: + action = agent.act(state, reward) + next_state, reward, done, _ = env.step(action) + agent.train(next_state, reward) + state = next_state + agent.end_episode(state, reward) + + env.close() + self.env = None + + def close(self): + # todo add context manager + self.daemon_process.terminate() + self.daemon_process.wait() + + def __del__(self): + self.close() + + def load_benchmark(self, benchmark : AbstractBenchmark, container_name : str, container_source : Union[str, Path], container_tag : str): + # see for implementation guideline hpobench hpobench/container/client_abstract_benchmark.py + # in the end self.container_source should contain the path to the file to run + + logger.warning("Only container source is used") + container_source = container_source if isinstance(container_source, Path) else Path(container_source) + + self.container_source = container_source + + +@Pyro4.expose +class RemoteRunnerServerFactory: + def __init__(self, pyro_demon): + self.pyro_demon = pyro_demon + + def create(self): + remote_runner_server = RemoteRunnerServer(pyro_demon=self.pyro_demon) + remote_runner_server_uri = daemon.register(remote_runner_server) + return remote_runner_server_uri + + def __call__(self): + return self.create() + + +if __name__ == '__main__': + # todo refactor move to RemoverRunnerServer + parser = argparse.ArgumentParser(description='Runs the benchmark remote server inside a container') + + parser.add_argument('--unixsocket', '-u', type=PathType(exists=False, type='socket'), required=False, default=None, + dest='socket', + help="The path to a exiting socket to run the name server on. If none a new socket unixsocket is created.") + + args = parser.parse_args() + + daemon_socket = RemoteRunner.socket_from_id(RemoteRunner.id_generator()) + ns_socket = args.socket if args.socket else RemoteRunner.socket_from_id(RemoteRunner.id_generator()) + print(ns_socket) + daemon_socket.parent.mkdir(parents=True, exist_ok=True) + ns_socket.parent.mkdir(parents=True, exist_ok=True) + + print(f'Starting Pyro4 Nameserver on {ns_socket} and Pyro4 Daemon on {daemon_socket}') + name_server_uir, name_server_daemon, _ = Pyro4.naming.startNS(unixsocket=str(ns_socket)) + daemon = Pyro4.Daemon(unixsocket=str(daemon_socket)) + daemon.combine(name_server_daemon) + factory = RemoteRunnerServerFactory(daemon) + factory_uri = daemon.register(factory) + name_server_daemon.nameserver.register("RemoteRunnerServerFactory", factory_uri) + + daemon.requestLoop() + + daemon_socket.unlink() + ns_socket.unlink() diff --git a/build/lib/dacbench/envs/__init__.py b/build/lib/dacbench/envs/__init__.py new file mode 100644 index 000000000..b853a7629 --- /dev/null +++ b/build/lib/dacbench/envs/__init__.py @@ -0,0 +1,81 @@ +# flake8: noqa: F401 +from dacbench.envs.luby import LubyEnv, luby_gen +from dacbench.envs.sigmoid import ( + SigmoidEnv, + ContinuousSigmoidEnv, + ContinuousStateSigmoidEnv, +) +from dacbench.envs.fast_downward import FastDownwardEnv +from dacbench.envs.toysgd import ToySGDEnv +from dacbench.envs.geometric import GeometricEnv + +__all__ = [ + "LubyEnv", + "luby_gen", + "SigmoidEnv", + "FastDownwardEnv", + "ToySGDEnv", + "GeometricEnv", +] + + +import importlib +import warnings + +cma_spec = importlib.util.find_spec("cma") +found = cma_spec is not None +if found: + from dacbench.envs.cma_es import CMAESEnv + + __all__.append("CMAESEnv") +else: + warnings.warn( + "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +modea_spec = importlib.util.find_spec("modea") +found = modea_spec is not None +if found: + from dacbench.envs.modea import ModeaEnv + + __all__.append("ModeaEnv") +else: + warnings.warn( + "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +modcma_spec = importlib.util.find_spec("modcma") +found = modcma_spec is not None +if found: + from dacbench.envs.cma_step_size import CMAStepSizeEnv + from dacbench.envs.modcma import ModCMAEnv + + __all__.append("ModCMAEnv") + __all__.append("CMAStepSizeEnv") +else: + warnings.warn( + "ModCMA Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +sgd_spec = importlib.util.find_spec("backpack") +found = sgd_spec is not None +if found: + from dacbench.envs.sgd import SGDEnv + + __all__.append("SGDEnv") +else: + warnings.warn( + "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) + +theory_spec = importlib.util.find_spec("uuid") +found = theory_spec is not None +if found: + from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv + + __all__.append("RLSEnv") + __all__.append("RLSEnvDiscrete") +else: + warnings.warn( + "Theory Benchmark not installed. If you want to use this benchmark, please follow the installation guide." + ) diff --git a/build/lib/dacbench/envs/cma_es.py b/build/lib/dacbench/envs/cma_es.py new file mode 100644 index 000000000..af89fc074 --- /dev/null +++ b/build/lib/dacbench/envs/cma_es.py @@ -0,0 +1,255 @@ +""" +CMA-ES environment adapted from CMAWorld in +"Learning Step-size Adaptation in CMA-ES" +by G.Shala and A. Biedenkapp and N.Awad and S. Adriaensen and M.Lindauer and F. Hutter. +Original author: Gresa Shala +""" + +import numpy as np +from collections import deque +from cma.evolution_strategy import CMAEvolutionStrategy +from cma import bbobbenchmarks as bn +import threading +import warnings +from dacbench import AbstractEnv +import resource +import sys + +resource.setrlimit(resource.RLIMIT_STACK, (2 ** 35, -1)) +sys.setrecursionlimit(10 ** 9) + +warnings.filterwarnings("ignore") + + +def _norm(x): + return np.sqrt(np.sum(np.square(x))) + + +# IDEA: if we ask cma instead of ask_eval, we could make this parallel + + +class CMAESEnv(AbstractEnv): + """ + Environment to control the step size of CMA-ES + """ + + def __init__(self, config): + """ + Initialize CMA Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super(CMAESEnv, self).__init__(config) + self.b = None + self.bounds = [None, None] + self.fbest = None + self.history_len = config.hist_length + self.history = deque(maxlen=self.history_len) + self.past_obj_vals = deque(maxlen=self.history_len) + self.past_sigma = deque(maxlen=self.history_len) + self.solutions = None + self.func_values = [] + self.cur_obj_val = -1 + # self.chi_N = dim ** 0.5 * (1 - 1.0 / (4.0 * dim) + 1.0 / (21.0 * dim ** 2)) + self.lock = threading.Lock() + self.popsize = config["popsize"] + self.cur_ps = self.popsize + + if "reward_function" in config.keys(): + self.get_reward = config["reward_function"] + else: + self.get_reward = self.get_default_reward + + if "state_method" in config.keys(): + self.get_state = config["state_method"] + else: + self.get_state = self.get_default_state + + def step(self, action): + """ + Execute environment step + + Parameters + ---------- + action : list + action to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, info + """ + truncated = super(CMAESEnv, self).step_() + self.history.append([self.f_difference, self.velocity]) + terminated = self.es.stop() != {} + if not (terminated or truncated): + """Moves forward in time one step""" + sigma = action + self.es.tell(self.solutions, self.func_values) + self.es.sigma = np.maximum(sigma, 0.2) + self.solutions, self.func_values = self.es.ask_and_eval(self.fcn) + + self.f_difference = np.nan_to_num( + np.abs(np.amax(self.func_values) - self.cur_obj_val) + / float(self.cur_obj_val) + ) + self.velocity = np.nan_to_num( + np.abs(np.amin(self.func_values) - self.cur_obj_val) + / float(self.cur_obj_val) + ) + self.fbest = min(self.es.best.f, np.amin(self.func_values)) + + self.past_obj_vals.append(self.cur_obj_val) + self.past_sigma.append(self.cur_sigma) + self.cur_ps = _norm(self.es.adapt_sigma.ps) + self.cur_loc = self.es.best.x + try: + self.cur_sigma = [self.es.sigma[0]] + except: + self.cur_sigma = [self.es.sigma] + self.cur_obj_val = self.es.best.f + + return self.get_state(self), self.get_reward(self), terminated, truncated, {} + + def reset(self): + """ + Reset environment + + Returns + ------- + np.array + Environment state + """ + super(CMAESEnv, self).reset_() + self.history.clear() + self.past_obj_vals.clear() + self.past_sigma.clear() + self.cur_loc = self.instance[3] + self.dim = self.instance[1] + self.init_sigma = self.instance[2] + self.cur_sigma = [self.init_sigma] + self.fcn = bn.instantiate(self.instance[0])[0] + + self.func_values = [] + self.f_vals = deque(maxlen=self.popsize) + self.es = CMAEvolutionStrategy( + self.cur_loc, + self.init_sigma, + {"popsize": self.popsize, "bounds": self.bounds, "seed": self.initial_seed}, + ) + self.solutions, self.func_values = self.es.ask_and_eval(self.fcn) + self.fbest = self.func_values[np.argmin(self.func_values)] + self.f_difference = np.abs( + np.amax(self.func_values) - self.cur_obj_val + ) / float(self.cur_obj_val) + self.velocity = np.abs(np.amin(self.func_values) - self.cur_obj_val) / float( + self.cur_obj_val + ) + self.es.mean_old = self.es.mean + self.history.append([self.f_difference, self.velocity]) + return self.get_state(self), {} + + def close(self): + """ + No additional cleanup necessary + + Returns + ------- + bool + Cleanup flag + """ + return True + + def render(self, mode: str = "human"): + """ + Render env in human mode + + Parameters + ---------- + mode : str + Execution mode + """ + if mode != "human": + raise NotImplementedError + + pass + + def get_default_reward(self, _): + """ + Compute reward + + Returns + ------- + float + Reward + + """ + reward = min(self.reward_range[1], max(self.reward_range[0], -self.fbest)) + return reward + + def get_default_state(self, _): + """ + Gather state description + + Returns + ------- + dict + Environment state + + """ + past_obj_val_deltas = [] + for i in range(1, len(self.past_obj_vals)): + past_obj_val_deltas.append( + (self.past_obj_vals[i] - self.past_obj_vals[i - 1] + 1e-3) + / float(self.past_obj_vals[i - 1]) + ) + if len(self.past_obj_vals) > 0: + past_obj_val_deltas.append( + (self.cur_obj_val - self.past_obj_vals[-1] + 1e-3) + / float(self.past_obj_vals[-1]) + ) + past_obj_val_deltas = np.array(past_obj_val_deltas).reshape(-1) + + history_deltas = [] + for i in range(len(self.history)): + history_deltas.append(self.history[i]) + history_deltas = np.array(history_deltas).reshape(-1) + past_sigma_deltas = [] + for i in range(len(self.past_sigma)): + past_sigma_deltas.append(self.past_sigma[i]) + past_sigma_deltas = np.array(past_sigma_deltas).reshape(-1) + past_obj_val_deltas = np.hstack( + ( + np.zeros((self.history_len - past_obj_val_deltas.shape[0],)), + past_obj_val_deltas, + ) + ) + history_deltas = np.hstack( + ( + np.zeros((self.history_len * 2 - history_deltas.shape[0],)), + history_deltas, + ) + ) + past_sigma_deltas = np.hstack( + ( + np.zeros((self.history_len - past_sigma_deltas.shape[0],)), + past_sigma_deltas, + ) + ) + + cur_loc = np.array(self.cur_loc) + cur_ps = np.array([self.cur_ps]) + cur_sigma = np.array(self.cur_sigma) + + state = { + "current_loc": cur_loc, + "past_deltas": past_obj_val_deltas, + "current_ps": cur_ps, + "current_sigma": cur_sigma, + "history_deltas": history_deltas, + "past_sigma_deltas": past_sigma_deltas, + } + return state diff --git a/build/lib/dacbench/envs/cma_step_size.py b/build/lib/dacbench/envs/cma_step_size.py new file mode 100644 index 000000000..2ca91fd1d --- /dev/null +++ b/build/lib/dacbench/envs/cma_step_size.py @@ -0,0 +1,54 @@ +import numpy as np +from modcma import ModularCMAES, Parameters +from IOHexperimenter import IOH_function + +from dacbench import AbstractEnv + + +class CMAStepSizeEnv(AbstractEnv): + def __init__(self, config): + super().__init__(config) + + self.es = None + self.budget = config.budget + self.total_budget = self.budget + + self.get_reward = config.get("reward_function", self.get_default_reward) + self.get_state = config.get("state_method", self.get_default_state) + + def reset(self): + super().reset_() + self.dim, self.fid, self.iid, self.representation = self.instance + self.objective = IOH_function( + self.fid, self.dim, self.iid, target_precision=1e-8 + ) + self.es = ModularCMAES( + self.objective, + parameters=Parameters.from_config_array(self.dim, self.representation), + ) + return self.get_state(self), {} + + def step(self, action): + truncated = super().step_() + self.es.parameters.sigma = action + terminated = not self.es.step() + return self.get_state(self), self.get_reward(self), terminated, truncated, {} + + def close(self): + return True + + def get_default_reward(self, *_): + return max( + self.reward_range[0], min(self.reward_range[1], -self.es.parameters.fopt) + ) + + def get_default_state(self, *_): + return np.array( + [ + self.es.parameters.lambda_, + self.es.parameters.sigma, + self.budget - self.es.parameters.used_budget, + self.fid, + self.iid, + ] + ) diff --git a/build/lib/dacbench/envs/fast_downward.py b/build/lib/dacbench/envs/fast_downward.py new file mode 100644 index 000000000..ebe9d277f --- /dev/null +++ b/build/lib/dacbench/envs/fast_downward.py @@ -0,0 +1,452 @@ +""" +Planning environment from +"Learning Heuristic Selection with Dynamic Algorithm Configuration" +by David Speck, André Biedenkapp, Frank Hutter, Robert Mattmüller und Marius Lindauer. +Original environment authors: David Speck, André Biedenkapp +""" + +import socket +import time +import typing +from copy import deepcopy +from enum import Enum +from os import remove +from os.path import join as joinpath +import subprocess +import os +import numpy as np +from dacbench import AbstractEnv + + +class StateType(Enum): + """Class to define numbers for state types""" + + RAW = 1 + DIFF = 2 + ABSDIFF = 3 + NORMAL = 4 + NORMDIFF = 5 + NORMABSDIFF = 6 + + +class FastDownwardEnv(AbstractEnv): + """ + Environment to control Solver Heuristics of FastDownward + """ + + def __init__(self, config): + """ + Initialize FD Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super(FastDownwardEnv, self).__init__(config) + self._heuristic_state_features = [ + "Average Value", # 'Dead Ends Reliable', + "Max Value", + "Min Value", + "Open List Entries", + "Varianz", + ] + self._general_state_features = [ # 'evaluated_states', 'evaluations', 'expanded_states', + # 'generated_ops', + # 'generated_states', 'num_variables', + # 'registered_states', 'reopened_states', + # "cg_num_eff_to_eff", "cg_num_eff_to_pre", "cg_num_pre_to_eff" + ] + + total_state_features = len(config.heuristics) * len( + self._heuristic_state_features + ) + self._use_gsi = config.use_general_state_info + if config.use_general_state_info: + total_state_features += len(self._general_state_features) + + self.__skip_transform = [False for _ in range(total_state_features)] + if config.use_general_state_info: + self.__skip_transform[4] = True # skip num_variables transform + self.__skip_transform[7] = True + self.__skip_transform[8] = True + self.__skip_transform[9] = True + + self.heuristics = config.heuristics + self.host = config.host + self._port = config.get("port", 0) + if config["parallel"]: + self.port = 0 + + self.fd_seed = config.fd_seed + self.control_interval = config.control_interval + + if config.fd_logs is None: + self.logpath_out = os.devnull + self.logpath_err = os.devnull + else: + self.logpath_out = os.path.join(config.fd_logs, "fdout.txt") + self.logpath_err = os.path.join(config.fd_logs, "fderr.txt") + self.fd_path = config.fd_path + self.fd = None + if "domain_file" in config.keys(): + self.domain_file = config["domain_file"] + + self.socket = None + self.conn = None + + self._prev_state = None + self.num_steps = config.num_steps + + self.__state_type = StateType(config.state_type) + self.__norm_vals = [] + self._config_dir = config.config_dir + self._port_file_id = config.port_file_id + + self._transformation_func = None + # create state transformation function with inputs (current state, previous state, normalization values) + if self.__state_type == StateType.DIFF: + self._transformation_func = lambda x, y, z, skip: x - y if not skip else x + elif self.__state_type == StateType.ABSDIFF: + self._transformation_func = ( + lambda x, y, z, skip: abs(x - y) if not skip else x + ) + elif self.__state_type == StateType.NORMAL: + self._transformation_func = ( + lambda x, y, z, skip: FastDownwardEnv._save_div(x, z) if not skip else x + ) + elif self.__state_type == StateType.NORMDIFF: + self._transformation_func = ( + lambda x, y, z, skip: FastDownwardEnv._save_div(x, z) + - FastDownwardEnv._save_div(y, z) + if not skip + else x + ) + elif self.__state_type == StateType.NORMABSDIFF: + self._transformation_func = ( + lambda x, y, z, skip: abs( + FastDownwardEnv._save_div(x, z) - FastDownwardEnv._save_div(y, z) + ) + if not skip + else x + ) + + self.max_rand_steps = config.max_rand_steps + self.__start_time = None + self.done = True # Starts as true as the expected behavior is that before normal resets an episode was done. + + @property + def port(self): + if self._port == 0: + if self.socket is None: + raise ValueError( + "Automatic port selection enabled. Port not know at the moment" + ) + _, port = self.socket.getsockname() + else: + port = self._port + return port + + @port.setter + def port(self, port): + self._port = port + + @property + def argstring(self): + # if a socket is bound to 0 it will automatically choose a free port + return f"rl_eager(rl([{''.join(f'{h},' for h in self.heuristics)[:-1]}],random_seed={self.fd_seed}),rl_control_interval={self.control_interval},rl_client_port={self.port})" + + @staticmethod + def _save_div(a, b): + """ + Helper method for safe division + + Parameters + ---------- + a : list or np.array + values to be divided + b : list or np.array + values to divide by + + Returns + ------- + np.array + Division result + """ + return np.divide(a, b, out=np.zeros_like(a), where=b != 0) + + def send_msg(self, msg: bytes): + """ + Send message and prepend the message size + + Based on comment from SO see [1] + [1] https://stackoverflow.com/a/17668009 + + Parameters + ---------- + msg : bytes + The message as byte + """ + # Prefix each message with a 4-byte length (network byte order) + msg = str.encode("{:>04d}".format(len(msg))) + msg + self.conn.sendall(msg) + + def recv_msg(self): + """ + Recieve a whole message. The message has to be prepended with its total size + Based on comment from SO see [1] + + Returns + ---------- + bytes + The message as byte + """ + # Read message length and unpack it into an integer + raw_msglen = self.recvall(4) + if not raw_msglen: + return None + msglen = int(raw_msglen.decode()) + # Read the message data + return self.recvall(msglen) + + def recvall(self, n: int): + """ + Given we know the size we want to recieve, we can recieve that amount of bytes. + Based on comment from SO see [1] + + Parameters + --------- + n: int + Number of bytes to expect in the data + + Returns + ---------- + bytes + The message as byte + """ + # Helper function to recv n bytes or return None if EOF is hit + data = b"" + while len(data) < n: + packet = self.conn.recv(n - len(data)) + if not packet: + return None + data += packet + return data + + def _process_data(self): + """ + Split received json into state reward and done + + Returns + ---------- + np.array, float, bool + state, reward, done + """ + msg = self.recv_msg().decode() + # print("----------------------------") + # print(msg) + # print("=>") + msg = msg.replace("-inf", "0") + msg = msg.replace("inf", "0") + # print(msg) + data = eval(msg) + r = data["reward"] + done = data["done"] + del data["reward"] + del data["done"] + + state = [] + + if self._use_gsi: + for feature in self._general_state_features: + state.append(data[feature]) + for heuristic_id in range(len(self.heuristics)): # process heuristic data + for feature in self._heuristic_state_features: + state.append(data["%d" % heuristic_id][feature]) + + if self._prev_state is None: + self.__norm_vals = deepcopy(state) + self._prev_state = deepcopy(state) + if ( + self.__state_type != StateType.RAW + ): # Transform state to DIFF state or normalize + tmp_state = state + state = list( + map( + self._transformation_func, + state, + self._prev_state, + self.__norm_vals, + self.__skip_transform, + ) + ) + self._prev_state = tmp_state + return np.array(state), r, done + + def step(self, action: typing.Union[int, typing.List[int]]): + """ + Environment step + + Parameters + --------- + action: typing.Union[int, List[int]] + Parameter(s) to apply + + Returns + ---------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info + """ + self.done = super(FastDownwardEnv, self).step_() + if not np.issubdtype( + type(action), np.integer + ): # check for core int and any numpy-int + try: + action = action[0] + except IndexError as e: + print(type(action)) + raise e + if self.num_steps: + msg = ",".join([str(action), str(self.num_steps)]) + else: + msg = str(action) + self.send_msg(str.encode(msg)) + s, r, terminated = self._process_data() + r = max(self.reward_range[0], min(self.reward_range[1], r)) + info = {} + if terminated: + self.done = True + self.kill_connection() + if self.c_step > self.n_steps: + info["needs_reset"] = True + self.send_msg(str.encode("END")) + self.kill_connection() + return s, r, terminated, self.done, info + + def reset(self): + """ + Reset environment + + Returns + ---------- + np.array + State after reset + dict + Meta-info + """ + super(FastDownwardEnv, self).reset_() + self._prev_state = None + self.__start_time = time.time() + if not self.done: # This means we interrupt FD before a plan was found + # Inform FD about imminent shutdown of the connection + self.send_msg(str.encode("END")) + self.done = False + if self.conn: + self.conn.shutdown(2) + self.conn.close() + self.conn = None + if not self.socket: + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.settimeout(10) + self.socket.bind((self.host, self.port)) + + if self.fd: + self.fd.terminate() + + if self.instance.endswith(".pddl"): + command = [ + "python3", + f"{self.fd_path}", + self.domain_file, + self.instance, + "--search", + self.argstring, + ] + else: + command = [ + "python3", + f"{self.fd_path}", + self.instance, + "--search", + self.argstring, + ] + + with open(self.logpath_out, "a+") as fout, open(self.logpath_err, "a+") as ferr: + err_output = subprocess.STDOUT if self.logpath_err == "/dev/null" else ferr + self.fd = subprocess.Popen(command, stdout=fout, stderr=err_output) + + # write down port such that FD can potentially read where to connect to + if self._port_file_id: + fp = joinpath(self._config_dir, "port_{:d}.txt".format(self._port_file_id)) + else: + fp = joinpath(self._config_dir, f"port_{self.port}.txt") + with open(fp, "w") as portfh: + portfh.write(str(self.port)) + + self.socket.listen() + try: + self.conn, address = self.socket.accept() + except socket.timeout: + raise OSError( + "Fast downward subprocess not reachable (time out). " + "Possible solutions:\n" + " (1) Did you run './dacbench/envs/rl-plan/fast-downward/build.py' " + "in order to build the fd backend?\n" + " (2) Try to fix this by setting OPENBLAS_NUM_THREADS=1. " + "For more details see https://github.com/automl/DACBench/issues/96" + ) + + s, _, _ = self._process_data() + if self.max_rand_steps > 1: + for _ in range(self.np_random.randint(1, self.max_rand_steps + 1)): + s, _, _, _ = self.step(self.action_space.sample()) + if self.conn is None: + return self.reset() + else: + s, _, _, _ = self.step(0) # hard coded to zero as initial step + + remove( + fp + ) # remove the port file such that there is no chance of loading the old port + return s, {} + + def kill_connection(self): + """Kill the connection""" + if self.conn: + self.conn.shutdown(2) + self.conn.close() + self.conn = None + if self.socket: + self.socket.shutdown(2) + self.socket.close() + self.socket = None + + def close(self): + """ + Close Env + + Returns + ------- + bool + Closing confirmation + """ + if self.socket is None: + return True + fp = joinpath(self._config_dir, f"port_{self.port}.txt") + if os.path.exists(fp): + remove(fp) + + self.kill_connection() + return True + + def render(self, mode: str = "human") -> None: + """ + Required by gym.Env but not implemented + + Parameters + ------- + mode : str + Rendering mode + """ + pass diff --git a/build/lib/dacbench/envs/geometric.py b/build/lib/dacbench/envs/geometric.py new file mode 100644 index 000000000..e3e2aacb0 --- /dev/null +++ b/build/lib/dacbench/envs/geometric.py @@ -0,0 +1,665 @@ +""" +Geometric environment. +Original environment authors: Rasmus von Glahn +""" +import bisect +import os +import itertools +import math +from typing import List, Dict, Tuple + +from mpl_toolkits import mplot3d +from matplotlib import pyplot as plt +import numpy as np +import seaborn as sns + +sns.set_theme(style="darkgrid") + +from dacbench import AbstractEnv + + +class GeometricEnv(AbstractEnv): + """ + Environment for tracing different curves that are orthogonal to each other + Use product approach: f(t,x,y,z) = X(t,x) * Y(t,y) * Z(t,z) + Normalize Function Value on a Scale between 0 and 1 + - min and max value for normalization over all timesteps + """ + + def __init__(self, config) -> None: + """ + Initialize Geometric Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super(GeometricEnv, self).__init__(config) + + self.action_vals = config["action_values"] + self.action_interval_mapping = config["action_interval_mapping"] + self.realistic_trajectory = config["realistic_trajectory"] + self.derivative_interval = config["derivative_interval"] + + self.correlation_table = config["correlation_table"] + self.correlation_active = config["correlation_active"] + self.correlation_depth = config["correlation_depth"] + self.n_steps = config["cutoff"] + + self._prev_state = None + self.action = None + self.n_actions = len(self.action_vals) + self.action_mapper = {} + + # Functions + self.functions = Functions( + self.n_steps, + self.n_actions, + len(self.instance_set), + self.correlation_active, + self.correlation_table, + self.correlation_depth, + self.derivative_interval, + ) + self.functions.calculate_norm_values(self.instance_set) + + # Trajectories + self.action_trajectory = [] + self.coord_trajectory = [] + self.action_trajectory_set = {} + self.coord_trajectory_set = {} + + self.derivative = [] + self.derivative_set = {} + + # Map actions from int to vector representation + for idx, prod_idx in zip( + range(np.prod(config["action_values"])), + itertools.product(*[np.arange(val) for val in config["action_values"]]), + ): + self.action_mapper[idx] = prod_idx + + if "reward_function" in config.keys(): + self.get_reward = config["reward_function"] + else: + self.get_reward = self.get_default_reward + + if "state_method" in config.keys(): + self.get_state = config["state_method"] + else: + self.get_state = self.get_default_state + + def get_optimal_policy( + self, instance: List = None, vector_action: bool = True + ) -> List[np.array]: + """ + Calculates the optimal policy for an instance + + Parameters + ---------- + instance : List, optional + instance with information about function config. + vector_action : bool, optional + if True return multidim actions else return onedimensional action, by default True + + Returns + ------- + List[np.array] + List with entry for each timestep that holds all optimal values in an array or as int + """ + if not instance: + instance = self.instance + + optimal_policy_coords = self.functions.get_coordinates(instance).transpose() + optimal_policy = np.zeros(((self.n_steps, self.n_actions))) + + for step in range(self.n_steps): + for dimension in range(self.n_actions): + step_size = 2 / self.action_vals[dimension] + interval = [step for step in np.arange(-1, 1, step_size)][1:] + + optimal_policy[step, dimension] = bisect.bisect_left( + interval, optimal_policy_coords[step, dimension] + ) + + optimal_policy = optimal_policy.astype(int) + if not vector_action: + reverse_action_mapper = {v: k for k, v in self.action_mapper.items()} + optimal_policy = [ + reverse_action_mapper[tuple(vec)] for vec in optimal_policy + ] + + return optimal_policy + + def step(self, action: int): + """ + Execute environment step + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info + """ + self.done = super(GeometricEnv, self).step_() + + # map integer action to vector + action_vec = self.action_mapper[action] + assert self.n_actions == len( + action_vec + ), f"action should be of length {self.n_actions}." + self.action = action_vec + + coords = self.functions.get_coordinates_at_time_step(self.c_step) + self.coord_trajectory.append(coords) + self.action_trajectory.append(np.array(action_vec)) + + self.coord_trajectory_set[self.inst_id] = self.coord_trajectory + self.action_trajectory_set[self.inst_id] = self.action_trajectory + + if self.realistic_trajectory: + self.derivative = self.functions.calculate_derivative( + self.coord_trajectory, self.c_step + ) + else: + self.derivative = self.functions.calculate_derivative( + self.action_trajectory, self.c_step + ) + + self.derivative_set[self.inst_id] = self.derivative + + next_state = self.get_state(self) + self._prev_state = next_state + + reward = self.get_reward(self) + if reward > 1: + print(f"Instance: {self.instance}, Reward:{reward}, step: {self.c_step}") + raise ValueError(f"Reward zu Hoch Coords: {coords}, step: {self.c_step}") + if math.isnan(reward): + raise ValueError(f"Reward NAN Coords: {coords}, step: {self.c_step}") + + return next_state, reward, False, self.done, {} + + def reset(self) -> List[int]: + """ + Resets env + + Returns + ------- + numpy.array + Environment state + dict + Meta-info + """ + super(GeometricEnv, self).reset_() + self.functions.set_instance(self.instance, self.instance_index) + + if self.c_step: + self.action_trajectory = self.action_trajectory_set.get(self.inst_id) + + self.coord_trajectory = self.coord_trajectory_set.get( + self.inst_id, [self.functions.get_coordinates_at_time_step(self.c_step)] + ) + + self.derivative = self.derivative_set.get( + self.inst_id, np.zeros(self.n_actions) + ) + self._prev_state = None + + return self.get_state(self), {} + + def get_default_reward(self, _) -> float: + """ + Calculate euclidean distance between action vector and real position of Curve. + + Parameters + ---------- + _ : self + ignore + + Returns + ------- + float + Euclidean distance + """ + coords, action_coords, highest_coords, lowest_actions = self._pre_reward() + euclidean_dist = np.linalg.norm(action_coords - coords) + + max_dist = np.linalg.norm(highest_coords - lowest_actions) + reward = 1 - (euclidean_dist / max_dist) + + return abs(reward) + + def get_default_state(self, _) -> np.array: + """ + Gather state information. + + Parameters + ---------- + _ : + ignore param + + Returns + ------- + np.array + numpy array with state information + """ + remaining_budget = self.n_steps - self.c_step + next_state = [remaining_budget] + + next_state += [self.n_actions] + + if self.c_step == 0: + next_state += [0 for _ in range(self.n_actions)] + next_state += [0 for _ in range(self.n_actions)] + else: + next_state += list(self.derivative) + next_state += list(self.coord_trajectory[self.c_step]) + + return np.array(next_state, dtype="float32") + + def close(self) -> bool: + """ + Close Env + + Returns + ------- + bool + Closing confirmation + """ + return True + + def render(self, dimensions: List, absolute_path: str): + """ + Multiplot for specific dimensions of benchmark with policy actions. + + Parameters + ---------- + dimensions : List + List of dimensions that get plotted + """ + coordinates = self.functions.get_coordinates() + + fig, axes = plt.subplots( + len(dimensions), sharex=True, sharey=True, figsize=(15, 4 * len(dimensions)) + ) + plt.xlabel("time steps", fontsize=32) + plt.ylim(-1.1, 1.1) + plt.xlim(-0.1, self.n_steps - 0.9) + plt.xticks(np.arange(0, self.n_steps, 1), fontsize=24.0) + + for idx, dim in zip(range(len(dimensions)), dimensions): + function_info = self.instance[dim] + title = function_info[1] + " - Dimension " + str(dim) + axes[idx].tick_params(axis="both", which="major", labelsize=24) + axes[idx].set_yticks((np.arange(-1, 1.1, 2 / self.action_vals[dim]))) + axes[idx].set_title(title, size=32) + axes[idx].plot(coordinates[dim], label="Function", marker="o", linewidth=3)[ + 0 + ].axes + axes[idx].xaxis.grid(False) + axes[idx].vlines(x=[3.5, 7.5], ymin=-1, ymax=1, colors="white", ls="--") + """ + axes[idx].legend( + loc="lower right", + framealpha=1, + shadow=True, + borderpad=1, + frameon=True, + ncol=1, + edgecolor="0.2", + ) + """ + + fig_title = f"GeoBench-Dimensions{len(dimensions)}" + fig.savefig(os.path.join(absolute_path, fig_title + ".jpg")) + + def render_3d_dimensions(self, dimensions: List, absolute_path: str): + """ + Plot 2 Dimensions in 3D space + + Parameters + ---------- + dimensions : List + List of dimensions that get plotted. Max 2 + """ + assert len(dimensions) == 2 + print(mplot3d) + + coordinates = self.functions.get_coordinates() + + fig = plt.figure(figsize=(10, 10)) + ax = plt.axes(projection="3d") + + x = list(range(self.n_steps)) + z = coordinates[dimensions[0]][x] + y = coordinates[dimensions[1]][x] + + ax.set_title("3D line plot") + + ax.plot3D(x, y, z, "blue") + ax.view_init() + fig.savefig(os.path.join(absolute_path, "3D.jpg")) + + ax.set_yticklabels([]) + ax.set_yticks([]) + ax.view_init(elev=0, azim=-90) + fig.savefig(os.path.join(absolute_path, "3D-90side.jpg")) + + def _pre_reward(self) -> Tuple[np.ndarray, List]: + """ + Prepare actions and coordinates for reward calculation. + + Returns + ------- + Tuple[np.ndarray, List] + [description] + """ + coordinates = self.functions.get_coordinates_at_time_step(self.c_step) + function_names = [function_info[1] for function_info in self.instance] + + # map action values to their interval mean + mapping_list = [self.action_interval_mapping[name] for name in function_names] + action_intervall = [ + mapping_list[count][index] for count, index in enumerate(self.action) + ] + highest_coords = np.ones(self.n_actions) + lowest_actions = np.array([val[0] for val in mapping_list]) + + return coordinates, action_intervall, highest_coords, lowest_actions + + +class Functions: + def __init__( + self, + n_steps: int, + n_actions: int, + n_instances: int, + correlation: bool, + correlation_table: np.ndarray, + correlation_depth: int, + derivative_interval: int, + ) -> None: + self.instance = None + self.instance_idx = None + + self.coord_array = np.zeros((n_actions, n_steps)) + self.calculated_instance = None + self.norm_calculated = False + self.norm_values = np.ones((n_instances, n_actions)) + + self.correlation = correlation + self.correlation_table = correlation_table + self.correlation_changes = np.zeros(n_actions) + self.correlation_depth = correlation_depth + + self.n_steps = n_steps + self.n_actions = n_actions + self.derivative_interval = derivative_interval + + def set_instance(self, instance: List, instance_index): + """update instance""" + self.instance = instance + self.instance_idx = instance_index + + def get_coordinates(self, instance: List = None) -> List[np.array]: + """ + Calculates coordinates for instance over all time_steps. + The values will change if correlation is applied and not optimal actions are taken. + + Parameters + ---------- + instance : List, optional + Instance that holds information about functions, by default None + + Returns + ------- + List[np.array] + Index of List refers to time step + """ + if not instance: + instance = self.instance + assert instance + + if self.instance_idx == self.calculated_instance: + optimal_coords = self.coord_array + else: + optimal_coords = np.zeros((self.n_actions, self.n_steps)) + for time_step in range(self.n_steps): + optimal_coords[:, time_step] = self.get_coordinates_at_time_step( + time_step + 1 + ) + + if self.norm_calculated: + self.coord_array = optimal_coords + self.calculated_instance = self.instance_idx + + return optimal_coords + + def get_coordinates_at_time_step(self, time_step: int) -> np.array: + """ + Calculate coordiantes at time_step. + Apply correlation. + + Parameters + ---------- + instance : List + Instance that holds information about functions + time_step : int + Time step of functions + + Returns + ------- + np.array + array of function values at timestep + """ + if self.instance_idx == self.calculated_instance: + value_array = self.coord_array[:, time_step - 1] + else: + value_array = np.zeros(self.n_actions) + for index, function_info in enumerate(self.instance): + value_array[index] = self._calculate_function_value( + time_step, function_info, index + ) + + if self.correlation and time_step > 1 and self.norm_calculated: + value_array = self._add_correlation(value_array, time_step) + + return value_array + + def calculate_derivative(self, trajectory: List, c_step: int) -> np.array: + """ + Calculate derivatives of each dimension, based on trajectories. + + Parameters + ---------- + trajectory: List + List of actions or coordinates already taken + c_step: int + current timestep + + Returns + ------- + np.array + derivatives for each dimension + """ + if c_step > 1: + upper_bound = c_step + 1 + lower_bound = max(upper_bound - self.derivative_interval, 1) + + derrivative = np.zeros(self.n_actions) + for step in range(lower_bound, upper_bound): + der = np.subtract( + np.array(trajectory[step], dtype=np.float), + np.array(trajectory[step - 1], dtype=np.float), + ) + derrivative = np.add(derrivative, der) + + derrivative /= upper_bound - lower_bound + + elif c_step == 1: + derrivative = np.subtract( + np.array(trajectory[c_step], dtype=np.float), + np.array(trajectory[c_step - 1], dtype=np.float), + ) + + else: + derrivative = np.zeros(self.n_actions) + + return derrivative + + def calculate_norm_values(self, instance_set: Dict): + """ + Norm Functions to Intervall between -1 and 1 + """ + for key, instance in instance_set.items(): + self.set_instance(instance, key) + instance_values = self.get_coordinates() + + for dim, function_values in enumerate(instance_values): + + if abs(min(function_values)) > max(function_values): + norm_factor = abs(min(function_values)) + else: + norm_factor = max(function_values) + + self.norm_values[key][dim] = norm_factor + + self.norm_calculated = True + + def _calculate_function_value( + self, time_step: int, function_infos: List, func_idx: int + ) -> float: + """ + Call different functions with their speicifc parameters and norm them. + + Parameters + ---------- + function_infos : List + Consists of function name and the coefficients + time_step: int + time step for each function + calculate_norm : bool, optional + True if norm gets calculated, by default False + + Returns + ------- + float + coordinate in dimension of function + """ + assert self.instance_idx == function_infos[0] + + function_name = function_infos[1] + coefficients = function_infos[2:] + if self.norm_calculated: + norm_value = self.norm_values[self.instance_idx, func_idx] + if norm_value == 0: + norm_value = 1 + else: + norm_value = 1 + + function_value = 0 + + if "sigmoid" == function_name: + function_value = self._sigmoid(time_step, coefficients[0], coefficients[1]) + + elif "linear" == function_name: + function_value = self._linear(time_step, coefficients[0], coefficients[1]) + + elif "constant" == function_name: + function_value = self._constant(coefficients[0]) + + elif "logarithmic" == function_name: + function_value = self._logarithmic(time_step, coefficients[0]) + + elif "cubic" in function_name: + function_value = self._cubic( + time_step, coefficients[0], coefficients[1], coefficients[2] + ) + + elif "parabel" in function_name: + function_value = self._parabel( + time_step, coefficients[0], coefficients[1], coefficients[2] + ) + + elif "sinus" in function_name: + function_value = self._sinus(time_step, coefficients[0]) + + function_value = np.round(function_value / norm_value, 5) + if self.norm_calculated: + function_value = max(min(function_value, 1), -1) + + return function_value + + def _add_correlation(self, value_array: np.ndarray, time_step: int): + """ + Adds correlation between dimensions but clips at -1 and 1. + Correlation table holds numbers between -1 and 1. + e.g. correlation_table[0][2] = 0.5 if dimension 1 changes dimension 3 changes about 50% of dimension one + + Parameters + ---------- + correlation_table : np.array + table that holds all values of correlation between dimensions [n,n] + """ + prev_values = self.coord_array[:, time_step - 1] + diff_values = value_array - prev_values + + new_values = [] + for idx, diff in enumerate(diff_values): + self._apply_correlation_update(idx, diff, self.correlation_depth) + + new_values = self.correlation_changes + value_array + clipped_values = np.clip(new_values, a_min=-1, a_max=1) + self.correlation_changes = np.zeros(self.n_actions) + + return clipped_values + + def _apply_correlation_update(self, idx: int, diff: float, depth): + """ + Recursive function for correlation updates + Call function recursively till depth is 0 or diff is too small. + """ + if not depth or diff < 0.001: + return + + for coeff_idx, corr_coeff in enumerate(self.correlation_table[:][idx]): + change = corr_coeff * diff + self.correlation_changes[coeff_idx] += change + self._apply_correlation_update(coeff_idx, change, depth - 1) + + def _sigmoid(self, t: float, scaling: float, inflection: float): + """Simple sigmoid function""" + return 1 / (1 + np.exp(-scaling * (t - inflection))) + + def _linear(self, t: float, a: float, b: float): + """Linear function""" + return a * t + b + + def _parabel(self, t: float, sig: int, x_int: int, y_int: int): + """Parabel function""" + return sig * (t - x_int) ** 2 + y_int + + def _cubic(self, t: float, sig: int, x_int: int, y_int: int): + """cubic function""" + return sig * (t - x_int) ** 3 + y_int + + def _logarithmic(self, t: float, a: float): + """Logarithmic function""" + if t != 0: + return a * np.log(t) + else: + return 1000 + + def _constant(self, c: float): + """Constant function""" + return c + + def _sinus(self, t: float, scale: float): + """Sinus function""" + return np.sin(scale * t) diff --git a/build/lib/dacbench/envs/luby.py b/build/lib/dacbench/envs/luby.py new file mode 100644 index 000000000..aebe00a97 --- /dev/null +++ b/build/lib/dacbench/envs/luby.py @@ -0,0 +1,180 @@ +""" +Luby environment from +"Dynamic Algorithm Configuration:Foundation of a New Meta-Algorithmic Framework" +by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. +Original environment authors: André Biedenkapp, H. Furkan Bozkurt +""" + +from typing import List +import numpy as np + +from dacbench import AbstractEnv + + +# Instance IDEA 1: shift luby seq -> feat is sum of skipped action values +# Instance IDEA 2: "Wiggle" luby i.e. luby(t + N(0, 0.1)) -> feat is sampled value + + +class LubyEnv(AbstractEnv): + """ + Environment to learn Luby Sequence + """ + + def __init__(self, config) -> None: + """ + Initialize Luby Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super().__init__(config) + + self._hist_len = config["hist_length"] + self._ms = self.n_steps + self._mi = config["min_steps"] + self._state = np.array([-1 for _ in range(self._hist_len + 1)]) + self._r = 0 + self._genny = luby_gen(1) + self._next_goal = next(self._genny) + # Generate luby sequence up to 2*max_steps + 2 as mode 1 could potentially shift up to max_steps + self._seq = np.log2( + [next(luby_gen(i)) for i in range(1, 2 * config["cutoff"] + 2)] + ) + self._jenny_i = 1 + self._start_dist = None + self._sticky_dis = None + self._sticky_shif = 0 + self._start_shift = 0 + self.__lower, self.__upper = 0, 0 + self.__error = 0 + self.done = None + self.action = None + + if "reward_function" in config.keys(): + self.get_reward = config["reward_function"] + else: + self.get_reward = self.get_default_reward + + if "state_method" in config.keys(): + self.get_state = config["state_method"] + else: + self.get_state = self.get_default_state + + def step(self, action: int): + """ + Execute environment step + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info + """ + self.done = super(LubyEnv, self).step_() + self.prev_state = self._state.copy() + self.action = action + reward = self.get_reward(self) + if ( + self.__error < self.__lower + ): # needed to avoid too long sequences of sticky actions + self.__error += np.abs(self.__lower) + elif self.__error > self.__upper: + self.__error -= np.abs(self.__upper) + self._jenny_i += 1 + self.__error += self._sticky_shif + + # next target in sequence at step luby_t is determined by the current time step (jenny_i), the start_shift + # value and the sticky error. Additive sticky error leads to sometimes rounding to the next time_step and + # thereby repeated actions. With check against lower/upper we reset the sequence to the correct timestep in + # the t+1 timestep. + luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) + self._next_goal = self._seq[luby_t - 1] + return self.get_state(self), reward, False, self.done, {} + + def reset(self) -> List[int]: + """ + Resets env + + Returns + ------- + numpy.array + Environment state + """ + super(LubyEnv, self).reset_() + self._start_shift = self.instance[0] + self._sticky_shif = self.instance[1] + self._r = 0 + self.n_steps = self._mi + + self.__error = 0 + self._sticky_shif + self._jenny_i = 1 + luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) + self._next_goal = self._seq[luby_t - 1] + self.done = False + return self.get_state(self), {} + + def get_default_reward(self, _): + if self.action == self._next_goal: + self._r = 0 # we don't want to allow for exploiting large rewards by tending towards long sequences + else: # mean and var chosen s.t. ~1/4 of rewards are positive + self._r = -1 + self._r = max(self.reward_range[0], min(self.reward_range[1], self._r)) + return self._r + + def get_default_state(self, _): + if self.c_step == 0: + self._state = [-1 for _ in range(self._hist_len + 1)] + else: + if self.c_step - 1 < self._hist_len: + self._state[(self.c_step - 1)] = self.action + else: + self._state[:-2] = self._state[1:-1] + self._state[-2] = self.action + self._state[-1] = self.c_step - 1 + next_state = np.array(self._state if not self.done else self.prev_state) + return next_state + + def close(self) -> bool: + """ + Close Env + + Returns + ------- + bool + Closing confirmation + """ + return True + + # TODO: this should render! + + def render(self, mode: str = "human") -> None: + """ + Render env in human mode + + Parameters + ---------- + mode : str + Execution mode + """ + if mode != "human": + raise NotImplementedError + + pass + + +def luby_gen(i): + """ Generator for the Luby Sequence """ + for k in range(1, 33): + if i == ((1 << k) - 1): + yield 1 << (k - 1) + + for k in range(1, 9999): + if 1 << (k - 1) <= i < (1 << k) - 1: + for x in luby_gen(i - (1 << (k - 1)) + 1): + yield x diff --git a/build/lib/dacbench/envs/modcma.py b/build/lib/dacbench/envs/modcma.py new file mode 100644 index 000000000..2760b1dc1 --- /dev/null +++ b/build/lib/dacbench/envs/modcma.py @@ -0,0 +1,60 @@ +import numpy as np +from modcma import ModularCMAES, Parameters +from IOHexperimenter import IOH_function + +from dacbench import AbstractEnv + + +class ModCMAEnv(AbstractEnv): + def __init__(self, config): + super().__init__(config) + + self.es = None + self.budget = config.budget + self.total_budget = self.budget + + self.get_reward = config.get("reward_function", self.get_default_reward) + self.get_state = config.get("state_method", self.get_default_state) + + def reset(self): + super().reset_() + self.dim, self.fid, self.iid, self.representation = self.instance + self.representation = np.array(self.representation) + self.objective = IOH_function( + self.fid, self.dim, self.iid, target_precision=1e-8 + ) + self.es = ModularCMAES( + self.objective, + parameters=Parameters.from_config_array( + self.dim, np.array(self.representation).astype(int) + ), + ) + return self.get_state(self), {} + + def step(self, action): + truncated = super().step_() + new_parameters = Parameters.from_config_array(self.dim, action) + self.es.parameters.update( + {m: getattr(new_parameters, m) for m in Parameters.__modules__} + ) + terminated = not self.es.step() + return self.get_state(self), self.get_reward(self), terminated, truncated, {} + + def close(self): + return True + + def get_default_reward(self, *_): + return max( + self.reward_range[0], min(self.reward_range[1], -self.es.parameters.fopt) + ) + + def get_default_state(self, *_): + return np.array( + [ + self.es.parameters.lambda_, + self.es.parameters.sigma, + self.budget - self.es.parameters.used_budget, + self.fid, + self.iid, + ] + ) diff --git a/dacbench/envs/modea.py b/build/lib/dacbench/envs/modea.py similarity index 97% rename from dacbench/envs/modea.py rename to build/lib/dacbench/envs/modea.py index 574a3969f..28499086b 100644 --- a/dacbench/envs/modea.py +++ b/build/lib/dacbench/envs/modea.py @@ -62,10 +62,11 @@ def reset(self): self.budgets = {"small": None, "large": None} self.regime = "first" self.update_parameters() - return self.get_state(self) + return self.get_state(self), {} def step(self, action): - done = super(ModeaEnv, self).step_() + truncated = super(ModeaEnv, self).step_() + terminated = False self.representation = self.ensureFullLengthRepresentation(action) opts = getOpts(self.representation[: len(options)]) self.switchConfiguration(opts) @@ -77,13 +78,13 @@ def step(self, action): self.es.budget <= self.es.used_budget or self.es.parameters.checkLocalRestartConditions(self.es.used_budget) ): - done = done or self.restart() + terminated = self.restart() if self.es.total_used_budget < self.es.total_budget: self.update_parameters() else: - done = True + terminated = True - return self.get_state(self), self.get_reward(self), done, {} + return self.get_state(self), self.get_reward(self), terminated, truncated, {} def update_parameters(self): # Every local restart needs its own parameters, so parameter update/mutation must also be linked every time diff --git a/build/lib/dacbench/envs/policies/__init__.py b/build/lib/dacbench/envs/policies/__init__.py new file mode 100644 index 000000000..6a1f123cf --- /dev/null +++ b/build/lib/dacbench/envs/policies/__init__.py @@ -0,0 +1,14 @@ +from dacbench.envs.policies.csa_cma import csa +from dacbench.envs.policies.optimal_fd import get_optimum as optimal_fd +from dacbench.envs.policies.optimal_luby import get_optimum as optimal_luby +from dacbench.envs.policies.optimal_sigmoid import get_optimum as optimal_sigmoid + +OPTIMAL_POLICIES = { + "LubyBenchmark": optimal_luby, + "SigmoidBenchmark": optimal_sigmoid, + "FastDownwardBenchmark": optimal_fd, +} + +NON_OPTIMAL_POLICIES = {"CMAESBenchmark": csa} + +ALL_POLICIES = {**OPTIMAL_POLICIES, **NON_OPTIMAL_POLICIES} diff --git a/build/lib/dacbench/envs/policies/csa_cma.py b/build/lib/dacbench/envs/policies/csa_cma.py new file mode 100644 index 000000000..1b7c0d631 --- /dev/null +++ b/build/lib/dacbench/envs/policies/csa_cma.py @@ -0,0 +1,7 @@ +def csa(env, state): + u = env.es.sigma + hsig = env.es.adapt_sigma.hsig(env.es) + env.es.hsig = hsig + delta = env.es.adapt_sigma.update2(env.es, function_values=env.cur_obj_val) + u *= delta + return u diff --git a/build/lib/dacbench/envs/policies/optimal_fd.py b/build/lib/dacbench/envs/policies/optimal_fd.py new file mode 100644 index 000000000..47c0e7daf --- /dev/null +++ b/build/lib/dacbench/envs/policies/optimal_fd.py @@ -0,0 +1,8 @@ +import json + + +def get_optimum(env, state): + instance = env.get_instance()[:-12] + "optimal.json" + with open(instance, "r+") as fp: + optimal = json.load(fp) + return optimal[env.c_step] diff --git a/build/lib/dacbench/envs/policies/optimal_luby.py b/build/lib/dacbench/envs/policies/optimal_luby.py new file mode 100644 index 000000000..5e602b8d4 --- /dev/null +++ b/build/lib/dacbench/envs/policies/optimal_luby.py @@ -0,0 +1,14 @@ +def luby_gen(i): + """ Generator for the Luby Sequence """ + for k in range(1, 33): + if i == ((1 << k) - 1): + yield 1 << (k - 1) + + for k in range(1, 9999): + if 1 << (k - 1) <= i < (1 << k) - 1: + for x in luby_gen(i - (1 << (k - 1)) + 1): + yield x + + +def get_optimum(env, state): + return env._next_goal diff --git a/build/lib/dacbench/envs/policies/optimal_sigmoid.py b/build/lib/dacbench/envs/policies/optimal_sigmoid.py new file mode 100644 index 000000000..d7d6e8859 --- /dev/null +++ b/build/lib/dacbench/envs/policies/optimal_sigmoid.py @@ -0,0 +1,25 @@ +import numpy as np + + +def sig(x, scaling, inflection): + """ Simple sigmoid function """ + return 1 / (1 + np.exp(-scaling * (x - inflection))) + + +def get_optimum(env, state): + sigmoids = [ + np.abs(sig(env.c_step, slope, shift)) + for slope, shift in zip(env.shifts, env.slopes) + ] + action = [] + for i in range(len(env.action_vals)): + best_action = None + dist = 100 + for a in range(env.action_vals[i] + 1): + if np.abs(sigmoids[i] - a / (env.action_vals[i] - 1)) < dist: + dist = np.abs(sigmoids[i] - a / (env.action_vals[i])) + best_action = a + action.append(best_action) + for k in env.action_mapper.keys(): + if env.action_mapper[k] == tuple(action): + return k diff --git a/build/lib/dacbench/envs/policies/sgd_ca.py b/build/lib/dacbench/envs/policies/sgd_ca.py new file mode 100644 index 000000000..03b256a8b --- /dev/null +++ b/build/lib/dacbench/envs/policies/sgd_ca.py @@ -0,0 +1,33 @@ +import math +from dacbench.abstract_agent import AbstractDACBenchAgent + + +class CosineAnnealingAgent(AbstractDACBenchAgent): + def __init__(self, env, base_lr=0.1, t_max=1000, eta_min=0): + self.eta_min = eta_min + self.t_max = t_max + self.base_lr = base_lr + self.current_lr = base_lr + self.last_epoch = -1 + super(CosineAnnealingAgent, self).__init__(env) + + def act(self, state, reward): + self.last_epoch += 1 + if self.last_epoch == 0: + return self.base_lr + elif (self.last_epoch - 1 - self.t_max) % (2 * self.t_max) == 0: + return ( + self.current_lr + + (self.base_lr - self.eta_min) + * (1 - math.cos(math.pi / self.t_max)) + / 2 + ) + return (1 + math.cos(math.pi * self.last_epoch / self.t_max)) / ( + 1 + math.cos(math.pi * (self.last_epoch - 1) / self.t_max) + ) * (self.current_lr - self.eta_min) + self.eta_min + + def train(self, state, reward): + pass + + def end_episode(self, state, reward): + pass diff --git a/build/lib/dacbench/envs/sgd.py b/build/lib/dacbench/envs/sgd.py new file mode 100644 index 000000000..38ab9bd8d --- /dev/null +++ b/build/lib/dacbench/envs/sgd.py @@ -0,0 +1,891 @@ +import math +import numbers +import warnings +import json +from functools import reduce +from enum import IntEnum, auto + +import numpy as np +import torch +from backpack import backpack, extend +from backpack.extensions import BatchGrad +from numpy import float32 +from torchvision import datasets, transforms +from dacbench import AbstractEnv +import random + +warnings.filterwarnings("ignore") + + +def reward_range(frange): + def wrapper(f): + f.frange = frange + return f + return wrapper + + +class Reward(IntEnum): + TrainingLoss = auto() + ValidationLoss = auto() + LogTrainingLoss = auto() + LogValidationLoss = auto() + DiffTraining = auto() + DiffValidation = auto() + LogDiffTraining = auto() + LogDiffValidation = auto() + FullTraining = auto() + + def __call__(self, f): + if hasattr(self, 'func'): + raise ValueError('Can not assign the same reward to a different function!') + self.func = f + return f + + +class SGDEnv(AbstractEnv): + """ + Environment to control the learning rate of adam + """ + + def __init__(self, config): + """ + Initialize SGD Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super(SGDEnv, self).__init__(config) + + self.batch_size = config.training_batch_size + self.validation_batch_size = config.validation_batch_size + self.no_cuda = config.no_cuda + self.current_batch_size = config.training_batch_size + self.on_features = config.features + self.cd_paper_reconstruction = config.cd_paper_reconstruction + self.cd_bias_correction = config.cd_bias_correction + self.crashed = False + self.terminate_on_crash = config.terminate_on_crash + self.crash_penalty = config.crash_penalty + + if isinstance(config.reward_type, Reward): + self.reward_type = config.reward_type + elif isinstance(config.reward_type, str): + try: + self.reward_type = getattr(Reward, config.reward_type) + except AttributeError: + raise ValueError(f'{config.reward_type} is not a valid reward type!') + else: + raise ValueError(f'Type {type(config.reward_type)} is not valid!') + + self.use_cuda = not self.no_cuda and torch.cuda.is_available() + self.device = torch.device("cuda" if self.use_cuda else "cpu") + + self.training_validation_ratio = config.train_validation_ratio + self.dataloader_shuffle = config.dataloader_shuffle + # self.test_dataset = None + self.train_dataset = None + self.validation_dataset = None + self.train_loader = None + # self.test_loader = None + self.validation_loader = None + self.train_loader_it = None + self.validation_loader_it = None + + self.train_batch_index = 0 + self.epoch_index = 0 + + self.current_training_loss = None + self.loss_batch = None + self.prev_training_loss = None + self._current_validation_loss = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self._current_validation_loss.calculated = False + self.prev_validation_loss = torch.zeros( + 1, device=self.device, requires_grad=False + ) + + self.model = None + self.val_model = None + # TODO: + """ + TODO: Samuel Mueller (PhD student in our group) also uses backpack and has ran into a similar memory leak. + He solved it calling this custom made RECURSIVE memory_cleanup function: + # from backpack import memory_cleanup + # def recursive_backpack_memory_cleanup(module: torch.nn.Module): + # memory_cleanup(module) + # for m in module.modules(): + # memory_cleanup(m) + (calling this after computing the training loss/gradients and after validation loss should suffice) + """ + self.parameter_count = 0 + self.layer_sizes = [] + + self.loss_function = config.loss_function(**config.loss_function_kwargs) + self.loss_function = extend(self.loss_function) + self.val_loss_function = config.loss_function(**config.val_loss_function_kwargs) + + self.initial_lr = config.lr * torch.ones( + 1, device=self.device, requires_grad=False + ) + self.current_lr = config.lr * torch.ones( + 1, device=self.device, requires_grad=False + ) + + self.optimizer_name = config.optimizer + + self.beta1 = config.beta1 + self.beta2 = config.beta2 + self.epsilon = config.epsilon + # RMSprop parameters + self.beta2 = config.beta2 + self.m = 0 + self.v = 0 + # Momentum parameters + self.sgd_momentum_v = 0 + self.sgd_rho = 0.9 + + self.clip_grad = config.clip_grad + + self.t = 0 + self.step_count = torch.zeros(1, device=self.device, requires_grad=False) + + self.prev_direction = None + self.current_direction = None + + self.predictiveChangeVarDiscountedAverage = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.predictiveChangeVarUncertainty = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.lossVarDiscountedAverage = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.lossVarUncertainty = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.discount_factor = config.discount_factor + self.firstOrderMomentum = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.secondOrderMomentum = torch.zeros( + 1, device=self.device, requires_grad=False + ) + + if self.optimizer_name=="adam": + self.get_optimizer_direction = self.get_adam_direction + elif self.optimizer_name=="rmsprop": + self.get_optimizer_direction = self.get_rmsprop_direction + elif self.optimizer_name=="momentum": + self.get_optimizer_direction = self.get_momentum_direction + else: + raise NotImplementedError + + if "reward_function" in config.keys(): + self._get_reward = config["reward_function"] + else: + self._get_reward = self.reward_type.func + + if "state_method" in config.keys(): + self.get_state = config["state_method"] + else: + self.get_state = self.get_default_state + + self.reward_range = self.reward_type.func.frange + + def get_reward(self): + return self._get_reward(self) + + @reward_range([-(10**9), 0]) + @Reward.TrainingLoss + def get_training_reward(self): + return -self.current_training_loss.item() + + @reward_range([-(10**9), 0]) + @Reward.ValidationLoss + def get_validation_reward(self): + return -self.current_validation_loss.item() + + @reward_range([-(10**9), (10**9)]) + @Reward.LogTrainingLoss + def get_log_training_reward(self): + return -torch.log(self.current_training_loss).item() + + @reward_range([-(10**9), (10**9)]) + @Reward.LogValidationLoss + def get_log_validation_reward(self): + return -torch.log(self.current_validation_loss).item() + + @reward_range([-(10**9), (10**9)]) + @Reward.LogDiffTraining + def get_log_diff_training_reward(self): + return -(torch.log(self.current_training_loss) - torch.log(self.prev_training_loss)).item() + + @reward_range([-(10**9), (10**9)]) + @Reward.LogDiffValidation + def get_log_diff_validation_reward(self): + return -(torch.log(self.current_validation_loss) - torch.log(self.prev_validation_loss)).item() + + @reward_range([-(10**9), (10**9)]) + @Reward.DiffTraining + def get_diff_training_reward(self): + return (self.current_training_loss - self.prev_training_loss).item() + + @reward_range([-(10**9), (10**9)]) + @Reward.DiffValidation + def get_diff_validation_reward(self): + return (self.current_validation_loss - self.prev_validation_loss).item() + + @reward_range([-(10**9), 0]) + @Reward.FullTraining + def get_full_training_reward(self): + return -self._get_full_training_loss(loader=self.train_loader).item() + + def get_full_training_loss(self): + return -self.get_full_training_reward() + + @property + def crash(self): + self.crashed = True + if self.c_step >= self.n_steps: + done = True + else: + done = self.terminate_on_crash + return self.get_state(self), self.crash_penalty, done, {} + + def seed(self, seed=None, seed_action_space=False): + """ + Set rng seed + + Parameters + ---------- + seed: + seed for rng + seed_action_space: bool, default False + if to seed the action space as well + """ + (seed,) = super().seed(seed, seed_action_space) + if seed is not None: + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + torch.backends.cudnn.benchmark = False + torch.backends.cudnn.deterministic = True + return [seed] + + def step(self, action): + """ + Execute environment step + + Parameters + ---------- + action : list + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info + """ + truncated = super(SGDEnv, self).step_() + + self.step_count += 1 + index = 0 + + if not isinstance(action, int) and not isinstance(action, float): + action = action.item() + if not isinstance(action, numbers.Number): + action = action[0] + + if np.isnan(action): + return self.crash + + new_lr = torch.Tensor([action]).to(self.device) + self.current_lr = new_lr + + direction = self.get_optimizer_direction() + if np.isnan(direction).any(): + return self.crash + + self.current_direction = direction + + delta_w = torch.mul(new_lr, direction) + + for i, p in enumerate(self.model.parameters()): + layer_size = self.layer_sizes[i] + p.data = p.data - delta_w[index : index + layer_size].reshape( + shape=p.data.shape + ) + index += layer_size + + self.model.zero_grad() + + self.prev_training_loss = self.current_training_loss + if self._current_validation_loss.calculated: + self.prev_validation_loss = self.current_validation_loss + + self.train_network() + reward = self.get_reward() + + if np.isnan(reward): + return self.crash + + state = self.get_state(self) + for value in state.values(): + if np.isnan(value): + return self.crash + return state, reward, False, truncated, {} + + def _architecture_constructor(self, arch_str): + layer_specs = [] + layer_strs = arch_str.split("-") + for layer_str in layer_strs: + idx = layer_str.find("(") + if idx == -1: + nn_module_name = layer_str + vargs = [] + else: + nn_module_name = layer_str[:idx] + vargs_json_str = '{"tmp": [' + layer_str[idx + 1 : -1] + "]}" + vargs = json.loads(vargs_json_str)["tmp"] + layer_specs.append((getattr(torch.nn, nn_module_name), vargs)) + + def model_constructor(): + layers = [cls(*vargs) for cls, vargs in layer_specs] + return torch.nn.Sequential(*layers) + + return model_constructor + + def reset(self): + """ + Reset environment + + Returns + ------- + np.array + Environment state + """ + super(SGDEnv, self).reset_() + + dataset = self.instance[0] + instance_seed = self.instance[1] + construct_model = self._architecture_constructor(self.instance[2]) + self.n_steps = self.instance[3] + dataset_size = self.instance[4] + + self.crashed = False + + self.seed(instance_seed) + + self.model = construct_model().to(self.device) + self.val_model = construct_model().to(self.device) + + def init_weights(m): + if type(m) == torch.nn.Linear or type(m) == torch.nn.Conv2d: + torch.nn.init.xavier_normal(m.weight) + m.bias.data.fill_(0.0) + + if self.cd_paper_reconstruction: + self.model.apply(init_weights) + + train_dataloader_args = {"batch_size": self.batch_size, "drop_last": True, + 'shuffle': self.dataloader_shuffle} + validation_dataloader_args = {"batch_size": self.validation_batch_size, + "drop_last": True, 'shuffle': False} # SA: shuffling empty data loader causes exception + if self.use_cuda: + param = {"num_workers": 1, "pin_memory": True} + train_dataloader_args.update(param) + validation_dataloader_args.update(param) + + if dataset == "MNIST": + transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,)) + ]) + + train_dataset = datasets.MNIST( + "../data", train=True, download=True, transform=transform + ) + # self.test_dataset = datasets.MNIST('../data', train=False, transform=transform) + elif dataset == "CIFAR": + transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), + ]) + + train_dataset = datasets.CIFAR10( + "../data", train=True, download=True, transform=transform + ) + # self.test_dataset = datasets.MNIST('../data', train=False, transform=transform) + else: + raise NotImplementedError + + if dataset_size is not None: + train_dataset = torch.utils.data.Subset( + train_dataset, range(0, dataset_size) + ) + + training_dataset_limit = math.floor( + len(train_dataset) * self.training_validation_ratio + ) + validation_dataset_limit = len(train_dataset) + + self.train_dataset = torch.utils.data.Subset( + train_dataset, range(0, training_dataset_limit - 1) + ) + self.validation_dataset = torch.utils.data.Subset( + train_dataset, range(training_dataset_limit, validation_dataset_limit) + ) + + self.train_loader = torch.utils.data.DataLoader( + self.train_dataset, **train_dataloader_args + ) + # self.test_loader = torch.utils.data.DataLoader(self.test_dataset, **train_dataloader_args) + self.validation_loader = torch.utils.data.DataLoader( + self.validation_dataset, **validation_dataloader_args + ) + + self.train_batch_index = 0 + self.epoch_index = 0 + self.train_loader_it = iter(self.train_loader) + self.validation_loader_it = iter(self.validation_loader) + + self.parameter_count = 0 + self.layer_sizes = [] + for p in self.model.parameters(): + layer_size = reduce(lambda x, y: x * y, p.shape) + self.layer_sizes.append(layer_size) + self.parameter_count += layer_size + + self.model = extend(self.model) + + self.model.zero_grad() + self.model.train() + self.val_model.eval() + + self.current_training_loss = None + self.loss_batch = None + + # Momentum parameters + self.m = 0 + self.v = 0 + self.sgd_momentum_v = 0 + + self.t = 0 + + self.step_count = torch.zeros(1, device=self.device, requires_grad=False) + + self.current_lr = self.initial_lr + self.prev_direction = torch.zeros( + (self.parameter_count,), device=self.device, requires_grad=False + ) + self.current_direction = torch.zeros( + (self.parameter_count,), device=self.device, requires_grad=False + ) + + self.predictiveChangeVarDiscountedAverage = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.predictiveChangeVarUncertainty = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.lossVarDiscountedAverage = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.lossVarUncertainty = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.firstOrderMomentum = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.secondOrderMomentum = torch.zeros( + 1, device=self.device, requires_grad=False + ) + + self._current_validation_loss = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self._current_validation_loss.calculated = False + self.prev_validation_loss = torch.zeros( + 1, device=self.device, requires_grad=False + ) + self.train_network() + + return self.get_state(self), {} + + def set_writer(self, writer): + self.writer = writer + + def close(self): + """ + No additional cleanup necessary + + Returns + ------- + bool + Cleanup flag + """ + return True + + def render(self, mode: str = "human"): + """ + Render env in human mode + + Parameters + ---------- + mode : str + Execution mode + """ + if mode != "human": + raise NotImplementedError + + pass + + def get_default_state(self, _): + """ + Gather state description + + Returns + ------- + dict + Environment state + + """ + self.gradients = self._get_gradients() + self.gradients = self.gradients.clip(*self.clip_grad) + + self.firstOrderMomentum, self.secondOrderMomentum, self.sgdMomentum = self._get_momentum(self.gradients) + + if 'predictiveChangeVarDiscountedAverage' in self.on_features or 'predictiveChangeVarUncertainty' in self.on_features: + predictiveChangeVarDiscountedAverage, predictiveChangeVarUncertainty = \ + self._get_predictive_change_features(self.current_lr) + + if 'lossVarDiscountedAverage' in self.on_features or 'lossVarUncertainty' in self.on_features: + lossVarDiscountedAverage, lossVarUncertainty = self._get_loss_features() + + if 'alignment' in self.on_features: + alignment = self._get_alignment() + + state = {} + + if 'predictiveChangeVarDiscountedAverage' in self.on_features: + state["predictiveChangeVarDiscountedAverage"] = predictiveChangeVarDiscountedAverage.item() + if 'predictiveChangeVarUncertainty' in self.on_features: + state["predictiveChangeVarUncertainty"] = predictiveChangeVarUncertainty.item() + if 'lossVarDiscountedAverage' in self.on_features: + state["lossVarDiscountedAverage"] = lossVarDiscountedAverage.item() + if 'lossVarUncertainty' in self.on_features: + state["lossVarUncertainty"] = lossVarUncertainty.item() + if 'currentLR' in self.on_features: + state["currentLR"] = self.current_lr.item() + if 'trainingLoss' in self.on_features: + if self.crashed: + state["trainingLoss"] = 0.0 + else: + state["trainingLoss"] = self.current_training_loss.item() + if 'validationLoss' in self.on_features: + if self.crashed: + state["validationLoss"] = 0.0 + else: + state["validationLoss"] = self.current_validation_loss.item() + if 'step' in self.on_features: + state["step"] = self.step_count.item() + if 'alignment' in self.on_features: + state["alignment"] = alignment.item() + if 'crashed' in self.on_features: + state["crashed"] = self.crashed + + return state + + def _train_batch_(self): + (data, target) = self.train_loader_it.next() + data, target = data.to(self.device), target.to(self.device) + self.current_batch_size = data.size()[0] + output = self.model(data) + loss = self.loss_function(output, target) + + with backpack(BatchGrad()): + loss.mean().backward() + + loss_value = loss.mean() + + self.loss_batch = loss + self.current_training_loss = torch.unsqueeze(loss_value.detach(), dim=0) + self.train_batch_index += 1 + self._current_validation_loss.calculated = False + + def train_network(self): + try: + self._train_batch_() + except StopIteration: + self.train_batch_index = 0 + self.epoch_index += 1 + self.train_loader_it = iter(self.train_loader) + self._train_batch_() + + def _get_full_training_loss(self, loader): + for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): + target_param.data.copy_(param.data) + loss = torch.zeros(1, device=self.device, requires_grad=False) + with torch.no_grad(): + for data, target in loader: + data, target = data.to(self.device), target.to(self.device) + output = self.val_model(data) + loss += self.val_loss_function(output, target).sum().detach().detach() + + loss /= len(loader.dataset) + return loss + + @property + def current_validation_loss(self): + if not self._current_validation_loss.calculated: + self._current_validation_loss = self._get_validation_loss() + self._current_validation_loss.calculated = True + return self._current_validation_loss + + def _get_validation_loss_(self): + with torch.no_grad(): + (data, target) = self.validation_loader_it.next() + data, target = data.to(self.device), target.to(self.device) + output = self.val_model(data) + validation_loss = self.val_loss_function(output, target).mean() + validation_loss = torch.unsqueeze(validation_loss.detach(), dim=0) + + return validation_loss + + def _get_validation_loss(self): + for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): + target_param.data.copy_(param.data) + try: + validation_loss = self._get_validation_loss_() + except StopIteration: + self.validation_loader_it = iter(self.validation_loader) + validation_loss = self._get_validation_loss_() + + return validation_loss + + def _get_gradients(self): + gradients = [] + for p in self.model.parameters(): + if p.grad is None: + continue + gradients.append(p.grad.flatten()) + + gradients = torch.cat(gradients, dim=0) + + return gradients + + def _get_momentum(self, gradients): + self.t += 1 + self.m = self.beta1 * self.m + (1 - self.beta1) * gradients + self.v = self.beta2 * self.v + (1 - self.beta2) * torch.square(gradients) + bias_corrected_m = self.m / (1 - self.beta1 ** self.t) + bias_corrected_v = self.v / (1 - self.beta2 ** self.t) + + self.sgd_momentum_v = self.sgd_rho * self.sgd_momentum_v + gradients + + return bias_corrected_m, bias_corrected_v, self.sgd_momentum_v + + def get_adam_direction(self): + return self.firstOrderMomentum / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) + + def get_rmsprop_direction(self): + return self.gradients / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) + + def get_momentum_direction(self): + return self.sgd_momentum_v + + def _get_loss_features(self): + if self.crashed: + return torch.tensor(0.0), torch.tensor(0.0) + bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 + with torch.no_grad(): + loss_var = torch.log(torch.var(self.loss_batch)) + self.lossVarDiscountedAverage = ( + self.discount_factor * self.lossVarDiscountedAverage + + (1 - self.discount_factor) * loss_var + ) + self.lossVarUncertainty = ( + self.discount_factor * self.lossVarUncertainty + + (1 - self.discount_factor) + * (loss_var - self.lossVarDiscountedAverage/bias_correction) ** 2 + ) + + return self.lossVarDiscountedAverage/bias_correction, self.lossVarUncertainty/bias_correction + + def _get_predictive_change_features(self, lr): + if self.crashed: + return torch.tensor(0.0), torch.tensor(0.0) + bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 + batch_gradients = [] + for i, (name, param) in enumerate(self.model.named_parameters()): + grad_batch = param.grad_batch.reshape( + self.current_batch_size, self.layer_sizes[i] + ) + batch_gradients.append(grad_batch) + + batch_gradients = torch.cat(batch_gradients, dim=1) + + update_value = torch.mul(lr, self.get_optimizer_direction()) + + predictive_change = torch.log( + torch.var(-1 * torch.matmul(batch_gradients, update_value)) + ) + + self.predictiveChangeVarDiscountedAverage = ( + self.discount_factor * self.predictiveChangeVarDiscountedAverage + + (1 - self.discount_factor) * predictive_change + ) + self.predictiveChangeVarUncertainty = ( + self.discount_factor * self.predictiveChangeVarUncertainty + + (1 - self.discount_factor) + * (predictive_change - self.predictiveChangeVarDiscountedAverage/bias_correction) ** 2 + ) + + return ( + self.predictiveChangeVarDiscountedAverage/bias_correction, + self.predictiveChangeVarUncertainty/bias_correction, + ) + + def _get_alignment(self): + if self.crashed: + return torch.tensor(0.0) + alignment = torch.mean(torch.sign(torch.mul(self.prev_direction, self.current_direction))) + alignment = torch.unsqueeze(alignment, dim=0) + self.prev_direction = self.current_direction + return alignment + + def generate_instance_file(self, file_name, mode='test', n=100): + header = ['ID', 'dataset', 'architecture', 'seed', 'steps'] + + # dataset name, architecture, dataset size, sample dimension, number of max pool layers, hidden layers, test architecture convolutional layers + architectures = [ + ('MNIST', + 'Conv2d(1, {0}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({0}, {1}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-Flatten-Linear({3}, 10)-LogSoftmax(1)', + 60000, + 28, + 2, + 3, + [20, 50, 500] + ), + ('CIFAR', + 'Conv2d(3, {0}, 3, 1, 1)-MaxPool2d(2, 2)-ReLU-Conv2d({0}, {1}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({2}, {3}, 3, 1, 1)-ReLU-Flatten-Linear({4}, 10)-LogSoftmax(1)', + 60000, + 32, + 3, + 4, + [32, 32, 64, 64] + ) + ] + if mode is 'test': + + seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] + + for i in range(len(architectures)): + + fname = file_name + "_" + architectures[i][0].lower() + ".csv" + + steps = int(1e8) + + conv = architectures[i][6] + hidden_layers = architectures[i][5] + + sample_size = architectures[i][3] + pool_layer_count = architectures[i][4] + linear_layer_size = conv[-1] * pow(sample_size / pow(2, pool_layer_count), 2) + linear_layer_size = int(round(linear_layer_size)) + + dataset = architectures[i][0] + + if hidden_layers == 3: + architecture = architectures[i][1].format(conv[0], conv[1], conv[2], linear_layer_size) + else: + architecture = architectures[i][1].format(conv[0], conv[1], conv[2], conv[3], linear_layer_size) + + # args = conv + # args.append(linear_layer_size) + # # architecture = architectures[i][1].format(**conv) + # args = {0: conv[0], 1: conv[1], 2: conv[2], 3: linear_layer_size} + # architecture = architectures[i][1].format(**args) + + with open(fname, 'w', encoding='UTF8') as f: + for h in header: + f.write(h + ";") + + f.write("\n") + + for id in range(0, n): + f.write(str(id) + ";") + + f.write(dataset + ";") + f.write(architecture + ";") + + seed = seed_list[id] + f.write(str(seed) + ";") + + f.write(str(steps) + ";") + + f.write("\n") + f.close() + + else: + dataset_index = 0 + + dataset_size_start = 0.1 + dataset_size_stop = 0.5 + + steps_start = 300 + steps_stop = 1000 + + conv1_start = 2 + conv1_stop = 10 + conv2_start = 5 + conv2_stop = 25 + conv3_start = 50 + conv3_stop = 250 + + dataset_list = [dataset_index for _ in range(n)] + + dataset_size_list = [random.uniform(dataset_size_start, dataset_size_stop) for _ in range(n)] + + seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] + + steps_list = [random.randrange(start=steps_start, stop=steps_stop) for _ in range(n)] + + conv1_list = [random.randrange(start=conv1_start, stop=conv1_stop) for _ in range(n)] + conv2_list = [random.randrange(start=conv2_start, stop=conv2_stop) for _ in range(n)] + conv3_list = [random.randrange(start=conv3_start, stop=conv3_stop) for _ in range(n)] + + fname = file_name + ".csv" + with open(fname, 'w', encoding='UTF8') as f: + for h in header: + f.write(h + ";") + + f.write("\n") + + for id in range(0, n): + f.write(str(id) + ";") + + sample_size = architectures[dataset_list[id]][3] + pool_layer_count = architectures[dataset_list[id]][4] + linear_layer_size = conv3_list[id] * pow(sample_size / pow(2, pool_layer_count), 2) + linear_layer_size = int(round(linear_layer_size)) + + dataset_size = int(dataset_size_list[id] * architectures[dataset_list[id]][2]) + dataset = architectures[dataset_list[id]][0] + "_" + str(dataset_size) + architecture = architectures[dataset_list[id]][1].format(conv1_list[id], conv2_list[id], conv3_list[id], linear_layer_size) + + f.write(dataset + ";") + f.write(architecture + ";") + + seed = seed_list[id] + f.write(str(seed) + ";") + + steps = steps_list[id] + f.write(str(steps) + ";") + + f.write("\n") + f.close() diff --git a/build/lib/dacbench/envs/sigmoid.py b/build/lib/dacbench/envs/sigmoid.py new file mode 100644 index 000000000..89dc8f2fa --- /dev/null +++ b/build/lib/dacbench/envs/sigmoid.py @@ -0,0 +1,325 @@ +""" +Sigmoid environment from +"Dynamic Algorithm Configuration:Foundation of a New Meta-Algorithmic Framework" +by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. +Original environment authors: André Biedenkapp, H. Furkan Bozkurt +""" + +import itertools +from typing import List + +import matplotlib.cm as cm +import matplotlib.pyplot as plt +import numpy as np + +from dacbench import AbstractEnv + + +class SigmoidEnv(AbstractEnv): + """ + Environment for tracing sigmoid curves + """ + + def _sig(self, x, scaling, inflection): + """ Simple sigmoid function """ + return 1 / (1 + np.exp(-scaling * (x - inflection))) + + def __init__(self, config) -> None: + """ + Initialize Sigmoid Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super(SigmoidEnv, self).__init__(config) + + self.shifts = [self.n_steps / 2 for _ in config["action_values"]] + self.slopes = [-1 for _ in config["action_values"]] + self.slope_multiplier = config["slope_multiplier"] + self.action_vals = config["action_values"] + self.n_actions = len(self.action_vals) + self.action_mapper = {} + for idx, prod_idx in zip( + range(np.prod(config["action_values"])), + itertools.product(*[np.arange(val) for val in config["action_values"]]), + ): + self.action_mapper[idx] = prod_idx + self._prev_state = None + self.action = None + + if "reward_function" in config.keys(): + self.get_reward = config["reward_function"] + else: + self.get_reward = self.get_default_reward + + if "state_method" in config.keys(): + self.get_state = config["state_method"] + else: + self.get_state = self.get_default_state + + def step(self, action: int): + """ + Execute environment step + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info + """ + self.done = super(SigmoidEnv, self).step_() + action = self.action_mapper[action] + assert self.n_actions == len( + action + ), f"action should be of length {self.n_actions}." + + self.action = action + next_state = self.get_state(self) + self._prev_state = next_state + return next_state, self.get_reward(self), False, self.done, {} + + def reset(self) -> List[int]: + """ + Resets env + + Returns + ------- + numpy.array + Environment state + """ + super(SigmoidEnv, self).reset_() + self.shifts = self.instance[: self.n_actions] + self.slopes = self.instance[self.n_actions :] + self._prev_state = None + return self.get_state(self), {} + + def get_default_reward(self, _): + r = [ + 1 - np.abs(self._sig(self.c_step, slope, shift) - (act / (max_act - 1))) + for slope, shift, act, max_act in zip( + self.slopes, self.shifts, self.action, self.action_vals + ) + ] + r = np.prod(r) + r = max(self.reward_range[0], min(self.reward_range[1], r)) + return r, {} + + def get_default_state(self, _): + remaining_budget = self.n_steps - self.c_step + next_state = [remaining_budget] + for shift, slope in zip(self.shifts, self.slopes): + next_state.append(shift) + next_state.append(slope) + if self.c_step == 0: + next_state += [-1 for _ in range(self.n_actions)] + else: + next_state += self.action + return np.array(next_state) + + def close(self) -> bool: + """ + Close Env + + Returns + ------- + bool + Closing confirmation + """ + return True + + def render(self, mode: str) -> None: + """ + Render env in human mode + + Parameters + ---------- + mode : str + Execution mode + """ + if mode == "human" and self.n_actions == 2: + plt.ion() + plt.show() + plt.cla() + steps = np.arange(self.n_steps) + self.data = self._sig(steps, self.slopes[0], self.shifts[0]) * self._sig( + steps, self.slopes[1], self.shifts[1] + ).reshape(-1, 1) + + plt.imshow( + self.data, + extent=(0, self.n_steps - 1, 0, self.n_steps - 1), + interpolation="nearest", + cmap=cm.plasma, + ) + plt.axvline(x=self.c_step, color="r", linestyle="-", linewidth=2) + plt.axhline(y=self.c_step, color="r", linestyle="-", linewidth=2) + + plt.draw() + plt.pause(0.005) + + +class ContinuousStateSigmoidEnv(SigmoidEnv): + """ + Environment for tracing sigmoid curves with a continuous state on the x-axis + """ + + def __init__(self, config) -> None: + """ + Initialize Sigmoid Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super().__init__(config) + + def step(self, action: int): + """ + Execute environment step + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, info + """ + action = self.action_mapper[action] + assert self.n_actions == len( + action + ), f"action should be of length {self.n_actions}." + + self.action = action + # The reward measures how wrong the choice was so we can take this error to determine how far we travel along + # the x-axis instead of always advancing + 1 + r = self.get_reward(self) + + # magic constants but such that the max step is ~1 and the min step is ~0.25 + self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25))/2 + + if self.c_step >= self.n_steps: + self.done = True + else: + self.done = False + + # self.c_step is used in get_next_state to show how much distance along the x-axis is left to cover + # Thus we get a continuous state this way. + next_state = self.get_state(self) + self._prev_state = next_state + return next_state, r, self.done, {} + +class ContinuousSigmoidEnv(SigmoidEnv): + """ + Environment for tracing sigmoid curves with a continuous state on the x-axis + """ + + def __init__(self, config) -> None: + """ + Initialize Sigmoid Env + + Parameters + ------- + config : objdict + Environment configuration + """ + super().__init__(config) + + def step(self, action: np.ndarray): + """ + Execute environment step. !!NOTE!! The action here is a list of floats and not a single number !!NOTE!! + + Parameters + ---------- + action : list of floats + action(s) to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, info + """ + assert self.n_actions == len( + action + ), f"action should be of length {self.n_actions}." + + self.action = action + # The reward measures how wrong the choice was so we can take this error to determine how far we travel along + # the x-axis instead of always advancing + 1 + r = self.get_reward(self) + + # magic constants but such that the max step is ~1 and the min step is ~0.25 + self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25)) / 2 + + if self.c_step >= self.n_steps: + self.done = True + else: + self.done = False + + # self.c_step is used in get_next_state to show how much distance along the x-axis is left to cover + # Thus we get a continuous state this way. + next_state = self.get_state(self) + self._prev_state = next_state + return next_state, r, self.done, {} + + +if __name__ == '__main__': + from dacbench.abstract_benchmark import objdict + config = objdict( + { + "action_space_class": "Box", + "action_space_args": [ + np.array([-np.inf for _ in range(1 + 2 * 3)]), + np.array([np.inf for _ in range(1 + 2 * 3)]), + ], + "observation_space_class": "Box", + "observation_space_type": np.float32, + "observation_space_args": [ + np.array([-np.inf for _ in range(1 + 2 * 3)]), + np.array([np.inf for _ in range(1 + 2 * 3)]), + ], + "reward_range": (0, 1), + "cutoff": 10, + "action_values": (2, 2), + "slope_multiplier": 2.0, + "seed": 0, + "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", + "benchmark_info": None, + 'instance_set': {0:[5.847291747472278,6.063505157165379,5.356361033331866,8.473324526654427], + 1:[5.699459023308639,0.17993881762205755,3.4218338308013356,8.486280024502191], + 2:[5.410536230957515,5.700091608324946,-5.3540400976249165,2.76787147719077], + 3:[1.5799464875295817,6.374885201056433,1.0378986341827443,4.219330699379608], + 4:[2.61235568666599,6.478051235772757,7.622760392199338,-3.0898869570275167]}, + } + ) + env = ContinuousSigmoidEnv(config) + done = False + s = env.reset() + env.render(mode='human') + while not done: + a = [np.random.rand(), np.random.rand()] + print(env.c_step, a) + s, r, done, _ = env.step(a) + env.render('human') + + + config['action_space'] = "Discrete" + config["action_space_args"] = [int(np.prod((2, 2)))], + env = ContinuousStateSigmoidEnv(config) + done = False + s = env.reset() + env.render(mode='human') + while not done: + a = np.random.randint(4) + print(env.c_step, a) + s, r, done, _ = env.step(a) + env.render('human') diff --git a/build/lib/dacbench/envs/theory.py b/build/lib/dacbench/envs/theory.py new file mode 100644 index 000000000..d2caca966 --- /dev/null +++ b/build/lib/dacbench/envs/theory.py @@ -0,0 +1,574 @@ +import numpy as np +from copy import deepcopy +import logging +from collections import deque + +import uuid +import gym + +from dacbench import AbstractEnv + + +class BinaryProblem: + """ + An abstract class for an individual in binary representation + """ + + def __init__(self, n, rng=np.random.default_rng()): + self.data = rng.choice([True, False], size=n) + self.n = n + self.fitness = self.eval() + + def initialise_with_fixed_number_of_bits(self, k, rng=np.random.default_rng()): + nbits = self.data.sum() + if nbits < k: + ids = rng.choice( + np.where(self.data == False)[0], size=k - nbits, replace=False + ) + self.data[ids] = True + self.eval() + + def is_optimal(self): + pass + + def get_optimal(self): + pass + + def eval(self): + pass + + def get_fitness_after_flipping(self, locs): + """ + Calculate the change in fitness after flipping the bits at positions locs + + Parameters + ----------- + locs: 1d-array + positions where bits are flipped + + Returns: int + ----------- + objective after flipping + """ + raise NotImplementedError + + def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): + """ + Calculate fitness of the child aftering being crossovered with xprime + + Parameters + ----------- + xprime: 1d boolean array + the individual to crossover with + locs_x: 1d boolean/integer array + positions where we keep current bits of self + locs_xprime: : 1d boolean/integer array + positions where we change to xprime's bits + + Returns: fitness of the new individual after crossover + ----------- + """ + raise NotImplementedError + + def flip(self, locs): + """ + flip the bits at position indicated by locs + + Parameters + ----------- + locs: 1d-array + positions where bits are flipped + + Returns: the new individual after the flip + """ + child = deepcopy(self) + child.data[locs] = ~child.data[locs] + child.eval() + return child + + def combine(self, xprime, locs_xprime): + """ + combine (crossover) self and xprime by taking xprime's bits at locs_xprime and self's bits at other positions + + Parameters + ----------- + xprime: 1d boolean array + the individual to crossover with + locs_x: 1d boolean/integer array + positions where we keep current bits of self + locs_xprime: : 1d boolean/integer array + positions where we change to xprime's bits + + Returns: the new individual after the crossover + + """ + child = deepcopy(self) + child.data[locs_xprime] = xprime.data[locs_xprime] + child.eval() + return child + + def mutate(self, p, n_childs, rng=np.random.default_rng()): + """ + Draw l ~ binomial(n, p), l>0 + Generate n_childs children by flipping exactly l bits + Return: the best child (maximum fitness), its fitness and number of evaluations used + """ + assert p >= 0 + + if p == 0: + return self, self.fitness, 0 + + l = 0 + while l == 0: + l = rng.binomial(self.n, p) + + best_obj = -1 + best_locs = None + for i in range(n_childs): + locs = rng.choice(self.n, size=l, replace=False) + obj = self.get_fitness_after_flipping(locs) + if obj > best_obj: + best_locs = locs + best_obj = obj + + best_child = self.flip(best_locs) + + return best_child, best_child.fitness, n_childs + + def mutate_rls(self, l, rng=np.random.default_rng()): + """ + generate a child by flipping exactly l bits + Return: child, its fitness + """ + assert l >= 0 + + if l == 0: + return self, self.fitness, 0 + + locs = rng.choice(self.n, size=l, replace=False) + child = self.flip(locs) + + return child, child.fitness, 1 + + def crossover( + self, + xprime, + p, + n_childs, + include_xprime=True, + count_different_inds_only=True, + rng=np.random.default_rng(), + ): + """ + Crossover operator: + for each bit, taking value from x with probability p and from self with probability 1-p + Arguments: + x: the individual to crossover with + p (float): in [0,1] + """ + assert p <= 1 + + if p == 0: + if include_xprime: + return xprime, xprime.fitness, 0 + else: + return self, self.fitness, 0 + + if include_xprime: + best_obj = xprime.fitness + else: + best_obj = -1 + best_locs = None + + n_evals = 0 + ls = rng.binomial(self.n, p, size=n_childs) + for l in ls: + locs_xprime = rng.choice(self.n, l, replace=False) + locs_x = np.full(self.n, True) + locs_x[locs_xprime] = False + obj = self.get_fitness_after_crossover(xprime, locs_x, locs_xprime) + + if (obj != self.fitness) and (obj != xprime.fitness): + n_evals += 1 + elif ( + not np.array_equal(xprime.data[locs_xprime], self.data[locs_xprime]) + ) and (not np.array_equal(self.data[locs_x], xprime.data[locs_x])): + n_evals += 1 + + if obj > best_obj: + best_obj = obj + best_locs = locs_xprime + + if best_locs is not None: + child = self.combine(xprime, best_locs) + else: + child = xprime + + if not count_different_inds_only: + n_evals = n_childs + + return child, child.fitness, n_evals + + +class LeadingOne(BinaryProblem): + """ + An individual for LeadingOne problem + The aim is to maximise the number of leading (and consecutive) 1 bits in the string + """ + + def __init__(self, n, rng=np.random.default_rng(), initObj=None): + if initObj is None: + super(LeadingOne, self).__init__(n=n, rng=rng) + else: + self.data = rng.choice([True, False], size=n) + self.data[: int(initObj)] = True + self.data[int(initObj)] = False + self.n = n + self.fitness = self.eval() + + def eval(self): + k = self.data.argmin() + if self.data[k]: + self.fitness = self.n + else: + self.fitness = k + return self.fitness + + def is_optimal(self): + return self.data.all() + + def get_optimal(self): + return self.n + + def get_fitness_after_flipping(self, locs): + min_loc = locs.min() + if min_loc < self.fitness: + return min_loc + elif min_loc > self.fitness: + return self.fitness + else: + old_fitness = self.fitness + self.data[locs] = ~self.data[locs] + new_fitness = self.eval() + self.data[locs] = ~self.data[locs] + self.fitness = old_fitness + return new_fitness + + def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): + child = self.combine(xprime, locs_xprime) + child.eval() + return child.fitness + + +MAX_INT = 1e8 +HISTORY_LENGTH = 5 + + +class RLSEnv(AbstractEnv): + """ + Environment for RLS with step size + Current assumption: we only consider (1+1)-RLS, so there's only one parameter to tune (r) + """ + + def __init__(self, config, test_env=False) -> None: + """ + Initialize RLSEnv + + Parameters + ------- + config : objdict + Environment configuration + """ + super(RLSEnv, self).__init__(config) + self.logger = logging.getLogger(self.__str__()) + + self.test_env = test_env + + self.name = config.name + + # name of reward function + assert config.reward_choice in [ + "imp_div_evals", + "imp_div_evals_new", + "imp_minus_evals", + "minus_evals", + "imp", + "minus_evals_normalised", + "imp_minus_evals_normalised", + ] + self.reward_choice = config.reward_choice + # print("Reward choice: " + self.reward_choice) + + # get problem + self.problem = globals()[config.problem] + + # read names of all observation variables + self.obs_description = config.observation_description + self.obs_var_names = [ + s.strip() for s in config.observation_description.split(",") + ] + + # functions to get values of the current state from histories + # (see reset() function for those history variables) + self.state_functions = [] + for var_name in self.obs_var_names: + if var_name == "n": + self.state_functions.append(lambda: self.n) + elif var_name in ["r"]: + self.state_functions.append( + lambda his="history_" + var_name: vars(self)[his][-1] + ) + elif ( + "_{t-" in var_name + ): # TODO: this implementation only allow accessing history of r, but not delta_f(x), optimal_k, etc + k = int( + var_name.split("_{t-")[1][:-1] + ) # get the number in _{t-} + name = var_name.split("_{t-")[0] # get the variable name (r, f(x), etc) + self.state_functions.append( + lambda his="history_" + name: vars(self)[his][-(k + 1)] + ) # the last element is the value at the current time step, so we have to go one step back to access the history + elif var_name == "f(x)": + self.state_functions.append(lambda: self.history_fx[-1]) + elif var_name == "delta_f(x)": + self.state_functions.append( + lambda: self.history_fx[-1] - self.history_fx[-2] + ) + elif var_name == "optimal_r": + self.state_functions.append( + lambda: int(self.n / (self.history_fx[-1] + 1)) + ) + else: + raise Exception("Error: invalid state variable name: " + var_name) + + # the random generator used by RLS + if "seed" in config: + seed = config.seed + else: + seed = None + if "seed" in self.instance: + seed = self.instance.seed + self.seed(seed) + + # for logging + self.outdir = None + if "outdir" in config: + self.outdir = config.outdir + "/" + str(uuid.uuid4()) + + def get_obs_domain_from_name(var_name): + """ + Get default lower and upperbound of a observation variable based on its name. + The observation space will then be created + Return: + Two int values, e.g., 1, np.inf + """ + return 0, np.inf + + def reset(self): + """ + Resets env + + Returns + ------- + numpy.array + Environment state + """ + super(RLSEnv, self).reset_() + + # current problem size (n) & evaluation limit (max_evals) + self.n = self.instance.size + if self.test_env: + self.max_evals = self.n_steps + else: + self.max_evals = int(0.8 * self.n * self.n) + self.logger.info("n:%d, max_evals:%d" % (self.n, self.max_evals)) + + # set random seed + if "seed" in self.instance: + self.seed(self.instance.seed) + + # create an initial solution + if self.instance.initObj == "random": + self.x = self.problem(n=self.instance.size, rng=self.np_random) + else: + self.x = self.problem( + n=self.instance.size, rng=self.np_random, initObj=self.instance.initObj + ) + + # total number of evaluations so far + self.total_evals = 1 + + # reset histories + self.history_r = deque([0] * HISTORY_LENGTH, maxlen=HISTORY_LENGTH) + self.history_fx = deque( + [self.x.fitness] * HISTORY_LENGTH, maxlen=HISTORY_LENGTH + ) + + # for debug only + self.log_r = [] + self.log_reward = [] + self.log_fx = [] + self.init_obj = self.x.fitness + + return self.get_state(), {} + + def get_state(self): + return np.asarray([f() for f in self.state_functions]) + + def step(self, action): + """ + Execute environment step + + Parameters + ---------- + action : Box + action to execute + + Returns + ------- + state, reward, terminated, truncated, info + np.array, float, bool, bool, dict + """ + truncated = super(RLSEnv, self).step_() + + fitness_before_update = self.x.fitness + + # get r + if isinstance(action, np.ndarray) or isinstance(action, list): + assert len(action) == 1 + r = action[0] + else: + r = action + + # if r is out of range + stop = False + if r < 1 or r > self.n: + self.logger.info(f"WARNING: r={r} is out of bound") + + # if we're in the training phase, we return a large negative reward and stop the episode + if self.test_env is False: + terminated = True + n_evals = 0 + reward = -MAX_INT + stop = True + # if we're in the test phase, just clip r back to the range and continue + else: + r = np.clip(r, 1, self.n) + + if stop is False: + # flip r bits + r = int(r) + y, f_y, n_evals = self.x.mutate_rls(r, self.np_random) + + # update x + if self.x.fitness <= y.fitness: + self.x = y + + # update total number of evaluations + self.total_evals += n_evals + + # check stopping criteria + terminated = (self.total_evals >= self.max_evals) or (self.x.is_optimal()) + + # calculate reward + if self.reward_choice == "imp_div_evals": + reward = (self.x.fitness - fitness_before_update - 0.5) / n_evals + elif self.reward_choice == "imp_minus_evals": + reward = self.x.fitness - fitness_before_update - n_evals + elif self.reward_choice == "minus_evals": + reward = -n_evals + elif self.reward_choice == "minus_evals_normalised": + reward = -n_evals / self.max_evals + elif self.reward_choice == "imp_minus_evals_normalised": + reward = ( + self.x.fitness - fitness_before_update - n_evals + ) / self.max_evals + elif self.reward_choice == "imp": + reward = self.x.fitness - fitness_before_update - 0.5 + self.log_reward.append(reward) + + # update histories + self.history_fx.append(self.x.fitness) + self.history_r.append(r) + + # update logs + self.log_r.append(r) + self.log_fx.append(self.x.fitness) + self.log_reward.append(reward) + + returned_info = {"msg": "", "values": {}} + if terminated or truncated: + if hasattr(self, "env_type"): + msg = "Env " + self.env_type + ". " + else: + msg = "" + msg += "Episode done: n=%d; obj=%d; init_obj=%d; evals=%d; max_evals=%d; steps=%d; r_min=%.1f; r_max=%.1f; r_mean=%.1f; R=%.4f" % ( + self.n, + self.x.fitness, + self.init_obj, + self.total_evals, + self.max_evals, + self.c_step, + min(self.log_r), + max(self.log_r), + sum(self.log_r) / len(self.log_r), + sum(self.log_reward), + ) + # self.logger.info(msg) + returned_info["msg"] = msg + returned_info["values"] = { + "n": int(self.n), + "obj": int(self.x.fitness), + "init_obj": int(self.init_obj), + "evals": int(self.total_evals), + "max_evals": int(self.max_evals), + "steps": int(self.c_step), + "r_min": float(min(self.log_r)), + "r_max": float(max(self.log_r)), + "r_mean": float(sum(self.log_r) / len(self.log_r)), + "R": float(sum(self.log_reward)), + "log_r": [int(x) for x in self.log_r], + "log_fx": [int(x) for x in self.log_fx], + "log_reward": [float(x) for x in self.log_reward], + } + + return self.get_state(), reward, truncated, terminated, returned_info + + def close(self) -> bool: + """ + Close Env + + No additional cleanup necessary + + Returns + ------- + bool + Closing confirmation + """ + return True + + +class RLSEnvDiscrete(RLSEnv): + """ + RLS environment where the choices of r is discretised + """ + + def __init__(self, config, test_env=False): + super(RLSEnvDiscrete, self).__init__(config, test_env) + assert ( + "action_choices" in config + ), "Error: action_choices must be specified in benchmark's config" + assert isinstance( + self.action_space, gym.spaces.Discrete + ), "Error: action space must be discrete" + assert self.action_space.n == len(config["action_choices"]), ( + "Error: action space's size (%d) must be equal to the len(action_choices) (%d)" + % (self.action_space.n, len(config["action_choices"])) + ) + self.action_choices = config["action_choices"] + + def step(self, action): + if isinstance(action, np.ndarray) or isinstance(action, list): + assert len(action) == 1 + action = action[0] + return super(RLSEnvDiscrete, self).step(self.action_choices[action]) diff --git a/build/lib/dacbench/envs/toysgd.py b/build/lib/dacbench/envs/toysgd.py new file mode 100644 index 000000000..4f7e913d3 --- /dev/null +++ b/build/lib/dacbench/envs/toysgd.py @@ -0,0 +1,234 @@ +from dacbench import AbstractEnv +import numpy as np +from numpy.polynomial import Polynomial +from typing import Union, Tuple, Optional, Dict +import pandas as pd + + +def create_polynomial_instance_set( + out_fname: str, + n_samples: int = 100, + order: int = 2, + low: float = -10, + high: float = 10, +): + instances = [] + for i in range(n_samples): + coeffs = sample_coefficients(order=order, low=low, high=high) + instance = { + "ID": i, + "family": "polynomial", + "order": order, + "low": low, + "high": high, + "coefficients": coeffs, + } + instances.append(instance) + df = pd.DataFrame(instances) + df.to_csv(out_fname, sep=";", index=False) + + +def sample_coefficients(order: int = 2, low: float = -10, high: float = 10): + n_coeffs = order + 1 + coeffs = np.zeros((n_coeffs,)) + coeffs[0] = np.random.uniform(0, high, size=1) + coeffs[1:] = np.random.uniform(low, high, size=n_coeffs - 1) + return coeffs + + +class ToySGDEnv(AbstractEnv): + """ + Optimize toy functions with SGD + Momentum. + + + Action: [log_learning_rate, log_momentum] (log base 10) + State: Dict with entries remaining_budget, gradient, learning_rate, momentum + Reward: negative log regret of current and true function value + + An instance can look as follows: + ID 0 + family polynomial + order 2 + low -2 + high 2 + coefficients [ 1.40501053 -0.59899755 1.43337392] + + """ + + def __init__(self, config): + super(ToySGDEnv, self).__init__(config) + self.n_steps_max = config.get("cutoff", 1000) + + self.velocity = 0 + self.gradient = 0 + self.history = [] + self.n_dim = None # type: Optional[int] + self.objective_function = None + self.objective_function_deriv = None + self.x_min = None + self.f_min = None + self.x_cur = None + self.f_cur = None + self.momentum = 0 # type: Optional[float] + self.learning_rate = None # type: Optional[float] + self.n_steps = 0 # type: Optional[int] + + def build_objective_function(self): + if self.instance["family"] == "polynomial": + order = int(self.instance["order"]) + if order != 2: + raise NotImplementedError( + "Only order 2 is currently implemented for polynomial functions." + ) + self.n_dim = order + coeffs_str = self.instance["coefficients"] + coeffs_str = coeffs_str.strip("[]") + coeffs = [float(item) for item in coeffs_str.split()] + self.objective_function = Polynomial(coef=coeffs) + self.objective_function_deriv = self.objective_function.deriv( + m=1 + ) # lambda x0: derivative(self.objective_function, x0, dx=1.0, n=1, args=(), order=3) + self.x_min = -coeffs[1] / ( + 2 * coeffs[0] + 1e-10 + ) # add small epsilon to avoid numerical instabilities + self.f_min = self.objective_function(self.x_min) + + self.x_cur = self.get_initial_position() + else: + raise NotImplementedError( + "No other function families than polynomial are currently supported." + ) + + def get_initial_position(self): + return 0 # np.random.uniform(-5, 5, size=self.n_dim-1) + + def step( + self, action: Union[float, Tuple[float, float]] + ) -> Tuple[Dict[str, float], float, bool, Dict]: + """ + Take one step with SGD + + Parameters + ---------- + action: Tuple[float, Tuple[float, float]] + If scalar, action = (log_learning_rate) + If tuple, action = (log_learning_rate, log_momentum) + + Returns + ------- + Tuple[Dict[str, float], float, bool, Dict] + + - state : Dict[str, float] + State with entries "remaining_budget", "gradient", "learning_rate", "momentum" + - reward : float + - terminated : bool + - truncated : bool + - info : Dict + """ + truncated = super(ToySGDEnv, self).step_() + info = {} + + # parse action + if np.isscalar(action): + log_learning_rate = action + elif len(action) == 2: + log_learning_rate, log_momentum = action + self.momentum = 10**log_momentum + else: + raise ValueError + self.learning_rate = 10**log_learning_rate + + # SGD + Momentum update + self.velocity = ( + self.momentum * self.velocity + self.learning_rate * self.gradient + ) + self.x_cur -= self.velocity + self.gradient = self.objective_function_deriv(self.x_cur) + + # State + remaining_budget = self.n_steps_max - self.n_steps + state = { + "remaining_budget": remaining_budget, + "gradient": self.gradient, + "learning_rate": self.learning_rate, + "momentum": self.momentum, + } + + # Reward + # current function value + self.f_cur = self.objective_function(self.x_cur) + # log regret + log_regret = np.log10(np.abs(self.f_min - self.f_cur)) + reward = -log_regret + + self.history.append(self.x_cur) + + # Stop criterion + self.n_steps += 1 + + return state, reward, False, truncated, info + + def reset(self): + """ + Reset environment + + Returns + ------- + np.array + Environment state + dict + Meta-info + """ + super(ToySGDEnv, self).reset_() + + self.velocity = 0 + self.gradient = 0 + self.history = [] + self.objective_function = None + self.objective_function_deriv = None + self.x_min = None + self.f_min = None + self.x_cur = None + self.f_cur = None + self.momentum = 0 + self.learning_rate = 0 + self.n_steps = 0 + self.build_objective_function() + return { + "remaining_budget": self.n_steps_max, + "gradient": self.gradient, + "learning_rate": self.learning_rate, + "momentum": self.momentum, + }, {} + + def render(self, **kwargs): + import matplotlib.pyplot as plt + + history = np.array(self.history).flatten() + X = np.linspace(1.05 * np.amin(history), 1.05 * np.amax(history), 100) + Y = self.objective_function(X) + fig = plt.figure() + ax = fig.add_subplot(111) + ax.plot(X, Y, label="True") + ax.plot( + history, + self.objective_function(history), + marker="x", + color="black", + label="Observed", + ) + ax.plot( + self.x_cur, + self.objective_function(self.x_cur), + marker="x", + color="red", + label="Current Optimum", + ) + ax.legend() + ax.set_xlabel("x") + ax.set_ylabel("y") + ax.set_title("instance: " + str(self.instance["coefficients"])) + plt.show() + + def close(self): + pass diff --git a/build/lib/dacbench/logger.py b/build/lib/dacbench/logger.py new file mode 100644 index 000000000..601786e70 --- /dev/null +++ b/build/lib/dacbench/logger.py @@ -0,0 +1,915 @@ +import json +from abc import ABCMeta, abstractmethod +from collections import defaultdict, ChainMap +from datetime import datetime +from functools import reduce +from itertools import chain +from numbers import Number +from pathlib import Path +from typing import Union, Dict, Any, Tuple, List + +import numpy as np +import pandas as pd + +from typing import Callable, Iterable +from dacbench import AbstractEnv, AbstractBenchmark +from dacbench.abstract_agent import AbstractDACBenchAgent + + +def load_logs(log_file: Path) -> List[Dict]: + """ + Loads the logs from a jsonl written by any logger. + + The result is the list of dicts in the format: + { + 'instance': 0, + 'episode': 0, + 'step': 1, + 'example_log_val': { + 'values': [val1, val2, ... valn], + 'times: [time1, time2, ..., timen], + } + ... + } + Parameters + ---------- + log_file: pathlib.Path + The path to the log file + + Returns + ------- + [Dict, ...] + """ + with open(log_file, "r") as log_file: + logs = list(map(json.loads, log_file)) + + return logs + + +def split(predicate: Callable, iterable: Iterable) -> Tuple[List, List]: + """ + Splits the iterable into two list depending on the result of predicate. + + Parameters + ---------- + predicate: Callable + A function taking an element of the iterable and return Ture or False + iterable: Iterable + + Returns + ------- + (positives, negatives) + """ + positives, negatives = [], [] + + for item in iterable: + (positives if predicate(item) else negatives).append(item) + + return positives, negatives + + +def flatten_log_entry(log_entry: Dict) -> List[Dict]: + """ + Transforms a log entry of format like + + + { + 'step': 0, + 'episode': 2, + 'some_value': { + 'values' : [34, 45], + 'times':['28-12-20 16:20:53', '28-12-20 16:21:30'], + } + } + into + [ + { 'step': 0,'episode': 2, 'value': 34, 'time': '28-12-20 16:20:53'}, + { 'step': 0,'episode': 2, 'value': 45, 'time': '28-12-20 16:21:30'} + ] + + Parameters + ---------- + log_entry: Dict + A log entry + + Returns + ------- + """ + dict_entries, top_level_entries = split( + lambda item: isinstance(item[1], dict), log_entry.items() + ) + rows = [] + for value_name, value_dict in dict_entries: + current_rows = ( + dict( + top_level_entries + + [("value", value), ("time", time), ("name", value_name)] + ) + for value, time in zip(value_dict["values"], value_dict["times"]) + ) + + rows.extend(map(dict, current_rows)) + + return rows + + +def list_to_tuple(list_: List) -> Tuple: + """ + Recursively transforms a list of lists into tuples of tuples + Parameters + ---------- + list_: + (nested) list + + Returns + ------- + (nested) tuple + """ + return tuple( + list_to_tuple(item) if isinstance(item, list) else item for item in list_ + ) + + +def log2dataframe( + logs: List[dict], wide: bool = False, drop_columns: List[str] = ["time"] +) -> pd.DataFrame: + """ + Converts a list of log entries to a pandas dataframe. + + Usually used in combination with load_dataframe. + + Parameters + ---------- + logs: List + List of log entries + wide: bool + wide=False (default) produces a dataframe with columns (episode, step, time, name, value) + wide=True returns a dataframe (episode, step, time, name_1, name_2, ...) if the variable name_n has not been logged + at (episode, step, time) name_n is NaN. + drop_columns: List[str] + List of column names to be dropped (before reshaping the long dataframe) mostly used in combination + with wide=True to reduce NaN values + + Returns + ------- + dataframe + """ + + flat_logs = map(flatten_log_entry, logs) + rows = reduce(lambda l1, l2: l1 + l2, flat_logs) + + dataframe = pd.DataFrame(rows) + dataframe.time = pd.to_datetime(dataframe.time) + + if drop_columns is not None: + dataframe = dataframe.drop(columns=drop_columns) + + dataframe = dataframe.infer_objects() + list_column_candidates = dataframe.dtypes == object + + for i, candidate in enumerate(list_column_candidates): + if candidate: + dataframe.iloc[:, i] = dataframe.iloc[:, i].apply( + lambda x: list_to_tuple(x) if isinstance(x, list) else x + ) + + if wide: + primary_index_columns = ["episode", "step"] + field_id_column = "name" + additional_columns = list( + set(dataframe.columns) + - set(primary_index_columns + ["time", "value", field_id_column]) + ) + index_columns = primary_index_columns + additional_columns + [field_id_column] + dataframe = dataframe.set_index(index_columns) + dataframe = dataframe.unstack() + dataframe.reset_index(inplace=True) + dataframe.columns = [a if b == "" else b for a, b in dataframe.columns] + + return dataframe.infer_objects() + + +def seed_mapper(self): + if self.env is None: + return None + return self.env.initial_seed + + +def instance_mapper(self): + if self.env is None: + return None + return self.env.get_inst_id() + + +class AbstractLogger(metaclass=ABCMeta): + """ + Logger interface. + + The logger classes provide a way of writing structured logs as jsonl files and also help to track information like + current episode, step, time ... + + In the jsonl log file each row corresponds to a step. + """ + + valid_types = { + "recursive": [dict, list, tuple, np.ndarray], + "primitive": [str, int, float, bool, np.number], + } + + def __init__( + self, + experiment_name: str, + output_path: Path, + step_write_frequency: int = None, + episode_write_frequency: int = 1, + ): + """ + + Parameters + ---------- + experiment_name: str + Name of the folder to store the result in + output_path: pathlib.Path + Path under which the experiment folder is created + step_write_frequency: int + number of steps after which the loggers writes to file. + If None only the data is only written to file if write is called, if triggered by episode_write_frequency + or on close + episode_write_frequency: int + see step_write_frequency + """ + self.experiment_name = experiment_name + self.output_path = output_path + self.log_dir = self._init_logging_dir(self.output_path / self.experiment_name) + self.step_write_frequency = step_write_frequency + self.episode_write_frequency = episode_write_frequency + self._additional_info = {} + self.additional_info_auto_mapper = { + "instance": instance_mapper, + "seed": seed_mapper, + } + self.env = None + + @property + def additional_info(self): + additional_info = self._additional_info.copy() + auto_info = { + key: mapper(self) + for key, mapper in self.additional_info_auto_mapper.items() + if mapper(self) is not None + } + + additional_info.update(auto_info) + + return additional_info + + def set_env(self, env: AbstractEnv) -> None: + """ + Needed to infer automatically logged information like the instance id + Parameters + ---------- + env: AbstractEnv + + Returns + ------- + + """ + self.env = env + + @staticmethod + def _pretty_valid_types() -> str: + """ + Returns a string pretty string representation of the types that can be logged as values + Returns + ------- + + """ + valid_types = chain( + AbstractLogger.valid_types["recursive"], + AbstractLogger.valid_types["primitive"], + ) + return ", ".join(map(lambda type_: type_.__name__, valid_types)) + + @staticmethod + def _init_logging_dir(log_dir: Path) -> None: + """ + Prepares the logging directory + Parameters + ---------- + log_dir: pathlib.Path + + Returns + ------- + None + """ + log_dir.mkdir(parents=True, exist_ok=True) + return log_dir + + def is_of_valid_type(self, value: Any) -> bool: + f""" + Checks if the value of any type in {AbstractLogger._pretty_valid_types()} + Parameters + ---------- + value + + Returns + ------- + bool + """ + + if any(isinstance(value, type) for type in self.valid_types["primitive"]): + return True + + elif any(isinstance(value, type) for type in self.valid_types["recursive"]): + value = value.vlaues() if isinstance(value, dict) else value + return all(self.is_of_valid_type(sub_value) for sub_value in value) + + else: + return False + + @abstractmethod + def close(self) -> None: + """ + Makes sure, that all remaining entries in the are written to file and the file is closed. + + Returns + ------- + + """ + pass + + @abstractmethod + def next_step(self) -> None: + """ + Call at the end of the step. + Updates the internal state and dumps the information of the last step into a json + + Returns + ------- + + """ + pass + + @abstractmethod + def next_episode(self) -> None: + """ + Call at the end of episode. + + See next_step + Returns + ------- + + """ + pass + + @abstractmethod + def write(self) -> None: + """ + Writes buffered logs to file. + + Invoke manually if you want to load logs during a run. + + Returns + ------- + + """ + pass + + @abstractmethod + def log(self, key: str, value) -> None: + f""" + Writes value to list of values and save the current time for key + + Parameters + ---------- + key: str + value: + the value must of of a type that is json serializable. + Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. + + Returns + ------- + + """ + pass + + @abstractmethod + def log_dict(self, data): + """ + Alternative to log if more the one value should be logged at once. + + Parameters + ---------- + data: dict + a dict with key-value so that each value is a valid value for log + + Returns + ------- + + """ + pass + + @abstractmethod + def log_space(self, key: str, value: Union[np.ndarray, Dict], space_info=None): + """ + Special for logging gym.spaces. + + Currently three types are supported: + * Numbers: e.g. samples from Discrete + * Fixed length arrays like MultiDiscrete or Box + * Dict: assuming each key has fixed length array + + Parameters + ---------- + key: + see log + value: + see log + space_info: + a list of column names. The length of this list must equal the resulting number of columns. + + Returns + ------- + + """ + pass + + +class ModuleLogger(AbstractLogger): + """ + A logger for handling logging of one module. e.g. a wrapper or toplevel general logging. + + Don't create manually use Logger to manage ModuleLoggers + """ + + def __init__( + self, + output_path: Path, + experiment_name: str, + module: str, + step_write_frequency: int = None, + episode_write_frequency: int = 1, + ) -> None: + """ + All results are placed under 'output_path / experiment_name' + + Parameters + ---------- + experiment_name: str + Name of the folder to store the result in + output_path: pathlib.Path + Path under which the experiment folder is created + module: str + the module (mostly name of the wrapper), each wrapper gets its own file + step_write_frequency: int + number of steps after which the loggers writes to file. + If None only the data is only written to file if write is called, if triggered by episode_write_frequency + or on close + episode_write_frequency: int + see step_write_frequency + output_path: + The path where logged information should be stored + + """ + super(ModuleLogger, self).__init__( + experiment_name, output_path, step_write_frequency, episode_write_frequency + ) + + self.log_file = open(self.log_dir / f"{module}.jsonl", "w") + + self.step = 0 + self.episode = 0 + self.buffer = [] + self.current_step = self.__init_dict() + + def get_logfile(self) -> Path: + """ + Returns + ------- + pathlib.Path + the path to the log file of this logger + """ + return Path(self.log_file.name) + + def close(self): + """ + Makes sure, that all remaining entries in the are written to file and the file is closed. + + Returns + ------- + + """ + if not self.log_file.closed: + self.write() + self.log_file.close() + + def __del__(self): + if not self.log_file.closed: + self.close() + + @staticmethod + def __json_default(object): + """ + Add supoort for dumping numpy arrays and numbers to json + Parameters + ---------- + object + + Returns + ------- + + """ + if isinstance(object, np.ndarray): + return object.tolist() + elif isinstance(object, np.number): + return object.item() + else: + raise ValueError(f"Type {type(object)} not supported") + + def __end_step(self): + if self.current_step: + self.current_step["step"] = self.step + self.current_step["episode"] = self.episode + self.current_step.update(self.additional_info) + self.buffer.append( + json.dumps(self.current_step, default=self.__json_default) + ) + self.current_step = self.__init_dict() + + @staticmethod + def __init_dict(): + return defaultdict(lambda: {"times": [], "values": []}) + + def reset_episode(self) -> None: + """ + Resets the episode and step. + + Be aware that this can lead to ambitious keys if no instance or seed or other identifying additional info is set + + Returns + ------- + + """ + self.__end_step() + self.episode = 0 + self.step = 0 + + def __reset_step(self): + self.__end_step() + self.step = 0 + + def next_step(self): + """ + Call at the end of the step. + Updates the internal state and dumps the information of the last step into a json + + Returns + ------- + + """ + self.__end_step() + if ( + self.step_write_frequency is not None + and self.step % self.step_write_frequency == 0 + ): + self.write() + self.step += 1 + + def next_episode(self): + """ + Writes buffered logs to file. + + Invoke manually if you want to load logs during a run. + + Returns + ------- + + """ + self.__reset_step() + if ( + self.episode_write_frequency is not None + and self.episode % self.episode_write_frequency == 0 + ): + self.write() + self.episode += 1 + + def write(self): + """ + Writes buffered logs to file. + + Invoke manually if you want to load logs during a run. + + Returns + ------- + + """ + self.__end_step() + self.__buffer_to_file() + + def __buffer_to_file(self): + if len(self.buffer) > 0: + self.log_file.write("\n".join(self.buffer)) + self.log_file.write("\n") + self.buffer.clear() + self.log_file.flush() + + def set_additional_info(self, **kwargs): + """ + Can be used to log additional information for each step e.g. for seed, and instance id. + Parameters + ---------- + kwargs + + Returns + ------- + + """ + self._additional_info.update(kwargs) + + def log( + self, key: str, value: Union[Dict, List, Tuple, str, int, float, bool] + ) -> None: + f""" + Writes value to list of values and save the current time for key + + Parameters + ---------- + key: str + value: + the value must of of a type that is json serializable. + Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. + + Returns + ------- + + """ + self.__log(key, value, datetime.now().strftime("%d-%m-%y %H:%M:%S.%f")) + + def __log(self, key, value, time): + if not self.is_of_valid_type(value): + valid_types = self._pretty_valid_types() + raise ValueError( + f"value {type(value)} is not of valid type or a recursive composition of valid types ({valid_types})" + ) + self.current_step[key]["times"].append(time) + self.current_step[key]["values"].append(value) + + def log_dict(self, data: Dict) -> None: + """ + Alternative to log if more the one value should be logged at once. + + Parameters + ---------- + data: dict + a dict with key-value so that each value is a valid value for log + + Returns + ------- + """ + time = datetime.now().strftime("%d-%m-%y %H:%M:%S.%f") + for key, value in data.items(): + self.__log(key, value, time) + + @staticmethod + def __space_dict(key: str, value, space_info): + if isinstance(value, np.ndarray) and len(value.shape) == 0: + value = value.item() + + if isinstance(value, Number): + if space_info is None: + data = {key: value} + else: + if len(space_info) != 1: + raise ValueError( + f"Space info must match length (expect 1 != got{len(space_info)}" + ) + + data = {f"{key}_{space_info[0]}": value} + + elif isinstance(value, np.ndarray): + if space_info is not None and len(space_info) != len(value): + raise ValueError( + f"Space info must match length (expect {len(value)} != got{len(space_info)}" + ) + key_suffix = ( + enumerate(value) if space_info is None else zip(space_info, value) + ) + data = {f"{key}_{suffix}": x for suffix, x in key_suffix} + + elif isinstance(value, dict): + key_suffix = ( + value.items() if space_info is None else zip(space_info, value.values()) + ) + dicts = ( + ModuleLogger.__space_dict(f"{key}_{sub_key}", sub_value, None) + for sub_key, sub_value in key_suffix + ) + data = dict(ChainMap(*dicts)) + else: + raise ValueError("Space does not seem be supported") + + return data + + def log_space(self, key, value, space_info=None): + """ + Special for logging gym.spaces. + + Currently three types are supported: + * Numbers: e.g. samples from Discrete + * Fixed length arrays like MultiDiscrete or Box + * Dict: assuming each key has fixed length array + + Parameters + ---------- + key: + see log + value: + see log + space_info: + a list of column names. The length of this list must equal the resulting number of columns. + + Returns + ------- + + """ + data = self.__space_dict(key, value, space_info) + self.log_dict(data) + + +class Logger(AbstractLogger): + """ + A logger that manages the creation of the module loggers. + + To get a ModuleLogger for you module (e.g. wrapper) call module_logger = Logger(...).add_module("my_wrapper"). + From now on module_logger.log(...) or logger.log(..., module="my_wrapper") can be used to log. + + The logger module takes care of updating information like episode and step in the subloggers. To indicate to the loggers + the end of the episode or the next_step simple call logger.next_episode() or logger.next_step(). + """ + + def __init__( + self, + experiment_name: str, + output_path: Path, + step_write_frequency: int = None, + episode_write_frequency: int = 1, + ) -> None: + """ + + Parameters + ---------- + experiment_name: str + Name of the folder to store the result in + output_path: pathlib.Path + Path under which the experiment folder is created + step_write_frequency: int + number of steps after which the loggers writes to file. + If None only the data is only written to file if write is called, if triggered by episode_write_frequency + or on close + episode_write_frequency: int + see step_write_frequency + """ + super(Logger, self).__init__( + experiment_name, output_path, step_write_frequency, episode_write_frequency + ) + self.env: AbstractEnv = None + self.module_logger: Dict[str, ModuleLogger] = dict() + + def set_env(self, env: AbstractEnv) -> None: + super().set_env(env) + for _, module_logger in self.module_logger.items(): + module_logger.set_env(env) + + def close(self): + """ + Makes sure, that all remaining entries (from all sublogger) are written to files and the files are closed. + + Returns + ------- + + """ + for _, module_logger in self.module_logger.items(): + module_logger.close() + + def __del__(self): + self.close() + + def next_step(self): + """ + Call at the end of the step. + Updates the internal state of all subloggers and dumps the information of the last step into a json + + Returns + ------- + + """ + for _, module_logger in self.module_logger.items(): + module_logger.next_step() + + def next_episode(self): + """ + Call at the end of episode. + + See next_step + Returns + ------- + + """ + for _, module_logger in self.module_logger.items(): + module_logger.next_episode() + + def reset_episode(self): + for _, module_logger in self.module_logger.items(): + module_logger.reset_episode() + + def write(self): + """ + Writes buffered logs to file. + + Invoke manually if you want to load logs during a run. + + Returns + ------- + + """ + for _, module_logger in self.module_logger.items(): + module_logger.write() + + def add_module(self, module: Union[str, type]) -> ModuleLogger: + """ + Creates a sub-logger. For more details see class level documentation + Parameters + ---------- + module: str or type + The module name or Wrapper-Type to create a sub-logger for + Returns + ------- + ModuleLogger + """ + if isinstance(module, str): + pass + elif isinstance(module, type): + module = module.__name__ + else: + module = module.__class__ + + if module in self.module_logger: + raise ValueError(f"Module {module} already registered") + else: + self.module_logger[module] = ModuleLogger( + self.output_path, + self.experiment_name, + module, + self.step_write_frequency, + self.episode_write_frequency, + ) + if self.env is not None: + self.module_logger[module].set_env(self.env) + + return self.module_logger[module] + + def add_agent(self, agent: AbstractDACBenchAgent): + """ + Writes information about the agent + Parameters + ---------- + agent: AbstractDACBenchAgent + + Returns + ------- + """ + agent_config = {"type": str(agent.__class__)} + with open(self.log_dir / "agent.json", "w") as f: + json.dump(agent_config, f) + + def add_benchmark(self, benchmark: AbstractBenchmark) -> None: + """ + Writes the config to the experiment path + Parameters + ---------- + benchmark + + Returns + ------- + + """ + benchmark.save_config(self.log_dir / "benchmark.json") + + def set_additional_info(self, **kwargs): + for _, module_logger in self.module_logger.items(): + module_logger.set_additional_info(**kwargs) + + def log(self, key, value, module): + if module not in self.module_logger: + raise ValueError(f"Module {module} not registered yet") + self.module_logger.log(key, value) + + def log_space(self, key, value, module, space_info=None): + if module not in self.module_logger: + raise ValueError(f"Module {module} not registered yet") + self.module_logger.log_space(key, value, space_info) + + def log_dict(self, data, module): + if module not in self.module_logger: + raise ValueError(f"Module {module} not registered yet") + self.module_logger.log_space(data) diff --git a/build/lib/dacbench/plotting.py b/build/lib/dacbench/plotting.py new file mode 100644 index 000000000..031685e42 --- /dev/null +++ b/build/lib/dacbench/plotting.py @@ -0,0 +1,557 @@ +from typing import List, Tuple + +import numpy as np +import seaborn as sns +import pandas as pd + +sns.set_style("darkgrid") + + +def space_sep_upper(column_name: str) -> str: + """ + Separates strings at underscores into headings. + Used to generate labels from logging names. + + Parameters + ---------- + column_name : str + + Returns + ------- + str + """ + if column_name is None: + return None + return column_name.title().replace("_", " ") + + +def generate_global_step( + data: pd.DataFrame, + x_column: str = "global_step", + x_label_columns: str = ["episode", "step"], +) -> Tuple[pd.DataFrame, str, List[str]]: + """ + Add a global_step column which enumerate all step over all episodes. + + Returns the altered data, a data frame containing mapping between global_step, x_column and x_label_columns. + + Often used in combination with add_multi_level_ticks. + + Parameters + ---------- + data: + x_column: str + the name of the global_step (default 'global_step') + x_label_columns: [str, ...] + the name and hierarchical order of the columns (default ['episode', 'step'] + + Returns + ------- + (data, plot_index, x_column, x_label_columns) + """ + plot_index = ( + data.groupby(x_label_columns) + .count() + .reset_index()[x_label_columns] + .sort_values(x_label_columns) + ) + plot_index[x_column] = np.arange(len(plot_index)) + plot_index.set_index(x_column) + data = data.merge(plot_index, on=x_label_columns) + return data, plot_index, x_column, x_label_columns + + +def add_multi_level_ticks( + grid: sns.FacetGrid, plot_index: pd.DataFrame, x_column: str, x_label_columns: str +) -> None: + """ + Expects a FacedGrid with global_step (x_column) as x-axis and replaces the tick labels to match format episode:step + + E.g. Run with 3 episodes, each of 10 steps. This results in 30 global steps. + The resulting tick labels could be ['0', '4', '9', '14', '19', '24', '29']. + After applying this method they will look like ['0:0', '0:4', '1:0', '1:4', '2:0', '2:4', '3:0', '3:4'] + + Parameters + ---------- + grid: sns.FacesGrid + + plot_index: pd.DataFrame + The mapping between current tick labels (global step values) and new tick labels joined by ':'. + usually the result from generate_global_step + x_column: str + column label to use for looking up tick values + x_label_columns: [str, ...] + columns labels of columns to use for new labels (joined by ':' + + Returns + ------- + + """ + for ax in grid.axes.flat: + ticks = ax.get_xticks() + sub_set = plot_index[plot_index[x_column].isin(ticks)] + new_labels = ( + sub_set.loc[tick][x_label_columns].tolist() + if tick in sub_set.index + else (None, None) + for tick in ticks + ) + new_labels = [ + f"{epoch}:{step}" if epoch is not None else "" for epoch, step in new_labels + ] + ax.set_xticklabels(new_labels, minor=False) + + +def plot( + plot_function, + settings: dict, + title: str = None, + x_label: str = None, + y_label: str = None, + **kwargs, +) -> sns.FacetGrid: + """ + Helper function that: create a FacetGrid + 1. Updates settings with kwargs (overwrites values) + 2. Plots using plot_function(**settings) + 3. Set x and y labels of not provided the columns names will converted to pretty strings using space_sep_upper + 4. Sets title (some times has to be readjusted afterwards especially in case of large plots e.g. multiple rows/cols) + + Parameters + ---------- + plot_function: + function to generate the FacedGrid. E.g. sns.catplot or sns.catplot + settings: dict + a dicts containing all needed default settings. + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + + """ + settings.update(kwargs.items()) # 1. + grid = plot_function(**settings) # 2. + + # 3. + x_label = space_sep_upper(grid._x_var) if x_label is None else x_label + y_label = space_sep_upper(grid._y_var) if y_label is None else y_label + grid.set_xlabels(x_label) + grid.set_ylabels(y_label) + + # 4. + grid.tight_layout() + if title is not None: + grid.fig.suptitle(title, y=0.97) # rule of thumb. Has to be improved in future + grid.fig.subplots_adjust(top=0.9) + + return grid + + +def plot_performance( + data, title=None, x_label=None, y_label=None, **kwargs +) -> sns.FacetGrid: + """ + Create a line plot of the performance over episodes. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to examples/plotting/performance_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + settings = { + "data": data, + "x": "episode", + "y": "overall_performance", + "kind": "line", + } + grid = plot(sns.relplot, settings, title, x_label, y_label, **kwargs) + + return grid + + +def plot_performance_per_instance( + data, title=None, x_label=None, y_label=None, **args +) -> sns.FacetGrid: + """ + Create a bar plot of the mean performance per instance ordered by the performance. + + Per default the mean performance seeds is shown if you want to change + this specify a property to map seed to e.g. col='seed'. + For more details see: https://seaborn.pydata.org/generated/seaborn.catplot.html + + For examples refer to examples/plotting/performance_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + # order the columns by mean instance + order = data.groupby("instance").mean().sort_values("overall_performance").index + settings = { + "data": data, + "x": "instance", + "y": "overall_performance", + "order": order, + "kind": "bar", + } + grid = plot(sns.catplot, settings, title, x_label, y_label, **args) + # todo: should probably not always be set like this (multi row/col) + grid.set_titles("Mean Performance per Instance") + return grid + + +def plot_step_time( + data, + show_global_step=False, + interval=1, + title=None, + x_label=None, + y_label=None, + **args, +) -> sns.FacetGrid: + """ + Create a line plot showing the measured time per step. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to examples/plotting/time_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + show_global_step: bool + If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) + interval: int + Interval in number of steps to average over. (default = 1) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + multi_level_x_label = "Epoch:Step" + data, plot_index, x_column, x_label_columns = generate_global_step(data) + if interval > 1: + data["groups"] = data[x_column] // interval + data = data.groupby("groups").agg({x_column: "min", "step_duration": "mean"}) + y_label = ( + f"Mean per duration per {interval} steps" if y_label is None else y_label + ) + + settings = { + "data": data, + "x": x_column, + "y": "step_duration", + "kind": "line", + } + if x_label is None and not show_global_step: + x_label = multi_level_x_label + + grid = plot(sns.relplot, settings, title, x_label, y_label, **args) + if not show_global_step: + add_multi_level_ticks(grid, plot_index, x_column, x_label_columns) + + return grid + + +def plot_episode_time( + data, title=None, x_label=None, y_label=None, **kargs +) -> sns.FacetGrid: + """ + Create a line plot showing the measured time per episode. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to examples/plotting/time_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + settings = { + "data": data, + "x": "episode", + "y": "episode_duration", + "kind": "line", + } + + grid = plot(sns.relplot, settings, title, x_label, y_label, **kargs) + + return grid + + +def plot_action( + data, + show_global_step=False, + interval=1, + title=None, + x_label=None, + y_label=None, + **kargs, +): + """ + Create a line plot showing actions over time. + + Please be aware that action spaces can be quite large and the plots can become quite messy (and take some time) + if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the + plot method. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to examples/plotting/action_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + show_global_step: bool + If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) + interval: int + Interval in number of steps to average over. (default = 1) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + + return plot_space( + data, "action", show_global_step, interval, title, x_label, y_label, **kargs + ) + + +def plot_state( + data, + show_global_step=False, + interval=1, + title=None, + x_label=None, + y_label=None, + **kargs, +): + """ + Create a line plot showing state over time. + + Please be aware that state can be quite large and the plots can become quite messy (and take some time) + if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the + plot method. Especially for dict state spaces. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to examples/plotting/state_plotting.py + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + show_global_step: bool + If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) + interval: int + Interval in number of steps to average over. (default = 1) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + return plot_space( + data, "state", show_global_step, interval, title, x_label, y_label, **kargs + ) + + +def plot_space( + data, + space_column_name, + show_global_step, + interval=1, + title=None, + x_label=None, + y_label=None, + **args, +) -> sns.FacetGrid: + """ + Create a line plot showing sapce over time. + + Please be aware that spaces can be quite large and the plots can become quite messy (and take some time) + if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the + plot method. Especially for dict spaces. + + Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change + this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. + For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html + + For examples refer to + examples/plotting/state_plotting.py or + examples/plotting/action_plotting.py + + + Parameters + ---------- + data: pd.DataFrame + Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + show_global_step: bool + If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) + interval: int + Interval in number of steps to average over. (default = 1) + title: str + Title of the plot (optional) + x_label: str + Label of the x-axis (optional) + y_label: str + Label of the y-axis (optional) + kwargs: + Keyword arguments to overwrite default settings. + + Returns + ------- + sns.FacedGrid + """ + # first find columns with prefix space_column_name + space_entries = list( + filter(lambda col: col.startswith(space_column_name), data.columns) + ) + number_of_space_entries = len(space_entries) + y_label_name = space_column_name + + if number_of_space_entries > 1: + # if we have more than one space dims we reshape the dataframe in order to be able to control the plots behavior + # per dimension + data = pd.wide_to_long( + data, + stubnames=[space_column_name], + sep="_", + i=["episode", "step", "instance"] + + (["seed"] if "seed" in data.columns else []), + j="i", + suffix=".*", + ).reset_index() + elif number_of_space_entries == 1 and space_column_name not in data.columns: + # Of there is only one dimension but the name is odd + space_column_name, *_ = space_entries + + data, plot_index, x_column, x_label_columns = generate_global_step(data) + + # perform averaging over intervals + if interval > 1: + data["interval"] = data[x_column] // interval + group_columns = list( + data.columns.drop(x_label_columns + [x_column, space_column_name]) + ) + data = data.groupby(group_columns).agg( + {x_column: "min", space_column_name: "mean"} + ) + y_label = ( + f"Mean {y_label_name} per {interval} steps" if y_label is None else y_label + ) + data = data.reset_index() + + settings = { + "data": data, + "x": x_column, + "y": space_column_name, + "kind": "line", + } + + # we want the different dims in different plots / columns + # todo: refactor + if number_of_space_entries > 1: + settings["col"] = "i" + if number_of_space_entries > 3: + settings["col_wrap"] = 3 + + if "instance" in data.columns: + settings["hue"] = "instance" + + if x_label is None: + x_label = None if show_global_step else "Epoch:Step" + + if y_label is None: + y_label = y_label_name + + grid = plot(sns.relplot, settings, title, x_label, y_label, **args) + if not show_global_step: + add_multi_level_ticks(grid, plot_index, x_column, x_label_columns) + + return grid diff --git a/build/lib/dacbench/run_baselines.py b/build/lib/dacbench/run_baselines.py new file mode 100644 index 000000000..2e598eabb --- /dev/null +++ b/build/lib/dacbench/run_baselines.py @@ -0,0 +1,248 @@ +import argparse +import itertools +import sys +from pathlib import Path + +import numpy as np + +from dacbench import benchmarks +from dacbench.agents import StaticAgent, GenericAgent, DynamicRandomAgent +from dacbench.envs.policies import OPTIMAL_POLICIES, NON_OPTIMAL_POLICIES +from dacbench.logger import Logger +from dacbench.runner import run_benchmark +from dacbench.wrappers import PerformanceTrackingWrapper + +modea_actions = [ + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(2), + np.arange(3), + np.arange(3), +] +DISCRETE_ACTIONS = { + "SigmoidBenchmark": np.arange(int(np.prod((5, 10)))), + "LubyBenchmark": np.arange(6), + "FastDownwardBenchmark": [0, 1], + "CMAESBenchmark": [np.around(a, decimals=1) for a in np.linspace(0.2, 10, num=50)], + "ModeaBenchmark": list(itertools.product(*modea_actions)), + "SGDBenchmark": [np.around(a, decimals=1) for a in np.linspace(0, 10, num=50)], +} + + +def run_random(results_path, benchmark_name, num_episodes, seeds, fixed): + bench = getattr(benchmarks, benchmark_name)() + for s in seeds: + if fixed > 1: + experiment_name = f"random_fixed{fixed}_{s}" + else: + experiment_name = f"random_{s}" + logger = Logger( + experiment_name=experiment_name, output_path=results_path / benchmark_name + ) + env = bench.get_benchmark(seed=s) + env = PerformanceTrackingWrapper( + env, logger=logger.add_module(PerformanceTrackingWrapper) + ) + agent = DynamicRandomAgent(env, fixed) + + logger.add_agent(agent) + logger.add_benchmark(bench) + logger.set_env(env) + + run_benchmark(env, agent, num_episodes, logger) + + logger.close() + + +def run_static(results_path, benchmark_name, action, num_episodes, seeds=np.arange(10)): + bench = getattr(benchmarks, benchmark_name)() + for s in seeds: + logger = Logger( + experiment_name=f"static_{action}_{s}", + output_path=results_path / benchmark_name, + ) + env = bench.get_benchmark(seed=s) + env = PerformanceTrackingWrapper( + env, logger=logger.add_module(PerformanceTrackingWrapper) + ) + agent = StaticAgent(env, action) + + logger.add_agent(agent) + logger.add_benchmark(bench) + logger.set_env(env) + logger.set_additional_info(action=action) + + run_benchmark(env, agent, num_episodes, logger) + + logger.close() + + +def run_optimal(results_path, benchmark_name, num_episodes, seeds): + if benchmark_name not in OPTIMAL_POLICIES: + print("No optimal policy found for this benchmark") + return + policy = OPTIMAL_POLICIES[benchmark_name] + run_policy(results_path, benchmark_name, num_episodes, policy, seeds) + + +def run_dynamic_policy(results_path, benchmark_name, num_episodes, seeds=np.arange(10)): + if benchmark_name not in NON_OPTIMAL_POLICIES: + print("No dynamic policy found for this benchmark") + policy = NON_OPTIMAL_POLICIES[benchmark_name] + run_policy(results_path, benchmark_name, num_episodes, policy, seeds) + + +def run_policy(results_path, benchmark_name, num_episodes, policy, seeds=np.arange(10)): + bench = getattr(benchmarks, benchmark_name)() + + for s in seeds: + if benchmark_name == "CMAESBenchmark": + experiment_name = f"csa_{s}" + else: + experiment_name = f"optimal_{s}" + logger = Logger( + experiment_name=experiment_name, output_path=results_path / benchmark_name + ) + + env = bench.get_benchmark(seed=s) + env = PerformanceTrackingWrapper( + env, logger=logger.add_module(PerformanceTrackingWrapper) + ) + agent = GenericAgent(env, policy) + + logger.add_agent(agent) + logger.add_benchmark(bench) + logger.set_env(env) + + run_benchmark(env, agent, num_episodes, logger) + + logger.close() + + +def main(args): + parser = argparse.ArgumentParser( + description="Run simple baselines for DAC benchmarks", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + parser.add_argument("--outdir", type=str, default="output", help="Output directory") + parser.add_argument( + "--benchmarks", + nargs="+", + type=str, + choices=benchmarks.__all__, + default=None, + help="Benchmarks to run baselines for, if not provides all benchmarks are run.", + ) + parser.add_argument( + "--num_episodes", + type=int, + default=10, + help="Number of episodes to evaluate policy on", + ) + parser.add_argument( + "--random", + action="store_true", + help="Run random policy. Use '--fixed_random' to fix the " + "random action for a number of steps", + ) + parser.add_argument("--static", action="store_true", help="Run static policy") + + parser.add_argument( + "--optimal", + action="store_true", + help=f"Run optimal policy. Only available for {', '.join(OPTIMAL_POLICIES.keys())}", + ) + parser.add_argument( + "--dyna_baseline", + action="store_true", + help=f"Run dynamic baseline. Only available for {', '.join(NON_OPTIMAL_POLICIES.keys())}", + ) + + shortened_possible_actions = { + benchmark: ", ".join( + ( + map(str, actions) + if len(actions) < 4 + else map(str, [*actions[:3], "...", actions[-1]]) + ) + ) + for benchmark, actions in DISCRETE_ACTIONS.items() + } + + possible_actions = ", ".join( + [ + f"{benchmark} : {actions}" + for benchmark, actions in shortened_possible_actions.items() + ] + ) + parser.add_argument( + "--actions", + nargs="+", + type=float, + default=None, + help="Action(s) for static policy. Make sure, that the actions correspond to the benchmarks. Available action " + f"are {possible_actions}", + ) + parser.add_argument( + "--seeds", + nargs="+", + type=int, + default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + help="Seeds for evaluation", + ) + parser.add_argument( + "--fixed_random", + type=int, + default=0, + help="Fixes random actions for n steps", + ) + args = parser.parse_args(args) + + if args.benchmarks is None: + benchs = benchmarks.__all__ + else: + benchs = args.benchmarks + + args.outdir = Path(args.outdir) + + if args.random: + for b in benchs: + run_random(args.outdir, b, args.num_episodes, args.seeds, args.fixed_random) + + if args.static: + for b in benchs: + + if args.actions is None: + actions = DISCRETE_ACTIONS[b] + else: + actions = args.actions + if b == "FastDownwardBenchmark": + actions = [int(a) for a in actions] + for a in actions: + run_static(args.outdir, b, a, args.num_episodes, args.seeds) + + if args.optimal: + for b in benchs: + if b not in OPTIMAL_POLICIES: + print("Option not available!") + break + + run_optimal(args.outdir, b, args.num_episodes, args.seeds) + + if args.dyna_baseline: + for b in benchs: + if b not in NON_OPTIMAL_POLICIES: + print("Option not available!") + break + + run_dynamic_policy(args.outdir, b, args.num_episodes, args.seeds) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/build/lib/dacbench/runner.py b/build/lib/dacbench/runner.py new file mode 100644 index 000000000..058d00d6b --- /dev/null +++ b/build/lib/dacbench/runner.py @@ -0,0 +1,94 @@ +from dacbench import benchmarks +from dacbench.wrappers import PerformanceTrackingWrapper +from dacbench.logger import Logger +import seaborn as sb +from pathlib import Path + +sb.set_style("darkgrid") +current_palette = list(sb.color_palette()) + + +def run_benchmark(env, agent, num_episodes, logger=None): + """ + Run single benchmark env for a given number of episodes with a given agent + + Parameters + ------- + env : gym.Env + Benchmark environment + agent + Any agent implementing the methods act, train and end_episode (see AbstractDACBenchAgent below) + num_episodes : int + Number of episodes to run + logger : dacbench.logger.Logger: logger to use for logging. Not closed automatically like env + """ + if logger is not None: + logger.reset_episode() + logger.set_env(env) + + for _ in range(num_episodes): + state = env.reset() + done = False + reward = 0 + while not done: + action = agent.act(state, reward) + next_state, reward, done, _ = env.step(action) + agent.train(next_state, reward) + state = next_state + if logger is not None: + logger.next_step() + agent.end_episode(state, reward) + + if logger is not None: + logger.next_episode() + env.close() + + +def run_dacbench(results_path, agent_method, num_episodes, bench=None, seeds=None): + """ + Run all benchmarks for 10 seeds for a given number of episodes with a given agent and save result + + Parameters + ------- + bench + results_path : str + Path to where results should be saved + agent_method : function + Method that takes an env as input and returns an agent + num_episodes : int + Number of episodes to run for each benchmark + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + """ + + if bench is None: + bench = map(benchmarks.__dict__.get, benchmarks.__all__) + else: + bench = [getattr(benchmarks, b) for b in bench] + + seeds = seeds if seeds is not None else range(10) + for b in bench: + print(f"Evaluating {b.__name__}") + for i in seeds: + print(f"Seed {i}/10") + bench = b() + try: + env = bench.get_benchmark(seed=i) + except: + continue + + logger = Logger( + experiment_name=f"seed_{i}", + output_path=Path(results_path) / f"{b.__name__}", + ) + perf_logger = logger.add_module(PerformanceTrackingWrapper) + logger.add_benchmark(bench) + logger.set_env(env) + + env = PerformanceTrackingWrapper(env, logger=perf_logger) + agent = agent_method(env) + logger.add_agent(agent) + + run_benchmark(env, agent, num_episodes, logger) + + logger.close() diff --git a/build/lib/dacbench/wrappers/__init__.py b/build/lib/dacbench/wrappers/__init__.py new file mode 100644 index 000000000..34d37d966 --- /dev/null +++ b/build/lib/dacbench/wrappers/__init__.py @@ -0,0 +1,20 @@ +from dacbench.wrappers.action_tracking_wrapper import ActionFrequencyWrapper +from dacbench.wrappers.episode_time_tracker import EpisodeTimeWrapper +from dacbench.wrappers.instance_sampling_wrapper import InstanceSamplingWrapper +from dacbench.wrappers.policy_progress_wrapper import PolicyProgressWrapper +from dacbench.wrappers.reward_noise_wrapper import RewardNoiseWrapper +from dacbench.wrappers.state_tracking_wrapper import StateTrackingWrapper +from dacbench.wrappers.performance_tracking_wrapper import PerformanceTrackingWrapper +from dacbench.wrappers.observation_wrapper import ObservationWrapper + +__all__ = [ + "ActionFrequencyWrapper", + "EpisodeTimeWrapper", + "InstanceSamplingWrapper", + "PolicyProgressWrapper", + "RewardNoiseWrapper", + "StateTrackingWrapper", + "PerformanceTrackingWrapper", + "PolicyProgressWrapper", + "ObservationWrapper", +] diff --git a/build/lib/dacbench/wrappers/action_tracking_wrapper.py b/build/lib/dacbench/wrappers/action_tracking_wrapper.py new file mode 100644 index 000000000..9963a58d0 --- /dev/null +++ b/build/lib/dacbench/wrappers/action_tracking_wrapper.py @@ -0,0 +1,259 @@ +import matplotlib.pyplot as plt +import numpy as np +import seaborn as sb +from gymnasium import Wrapper +from gymnasium import spaces +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas + +sb.set_style("darkgrid") +current_palette = list(sb.color_palette()) + + +class ActionFrequencyWrapper(Wrapper): + """ + Wrapper to action frequency. + Includes interval mode that returns frequencies in lists of len(interval) instead of one long list. + """ + + def __init__(self, env, action_interval=None, logger=None): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + action_interval : int + If not none, mean in given intervals is tracked, too + logger: logger.ModuleLogger + """ + super(ActionFrequencyWrapper, self).__init__(env) + self.action_interval = action_interval + self.overall_actions = [] + if self.action_interval: + self.action_intervals = [] + self.current_actions = [] + self.action_space_type = type(self.env.action_space) + self.logger = logger + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in [ + "action_interval", + "overall_actions", + "action_intervals", + "current_actions", + "env", + "get_actions", + "step", + "render_action_tracking", + "logger", + ]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in [ + "action_interval", + "overall_actions", + "action_intervals", + "current_actions", + "env", + "get_actions", + "step", + "render_action_tracking", + "logger", + ]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and record state + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + self.overall_actions.append(action) + if self.logger is not None: + self.logger.log_space("action", action) + + if self.action_interval: + if len(self.current_actions) < self.action_interval: + self.current_actions.append(action) + else: + self.action_intervals.append(self.current_actions) + self.current_actions = [action] + return state, reward, terminated, truncated, info + + def get_actions(self): + """ + Get state progression + + Returns + ------- + np.array or np.array, np.array + all states or all states and interval sorted states + + """ + if self.action_interval: + complete_intervals = self.action_intervals + [self.current_actions] + return self.overall_actions, complete_intervals + + else: + return self.overall_actions + + def render_action_tracking(self): + """ + Render action progression + + Returns + ------- + np.array + RBG data of action tracking + + """ + + def plot_single(ax=None, index=None, title=None, x=False, y=False): + if ax is None: + plt.xlabel("Step") + plt.ylabel("Action value") + elif x and y: + ax.set_ylabel("Action value") + ax.set_xlabel("Step") + elif x: + ax.set_xlabel("Step") + elif y: + ax.set_ylabel("Action value") + + if index is not None: + ys = [state[index] for state in self.overall_actions] + else: + ys = self.overall_actions + + if ax is None: + p = plt.plot( + np.arange(len(self.overall_actions)), + ys, + label="Step actions", + color="g", + ) + else: + p = ax.plot( + np.arange(len(self.overall_actions)), + ys, + label="Step actions", + color="g", + ) + p2 = None + if self.action_interval: + if index is not None: + y_ints = [] + for interval in self.action_intervals: + y_ints.append([state[index] for state in interval]) + else: + y_ints = self.action_intervals + if ax is None: + p2 = plt.plot( + np.arange(len(self.action_intervals)) * self.action_interval, + [np.mean(interval) for interval in y_ints], + label="Mean interval action", + color="orange", + ) + plt.legend(loc="upper left") + else: + p2 = ax.plot( + np.arange(len(self.action_intervals)) * self.action_interval, + [np.mean(interval) for interval in y_ints], + label="Mean interval action", + color="orange", + ) + ax.legend(loc="upper left") + return p, p2 + + if self.action_space_type == spaces.Discrete: + figure = plt.figure(figsize=(12, 6)) + canvas = FigureCanvas(figure) + p, p2 = plot_single() + canvas.draw() + elif self.action_space_type == spaces.Dict: + raise NotImplementedError + + elif self.action_space_type == spaces.Tuple: + raise NotImplementedError + + elif ( + self.action_space_type == spaces.MultiDiscrete + or self.action_space_type == spaces.MultiBinary + or self.action_space_type == spaces.Box + ): + if self.action_space_type == spaces.MultiDiscrete: + action_size = len(self.env.action_space.nvec) + elif self.action_space_type == spaces.MultiBinary: + action_size = self.env.action_space.n + else: + action_size = len(self.env.action_space.high) + + if action_size == 1: + figure = plt.figure(figsize=(12, 6)) + canvas = FigureCanvas(figure) + p, p2 = plot_single() + elif action_size < 5: + dim = 1 + figure, axarr = plt.subplots(action_size) + else: + dim = action_size % 4 + figure, axarr = plt.subplots(action_size % 4, action_size // dim) + figure.suptitle("State over time") + canvas = FigureCanvas(figure) + for i in range(action_size): + if action_size == 1: + continue + + x = False + if i % dim == dim - 1: + x = True + if action_size < 5: + p, p2 = plot_single(axarr[i], i, y=True, x=x) + else: + y = i % action_size // dim == 0 + p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) + canvas.draw() + width, height = figure.get_size_inches() * figure.get_dpi() + img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( + int(height), int(width), 3 + ) + return img diff --git a/build/lib/dacbench/wrappers/episode_time_tracker.py b/build/lib/dacbench/wrappers/episode_time_tracker.py new file mode 100644 index 000000000..bab927cee --- /dev/null +++ b/build/lib/dacbench/wrappers/episode_time_tracker.py @@ -0,0 +1,243 @@ +from gymnasium import Wrapper +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +import time +import seaborn as sb + +sb.set_style("darkgrid") +current_palette = list(sb.color_palette()) + + +class EpisodeTimeWrapper(Wrapper): + """ + Wrapper to track time spent per episode. + Includes interval mode that returns times in lists of len(interval) instead of one long list. + """ + + def __init__(self, env, time_interval=None, logger=None): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + time_interval : int + If not none, mean in given intervals is tracked, too + logger : dacbench.logger.ModuleLogger + """ + super(EpisodeTimeWrapper, self).__init__(env) + self.time_interval = time_interval + self.all_steps = [] + if self.time_interval: + self.step_intervals = [] + self.current_step_interval = [] + self.overall_times = [] + self.episode = [] + if self.time_interval: + self.time_intervals = [] + self.current_times = [] + + self.logger = logger + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in [ + "time_interval", + "overall_times", + "time_intervals", + "current_times", + "env", + "get_times", + "step", + "render_step_time", + "render_episode_time", + "reset", + "episode", + "all_steps", + "current_step_interval", + "step_intervals", + "logger", + ]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in [ + "time_interval", + "overall_times", + "time_intervals", + "current_times", + "env", + "get_times", + "step", + "render_step_time", + "render_episode_time", + "reset", + "episode", + "all_steps", + "current_step_interval", + "step_intervals", + "logger", + ]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and record time + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo + """ + start = time.time() + state, reward, terminated, truncated, info = self.env.step(action) + stop = time.time() + duration = stop - start + self.episode.append(duration) + self.all_steps.append(duration) + + if self.logger is not None: + self.logger.log("step_duration", duration) + + if self.time_interval: + if len(self.current_step_interval) < self.time_interval: + self.current_step_interval.append(duration) + else: + self.step_intervals.append(self.current_step_interval) + self.current_step_interval = [duration] + if terminated or truncated: + self.overall_times.append(self.episode) + if self.logger is not None: + self.logger.log("episode_duration", sum(self.episode)) + + if self.time_interval: + if len(self.current_times) < self.time_interval: + self.current_times.append(self.episode) + else: + self.time_intervals.append(self.current_times) + self.current_times = [] + self.episode = [] + return state, reward, terminated, truncated, info + + def get_times(self): + """ + Get times + + Returns + ------- + np.array or np.array, np.array + all times or all times and interval sorted times + + """ + if self.time_interval: + complete_intervals = self.time_intervals + [self.current_times] + complete_step_intervals = self.step_intervals + [self.current_step_interval] + return ( + self.overall_times, + self.all_steps, + complete_intervals, + complete_step_intervals, + ) + + else: + return np.array(self.overall_times), np.array(self.all_steps) + + def render_step_time(self): + """Render step times""" + figure = plt.figure(figsize=(12, 6)) + canvas = FigureCanvas(figure) + plt.title("Time per Step") + plt.xlabel("Step") + plt.ylabel("Time (s)") + + plt.plot( + np.arange(len(self.all_steps)), self.all_steps, label="Step time", color="g" + ) + if self.time_interval: + interval_means = [np.mean(interval) for interval in self.step_intervals] + [ + np.mean(self.current_step_interval) + ] + plt.plot( + np.arange(len(self.step_intervals) + 2) * self.time_interval, + [interval_means[0]] + interval_means, + label="Mean interval time", + color="orange", + ) + plt.legend(loc="upper right") + canvas.draw() + width, height = figure.get_size_inches() * figure.get_dpi() + img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( + int(height), int(width), 3 + ) + # plt.close(figure) + return img + + def render_episode_time(self): + """Render episode times""" + figure = plt.figure(figsize=(12, 6)) + canvas = FigureCanvas(figure) + plt.title("Time per Episode") + plt.xlabel("Episode") + plt.ylabel("Time (s)") + + plt.plot( + np.arange(len(self.overall_times)), + [sum(episode) for episode in self.overall_times], + label="Episode time", + color="g", + ) + if self.time_interval: + interval_sums = [] + for interval in self.time_intervals: + ep_times = [] + for episode in interval: + ep_times.append(sum(episode)) + interval_sums.append(np.mean(ep_times)) + interval_sums += [np.mean([sum(episode) for episode in self.current_times])] + plt.plot( + np.arange(len(self.time_intervals) + 2) * self.time_interval, + [interval_sums[0]] + interval_sums, + label="Mean interval time", + color="orange", + ) + plt.legend(loc="upper right") + canvas.draw() + width, height = figure.get_size_inches() * figure.get_dpi() + img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( + int(height), int(width), 3 + ) + return img diff --git a/build/lib/dacbench/wrappers/instance_sampling_wrapper.py b/build/lib/dacbench/wrappers/instance_sampling_wrapper.py new file mode 100644 index 000000000..72a66f707 --- /dev/null +++ b/build/lib/dacbench/wrappers/instance_sampling_wrapper.py @@ -0,0 +1,112 @@ +from gym import Wrapper +import numpy as np +from scipy.stats import norm + + +class InstanceSamplingWrapper(Wrapper): + """ + Wrapper to sample a new instance at a given time point. + Instances can either be sampled using a given method or a distribution infered from a given list of instances. + """ + + def __init__(self, env, sampling_function=None, instances=None, reset_interval=0): + """ + Initialize wrapper + Either sampling_function or instances must be given + + Parameters + ------- + env : gym.Env + Environment to wrap + sampling_function : function + Function to sample instances from + instances : list + List of instances to infer distribution from + """ + super(InstanceSamplingWrapper, self).__init__(env) + if sampling_function: + self.sampling_function = sampling_function + elif instances: + self.sampling_function = self.fit_dist(instances) + else: + raise Exception("No distribution to sample from given") + self.reset_interval = reset_interval + self.reset_tracker = 0 + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in ["sampling_function", "env", "fit_dist", "reset"]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in ["sampling_function", "env", "fit_dist", "reset"]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def reset(self): + """ + Reset environment and use sampled instance for training + + Returns + ------- + np.array + state + """ + if self.reset_tracker >= self.reset_interval: + instance = self.sampling_function() + self.env.use_next_instance(instance=instance) + return self.env.reset() + + def fit_dist(self, instances): + """ + Approximate instance distribution in given instance set + + Parameters + ---------- + instances : List + instance set + + Returns + --------- + method + sampling method for new instances + """ + dists = [] + for i in range(len(instances[0])): + component = [instances[k][i] for k in instances.keys()] + dist = norm.fit(component) + dists.append(dist) + + def sample(): + instance = [] + for d in dists: + instance.append(np.random.normal(d[0], d[1])) + return instance + + return sample diff --git a/build/lib/dacbench/wrappers/observation_wrapper.py b/build/lib/dacbench/wrappers/observation_wrapper.py new file mode 100644 index 000000000..57d8e27fe --- /dev/null +++ b/build/lib/dacbench/wrappers/observation_wrapper.py @@ -0,0 +1,106 @@ +from collections.abc import Iterable + +from gym import Wrapper, spaces +import numpy as np + + +class ObservationWrapper(Wrapper): + """ + Wrapper covert observations spaces to spaces.Box for convenience + Currently only supports Dict -> Box + """ + + def __init__(self, env): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + compute_optimal : function + Function to compute optimal policy + """ + super(ObservationWrapper, self).__init__(env) + obs_sample = self.flatten(self.env.observation_space.sample()) + size = len(obs_sample) + self.observation_space = spaces.Box( + low=-np.inf * np.ones(size), high=np.inf * np.ones(size) + ) + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in ["observation_space", "step", "env", "flatten", "reset"]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in ["observation_space", "step", "env", "flatten", "reset"]: + return object.__getattribute__(self, name) + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and record distance + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + state = self.flatten(state) + return state, reward, terminated, truncated, info + + def reset(self): + """ + Execute environment step and record distance + + Returns + ------- + np.array, dict + state, info + """ + state, info = self.env.reset() + state = self.flatten(state) + return state, info + + def flatten(self, state_dict): + keys = sorted(list(state_dict.keys())) + values = [] + for k in keys: + if isinstance(state_dict[k], np.ndarray): + for s in state_dict[k]: + values.append(s) + else: + values.append(state_dict[k]) + return np.array(values).astype(np.float32) diff --git a/build/lib/dacbench/wrappers/performance_tracking_wrapper.py b/build/lib/dacbench/wrappers/performance_tracking_wrapper.py new file mode 100644 index 000000000..187e22e85 --- /dev/null +++ b/build/lib/dacbench/wrappers/performance_tracking_wrapper.py @@ -0,0 +1,204 @@ +from collections import defaultdict + +from gym import Wrapper +import matplotlib.pyplot as plt +import numpy as np +import seaborn as sb + +sb.set_style("darkgrid") +current_palette = list(sb.color_palette()) + + +class PerformanceTrackingWrapper(Wrapper): + """ + Wrapper to track episode performance. + Includes interval mode that returns performance in lists of len(interval) instead of one long list. + """ + + def __init__( + self, + env, + performance_interval=None, + track_instance_performance=True, + logger=None, + ): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + performance_interval : int + If not none, mean in given intervals is tracked, too + track_instance_performance : bool + Indicates whether to track per-instance performance + logger : dacbench.logger.ModuleLogger + """ + super(PerformanceTrackingWrapper, self).__init__(env) + self.performance_interval = performance_interval + self.overall_performance = [] + self.episode_performance = 0 + if self.performance_interval: + self.performance_intervals = [] + self.current_performance = [] + self.track_instances = track_instance_performance + if self.track_instances: + self.instance_performances = defaultdict(lambda: []) + + self.logger = logger + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in [ + "performance_interval", + "track_instances", + "overall_performance", + "performance_intervals", + "current_performance", + "env", + "get_performance", + "step", + "instance_performances", + "episode_performance", + "render_performance", + "render_instance_performance", + "logger", + ]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in [ + "performance_interval", + "track_instances", + "overall_performance", + "performance_intervals", + "current_performance", + "env", + "get_performance", + "step", + "instance_performances", + "episode_performance", + "render_performance", + "render_instance_performance", + "logger", + ]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and record performance + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + self.episode_performance += reward + + if terminated or truncated: + self.overall_performance.append(self.episode_performance) + if self.logger is not None: + self.logger.log( + "overall_performance", + self.episode_performance, + ) + + if self.performance_interval: + if len(self.current_performance) < self.performance_interval: + self.current_performance.append(self.episode_performance) + else: + self.performance_intervals.append(self.current_performance) + self.current_performance = [self.episode_performance] + if self.track_instances: + key = "".join(str(e) for e in self.env.instance) + self.instance_performances[key].append(self.episode_performance) + self.episode_performance = 0 + return state, reward, terminated, truncated, info + + def get_performance(self): + """ + Get state performance + + Returns + ------- + np.array or np.array, np.array or np.array, dict or np.array, np.arry, dict + all states or all states and interval sorted states + + """ + if self.performance_interval and self.track_instances: + complete_intervals = self.performance_intervals + [self.current_performance] + return ( + self.overall_performance, + complete_intervals, + self.instance_performances, + ) + + elif self.performance_interval: + complete_intervals = self.performance_intervals + [self.current_performance] + return self.overall_performance, complete_intervals + + elif self.track_instances: + return self.overall_performance, self.instance_performances + + else: + return self.overall_performance + + def render_performance(self): + """ Plot performance """ + plt.figure(figsize=(12, 6)) + plt.plot( + np.arange(len(self.overall_performance) // 2), + self.overall_performance[1::2], + ) + plt.title("Mean Performance per episode") + plt.xlabel("Episode") + plt.ylabel("Reward") + plt.show() + + def render_instance_performance(self): + """ Plot mean performance for each instance """ + plt.figure(figsize=(12, 6)) + plt.title("Mean Performance per Instance") + plt.ylabel("Mean reward") + plt.xlabel("Instance") + ax = plt.subplot(111) + for k, i in zip( + self.instance_performances.keys(), + np.arange(len(self.instance_performances.keys())), + ): + ax.bar(str(i), np.mean(self.instance_performances[k])) + plt.show() diff --git a/build/lib/dacbench/wrappers/policy_progress_wrapper.py b/build/lib/dacbench/wrappers/policy_progress_wrapper.py new file mode 100644 index 000000000..e8fcb6773 --- /dev/null +++ b/build/lib/dacbench/wrappers/policy_progress_wrapper.py @@ -0,0 +1,107 @@ +from gym import Wrapper +import matplotlib.pyplot as plt +import numpy as np + + +class PolicyProgressWrapper(Wrapper): + """ + Wrapper to track progress towards optimal policy. + Can only be used if a way to obtain the optimal policy given an instance can be obtained + """ + + def __init__(self, env, compute_optimal): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + compute_optimal : function + Function to compute optimal policy + """ + super(PolicyProgressWrapper, self).__init__(env) + self.compute_optimal = compute_optimal + self.episode = [] + self.policy_progress = [] + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in [ + "compute_optimal", + "env", + "episode", + "policy_progress", + "render_policy_progress", + ]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in [ + "step", + "compute_optimal", + "env", + "episode", + "policy_progress", + "render_policy_progress", + ]: + return object.__getattribute__(self, name) + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and record distance + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + self.episode.append(action) + if terminated or truncated: + optimal = self.compute_optimal(self.env.instance) + self.policy_progress.append( + np.linalg.norm(np.array(optimal) - np.array(self.episode)) + ) + self.episode = [] + return state, reward,terminated, truncated, info + + def render_policy_progress(self): + """ Plot progress """ + plt.figure(figsize=(12, 6)) + plt.plot(np.arange(len(self.policy_progress)), self.policy_progress) + plt.title("Policy progress over time") + plt.xlabel("Episode") + plt.ylabel("Distance to optimal policy") + plt.show() diff --git a/build/lib/dacbench/wrappers/reward_noise_wrapper.py b/build/lib/dacbench/wrappers/reward_noise_wrapper.py new file mode 100644 index 000000000..779482800 --- /dev/null +++ b/build/lib/dacbench/wrappers/reward_noise_wrapper.py @@ -0,0 +1,119 @@ +from gym import Wrapper +import numpy as np + + +class RewardNoiseWrapper(Wrapper): + """ + Wrapper to add noise to the reward signal. + Noise can be sampled from a custom distribution or any distribution in numpy's random module + """ + + def __init__( + self, env, noise_function=None, noise_dist="standard_normal", dist_args=None + ): + """ + Initialize wrapper + Either noise_function or noise_dist and dist_args need to be given + + Parameters + ------- + env : gym.Env + Environment to wrap + noise_function : function + Function to sample noise from + noise_dist : str + Name of distribution to sample noise from + dist_args : list + Arguments for noise distribution + """ + super(RewardNoiseWrapper, self).__init__(env) + + if noise_function: + self.noise_function = noise_function + elif noise_dist: + self.noise_function = self.add_noise(noise_dist, dist_args) + else: + raise Exception("No distribution to sample noise from given") + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in ["noise_function", "env", "add_noise", "step"]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in ["noise_function", "env", "add_noise", "step"]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def step(self, action): + """ + Execute environment step and add noise + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + reward += self.noise_function() + reward = max(self.env.reward_range[0], min(self.env.reward_range[1], reward)) + return state, reward, terminated, truncated, info + + def add_noise(self, dist, args): + """ + Make noise function from distribution name and arguments + + Parameters + ---------- + dist : str + Name of distribution + args : list + List of distribution arguments + + Returns + ------- + function + Noise sampling function + """ + rng = np.random.default_rng() + function = getattr(rng, dist) + + def sample_noise(): + if args: + return function(*args) + + else: + return function() + + return sample_noise diff --git a/build/lib/dacbench/wrappers/state_tracking_wrapper.py b/build/lib/dacbench/wrappers/state_tracking_wrapper.py new file mode 100644 index 000000000..31199c83f --- /dev/null +++ b/build/lib/dacbench/wrappers/state_tracking_wrapper.py @@ -0,0 +1,289 @@ +from gymnasium import spaces +from gymnasium import Wrapper +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +import seaborn as sb + +sb.set_style("darkgrid") +current_palette = list(sb.color_palette()) + + +class StateTrackingWrapper(Wrapper): + """ + Wrapper to track state changed over time + Includes interval mode that returns states in lists of len(interval) instead of one long list. + """ + + def __init__(self, env, state_interval=None, logger=None): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + state_interval : int + If not none, mean in given intervals is tracked, too + logger : dacbench.logger.ModuleLogger + """ + super(StateTrackingWrapper, self).__init__(env) + self.state_interval = state_interval + self.overall_states = [] + if self.state_interval: + self.state_intervals = [] + self.current_states = [] + self.episode_states = None + self.state_type = type(env.observation_space) + self.logger = logger + if self.logger is not None: + benchmark_info = getattr(env, "benchmark_info", None) + self.state_description = ( + benchmark_info.get("state_description", None) + if benchmark_info is not None + else None + ) + + def __setattr__(self, name, value): + """ + Set attribute in wrapper if available and in env if not + + Parameters + ---------- + name : str + Attribute to set + value + Value to set attribute to + """ + if name in [ + "state_interval", + "overall_states", + "state_intervals", + "current_states", + "state_type", + "env", + "episode_states", + "get_states", + "step", + "reset", + "render_state_tracking", + "logger", + ]: + object.__setattr__(self, name, value) + else: + setattr(self.env, name, value) + + def __getattribute__(self, name): + """ + Get attribute value of wrapper if available and of env if not + + Parameters + ---------- + name : str + Attribute to get + + Returns + ------- + value + Value of given name + """ + if name in [ + "state_interval", + "overall_states", + "state_intervals", + "current_states", + "state_type", + "env", + "episode_states", + "get_states", + "step", + "reset", + "render_state_tracking", + "logger", + ]: + return object.__getattribute__(self, name) + + else: + return getattr(self.env, name) + + def reset(self): + """ + Reset environment and record starting state + + Returns + ------- + np.array, {} + state, info + """ + state, info = self.env.reset() + self.overall_states.append(state) + if self.state_interval: + if len(self.current_states) < self.state_interval: + self.current_states.append(state) + else: + self.state_intervals.append(self.current_states) + self.current_states = [state] + return state, info + + def step(self, action): + """ + Execute environment step and record state + + Parameters + ---------- + action : int + action to execute + + Returns + ------- + np.array, float, bool, dict + state, reward, done, metainfo + """ + state, reward, terminated, truncated, info = self.env.step(action) + self.overall_states.append(state) + if self.logger is not None: + self.logger.log_space("state", state, self.state_description) + if self.state_interval: + if len(self.current_states) < self.state_interval: + self.current_states.append(state) + else: + self.state_intervals.append(self.current_states) + self.current_states = [state] + return state, reward, terminated, truncated, info + + def get_states(self): + """ + Get state progression + + Returns + ------- + np.array or np.array, np.array + all states or all states and interval sorted states + + """ + if self.state_interval: + complete_intervals = self.state_intervals + [self.current_states] + return self.overall_states, complete_intervals + + else: + return self.overall_states + + def render_state_tracking(self): + """ + Render state progression + + Returns + ------- + np.array + RBG data of state tracking + """ + + def plot_single(ax=None, index=None, title=None, x=False, y=False): + if ax is None: + plt.xlabel("Episode") + plt.ylabel("State") + elif x and y: + ax.set_ylabel("State") + ax.set_xlabel("Episode") + elif x: + ax.set_xlabel("Episode") + elif y: + ax.set_ylabel("State") + + if index is not None: + ys = [state[index] for state in self.overall_states] + else: + ys = self.overall_states + + if ax is None: + p = plt.plot( + np.arange(len(self.overall_states)), + ys, + label="Episode state", + color="g", + ) + else: + p = ax.plot( + np.arange(len(self.overall_states)), + ys, + label="Episode state", + color="g", + ) + p2 = None + if self.state_interval: + if index is not None: + y_ints = [] + for interval in self.state_intervals: + y_ints.append([state[index] for state in interval]) + else: + y_ints = self.state_intervals + if ax is None: + p2 = plt.plot( + np.arange(len(self.state_intervals)), + [np.mean(interval) for interval in y_ints], + label="Mean interval state", + color="orange", + ) + plt.legend(loc="upper left") + else: + p2 = ax.plot( + np.arange(len(self.state_intervals)) * self.state_interval, + [np.mean(interval) for interval in y_ints], + label="Mean interval state", + color="orange", + ) + ax.legend(loc="upper left") + return p, p2 + + if self.state_type == spaces.Discrete: + figure = plt.figure(figsize=(20, 20)) + canvas = FigureCanvas(figure) + p, p2 = plot_single() + canvas.draw() + elif self.state_type == spaces.Dict: + raise NotImplementedError + + elif self.state_type == spaces.Tuple: + raise NotImplementedError + + elif ( + self.state_type == spaces.MultiDiscrete + or self.state_type == spaces.MultiBinary + or self.state_type == spaces.Box + ): + if self.state_type == spaces.MultiDiscrete: + state_length = len(self.env.observation_space.nvec) + elif self.state_type == spaces.MultiBinary: + state_length = self.env.observation_space.n + else: + state_length = len(self.env.observation_space.high) + if state_length == 1: + figure = plt.figure(figsize=(20, 20)) + canvas = FigureCanvas(figure) + p, p2 = plot_single() + elif state_length < 5: + dim = 1 + figure, axarr = plt.subplots(state_length) + else: + dim = state_length % 4 + figure, axarr = plt.subplots(state_length % 4, state_length // dim) + figure.suptitle("State over time") + canvas = FigureCanvas(figure) + for i in range(state_length): + if state_length == 1: + continue + + x = False + if i % dim == dim - 1: + x = True + if state_length < 5: + p, p2 = plot_single(axarr[i], i, y=True, x=x) + else: + y = i % state_length // dim == 0 + p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) + canvas.draw() + width, height = figure.get_size_inches() * figure.get_dpi() + img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( + int(height), int(width), 3 + ) + return img diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index cfe234c49..0639c3365 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -2,7 +2,7 @@ from types import FunctionType import numpy as np -from gym import spaces +from gymnasium import spaces from functools import partial from dacbench import wrappers @@ -80,6 +80,7 @@ def serialize_config(self): self.config[k], list ): if type(self.config[k][0]) == np.ndarray: + print(k) conf[k] = list(map(list, conf[k])) for i in range(len(conf[k])): if ( @@ -216,6 +217,12 @@ def from_json(cls, json_config): def to_json(self): conf = self.serialize_config() + for k in conf: + print(k) + print(conf[k]) + from copy import deepcopy + del_conf = deepcopy(conf)[k] + json.dumps(del_conf) return json.dumps(conf) def save_config(self, path): @@ -374,13 +381,13 @@ def jsonify_dict_space(self, dict_space): if isinstance(value, spaces.Box): types.append("box") - low = value.low.tolist() - high = value.high.tolist() + low = value.low.astype(float).tolist() + high = value.high.astype(float).tolist() arguments.append([low, high]) if isinstance(value, spaces.Discrete): types.append("discrete") - n = value.n + n = int(value.n) arguments.append([n]) return [keys, types, arguments] @@ -388,11 +395,11 @@ def dictify_json(self, dict_list): dict_space = {} keys, types, args = dict_list for k, type, args_ in zip(keys, types, args): - prepared_args = map(np.array, args_) if type == "box": + prepared_args = map(np.array, args_) dict_space[k] = spaces.Box(*prepared_args, dtype=np.float32) elif type == "discrete": - dict_space[k] = spaces.Discrete(*prepared_args) + dict_space[k] = spaces.Discrete(*args_) else: raise TypeError( f"Currently only Discrete and Box spaces are allowed in Dict spaces, got {type}" diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index b62bf8b5f..350515744 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -1,7 +1,7 @@ import random -import gym -from gym.utils import seeding +import gymnasium as gym +from gymnasium.utils import seeding import numpy as np @@ -79,7 +79,7 @@ def __init__(self, config): self.observation_space = getattr( gym.spaces, config["observation_space_class"] )(*config["observation_space_args"]) - except TypeError: + except AssertionError: print( "To use a Dict observation space, the 'observation_space_args' in the configuration should be a list containing a Dict of gym.Spaces" ) @@ -149,17 +149,19 @@ def step_(self): bool End of episode """ - done = False + truncated = False self.c_step += 1 if self.c_step >= self.n_steps: - done = True - return done + truncated = True + return truncated - def reset_(self, instance=None, instance_id=None, scheme=None): + def reset_(self, seed=0, options={}, instance=None, instance_id=None, scheme=None): """ Pre-reset function for progressing through the instance set Will either use round robin, random or no progression scheme """ + if seed is not None: + self.seed(seed, self.config.get("seed_action_space", False)) self.c_step = 0 if scheme is None: scheme = self.instance_updates @@ -206,21 +208,30 @@ def step(self, action): Environment state reward Environment reward - done : bool + terminated: bool Run finished flag + truncated: bool + Run timed out flag info : dict Additional metainfo """ raise NotImplementedError - def reset(self): + def reset(self, seed: int = None): """ Reset environment + Parameters + ------- + seed + Seed for the environment + Returns ------- state Environment state + info: dict + Additional metainfo """ raise NotImplementedError diff --git a/dacbench/agents/dynamic_random_agent.py b/dacbench/agents/dynamic_random_agent.py index c10b25b12..2f312834b 100644 --- a/dacbench/agents/dynamic_random_agent.py +++ b/dacbench/agents/dynamic_random_agent.py @@ -1,5 +1,5 @@ from dacbench.abstract_agent import AbstractDACBenchAgent -from gym import spaces +from gymnasium import spaces class DynamicRandomAgent(AbstractDACBenchAgent): diff --git a/dacbench/agents/simple_agents.py b/dacbench/agents/simple_agents.py index 0b0965e6e..3fc6a7f0c 100644 --- a/dacbench/agents/simple_agents.py +++ b/dacbench/agents/simple_agents.py @@ -1,5 +1,5 @@ from dacbench.abstract_agent import AbstractDACBenchAgent -from gym import spaces +from gymnasium import spaces class RandomAgent(AbstractDACBenchAgent): diff --git a/dacbench/benchmarks/__init__.py b/dacbench/benchmarks/__init__.py index 50d412a0f..4938c4e58 100644 --- a/dacbench/benchmarks/__init__.py +++ b/dacbench/benchmarks/__init__.py @@ -28,17 +28,6 @@ "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." ) -modea_spec = importlib.util.find_spec("modea") -found = modea_spec is not None -if found: - from dacbench.benchmarks.modea_benchmark import ModeaBenchmark - - __all__.append("ModeaBenchmark") -else: - warnings.warn( - "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - modcma_spec = importlib.util.find_spec("modcma") found = modcma_spec is not None if found: diff --git a/dacbench/benchmarks/cma_benchmark.py b/dacbench/benchmarks/cma_benchmark.py index 47d5ae26d..a22e393ee 100644 --- a/dacbench/benchmarks/cma_benchmark.py +++ b/dacbench/benchmarks/cma_benchmark.py @@ -1,6 +1,6 @@ from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import CMAESEnv -from gym import spaces +from gymnasium import spaces import numpy as np import os import csv diff --git a/dacbench/benchmarks/sgd_benchmark.py b/dacbench/benchmarks/sgd_benchmark.py index ff00ece88..1122ae9a1 100755 --- a/dacbench/benchmarks/sgd_benchmark.py +++ b/dacbench/benchmarks/sgd_benchmark.py @@ -2,7 +2,7 @@ import os import numpy as np -from gym import spaces +from gymnasium import spaces from torch.nn import NLLLoss from dacbench.abstract_benchmark import AbstractBenchmark, objdict diff --git a/dacbench/benchmarks/theory_benchmark.py b/dacbench/benchmarks/theory_benchmark.py index b5c0f8f78..2f48b031b 100644 --- a/dacbench/benchmarks/theory_benchmark.py +++ b/dacbench/benchmarks/theory_benchmark.py @@ -4,7 +4,7 @@ import numpy as np import os import pandas as pd -import gym +import gymnasium as gym import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH diff --git a/dacbench/benchmarks/toysgd_benchmark.py b/dacbench/benchmarks/toysgd_benchmark.py index 9b1c7debc..716a4f9c4 100644 --- a/dacbench/benchmarks/toysgd_benchmark.py +++ b/dacbench/benchmarks/toysgd_benchmark.py @@ -2,7 +2,7 @@ import numpy as np import pandas as pd -from gym import spaces +from gymnasium import spaces from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import ToySGDEnv diff --git a/dacbench/container/container_utils.py b/dacbench/container/container_utils.py index 3f13df81c..923e0d8e5 100644 --- a/dacbench/container/container_utils.py +++ b/dacbench/container/container_utils.py @@ -5,7 +5,7 @@ import time from typing import Any, Union, Tuple, List, Dict -import gym +import gymnasium as gym import numpy as np @@ -25,11 +25,9 @@ def hint(item): if isinstance(item, np.floating): return {'__type__': 'np.float', '__items__': float(item)} if isinstance(item, np.integer): - return {'__type__': 'np.int', '__items__': item.tolist()} + return {'__type__': 'np.int32', '__items__': item.tolist()} if isinstance(item, enum.Enum): return str(item) - if isinstance(item, np.random.RandomState): - return serialize_random_state(item) if isinstance(item, gym.Space): return Encoder.encode_space(item) if isinstance(item, np.dtype): @@ -53,9 +51,6 @@ def encode_space(space_obj : gym.Space): ) )] - if not isinstance(space_obj, (gym.spaces.Dict, gym.spaces.Tuple)): - properties.append(('np_random', serialize_random_state(space_obj.np_random))) - if isinstance(space_obj, (gym.spaces.Box, gym.spaces.Discrete, gym.spaces.MultiDiscrete, gym.spaces.MultiBinary)): # by default assume all constrcutor arguments are stored under the same name # for box we need to drop shape, since either shape or a array for low and height is required @@ -64,7 +59,7 @@ def encode_space(space_obj : gym.Space): # drop self and non-args (self, arg1, arg2, ..., local_var1, local_var2, ...) arguments = local_vars[1:__init__.co_argcount] - attributes_to_serialize = list(filter(lambda att: att not in ['shape'], arguments)) + attributes_to_serialize = list(filter(lambda att: att not in ['shape', 'seed'], arguments)) for attribute in attributes_to_serialize: if hasattr(space_obj, attribute): @@ -95,13 +90,11 @@ def object_hook(self, obj: Any) -> Union[Union[tuple, np.ndarray, float, float, return np.array(obj['__items__']) if __type == 'np.float': return np.float(obj['__items__']) - if __type == 'np.int': - return np.int(obj['__items__']) - if __type == 'random_state': - return deserialize_random_state(obj) + if __type == 'np.int32': + return np.int32(obj['__items__']) if __type == 'np.dtype': return np.dtype(obj['__items__']) - if __type.startswith('gym.spaces.'): + if __type.startswith('gymnasium.spaces.'): return self.decode_space(obj) return obj @@ -110,7 +103,7 @@ def decode_space(self, space_dict: Dict) -> gym.Space: __type = space_dict['__type__'] __class = getattr(gym.spaces, __type.split('.')[-1]) - args = {name:value for name, value in space_dict.items() if name not in ['__type__', 'np_random', 'shape']} + args = {name:value for name, value in space_dict.items() if name not in ['__type__', 'shape']} # temporally remove subspace since constructor reseeds them if issubclass(__class,(gym.spaces.Tuple, gym.spaces.Dict)): @@ -125,26 +118,11 @@ def decode_space(self, space_dict: Dict) -> gym.Space: if isinstance(space_object, gym.spaces.Tuple): space_object.spaces = tuple(space_object.spaces) - - if not isinstance(space_object, (gym.spaces.Dict, gym.spaces.Tuple)): - space_object.np_random = space_dict['np_random'] - + + print(space_object) return space_object -def deserialize_random_state(random_state_dict: Dict) -> np.random.RandomState: - (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state_dict['__items__'] - rnd1 = np.array(rnd1, dtype=np.uint32) - random_state = np.random.RandomState() - random_state.set_state((rnd0, rnd1, rnd2, rnd3, rnd4)) - return random_state - -def serialize_random_state(random_state: np.random.RandomState) -> Tuple[int, List, int, int, int]: - (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state.get_state() - rnd1 = rnd1.tolist() - return {'__type__': 'random_state', '__items__': [rnd0, rnd1, rnd2, rnd3, rnd4]} - - def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: """ Wait for a UNIX socket to be created. diff --git a/dacbench/container/singularity_recipes/cma.def b/dacbench/container/singularity_recipes/cma.def index 09b472ab7..f5d2ab010 100644 --- a/dacbench/container/singularity_recipes/cma.def +++ b/dacbench/container/singularity_recipes/cma.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/dacbench.def b/dacbench/container/singularity_recipes/dacbench.def index b232d43be..c6ca2ae40 100644 --- a/dacbench/container/singularity_recipes/dacbench.def +++ b/dacbench/container/singularity_recipes/dacbench.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/geometric.def b/dacbench/container/singularity_recipes/geometric.def index 8e0efb636..db0a9d3c6 100644 --- a/dacbench/container/singularity_recipes/geometric.def +++ b/dacbench/container/singularity_recipes/geometric.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/modcma.def b/dacbench/container/singularity_recipes/modcma.def index 28d78cb87..a99215b9b 100644 --- a/dacbench/container/singularity_recipes/modcma.def +++ b/dacbench/container/singularity_recipes/modcma.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/modea.def b/dacbench/container/singularity_recipes/modea.def index d1c5015ef..5ea4c7502 100644 --- a/dacbench/container/singularity_recipes/modea.def +++ b/dacbench/container/singularity_recipes/modea.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/recipe_template b/dacbench/container/singularity_recipes/recipe_template index 56c2e235b..23537a2e3 100644 --- a/dacbench/container/singularity_recipes/recipe_template +++ b/dacbench/container/singularity_recipes/recipe_template @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels VERSION v0.1 diff --git a/dacbench/container/singularity_recipes/sgd.def b/dacbench/container/singularity_recipes/sgd.def index eee6f6ddc..f785d0d88 100644 --- a/dacbench/container/singularity_recipes/sgd.def +++ b/dacbench/container/singularity_recipes/sgd.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/container/singularity_recipes/theory.def b/dacbench/container/singularity_recipes/theory.def index 7c3c1a0c3..19dfc9512 100644 --- a/dacbench/container/singularity_recipes/theory.def +++ b/dacbench/container/singularity_recipes/theory.def @@ -1,5 +1,5 @@ Bootstrap: docker -From: python:3.7-slim +From: python:3.9-slim %labels MAINTAINER AREEB AHMAD diff --git a/dacbench/envs/__init__.py b/dacbench/envs/__init__.py index b853a7629..91c598942 100644 --- a/dacbench/envs/__init__.py +++ b/dacbench/envs/__init__.py @@ -33,17 +33,6 @@ "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." ) -modea_spec = importlib.util.find_spec("modea") -found = modea_spec is not None -if found: - from dacbench.envs.modea import ModeaEnv - - __all__.append("ModeaEnv") -else: - warnings.warn( - "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - modcma_spec = importlib.util.find_spec("modcma") found = modcma_spec is not None if found: diff --git a/dacbench/envs/cma_es.py b/dacbench/envs/cma_es.py index 65009b2da..8b0c9f7fc 100644 --- a/dacbench/envs/cma_es.py +++ b/dacbench/envs/cma_es.py @@ -82,10 +82,10 @@ def step(self, action): np.array, float, bool, dict state, reward, done, info """ - done = super(CMAESEnv, self).step_() + truncated = super(CMAESEnv, self).step_() self.history.append([self.f_difference, self.velocity]) - done = done or self.es.stop() != {} - if not done: + terminated = self.es.stop() != {} + if not (terminated or truncated): """Moves forward in time one step""" sigma = action self.es.tell(self.solutions, self.func_values) @@ -112,9 +112,9 @@ def step(self, action): self.cur_sigma = [self.es.sigma] self.cur_obj_val = self.es.best.f - return self.get_state(self), self.get_reward(self), done, {} + return self.get_state(self), self.get_reward(self), terminated, truncated, {} - def reset(self): + def reset(self, seed=None, options={}): """ Reset environment @@ -123,7 +123,7 @@ def reset(self): np.array Environment state """ - super(CMAESEnv, self).reset_() + super(CMAESEnv, self).reset_(seed) self.history.clear() self.past_obj_vals.clear() self.past_sigma.clear() @@ -131,7 +131,7 @@ def reset(self): self.dim = self.instance[1] self.init_sigma = self.instance[2] self.cur_sigma = [self.init_sigma] - self.fcn = bn.instantiate(self.instance[0])[0] + self.fcn = bn.instantiate(self.instance[0], seed=self.seed)[0] self.func_values = [] self.f_vals = deque(maxlen=self.popsize) @@ -150,7 +150,7 @@ def reset(self): ) self.es.mean_old = self.es.mean self.history.append([self.f_difference, self.velocity]) - return self.get_state(self) + return self.get_state(self), {} def close(self): """ diff --git a/dacbench/envs/cma_step_size.py b/dacbench/envs/cma_step_size.py index 7bdb9f5bc..44000e834 100644 --- a/dacbench/envs/cma_step_size.py +++ b/dacbench/envs/cma_step_size.py @@ -16,8 +16,8 @@ def __init__(self, config): self.get_reward = config.get("reward_function", self.get_default_reward) self.get_state = config.get("state_method", self.get_default_state) - def reset(self): - super().reset_() + def reset(self, seed=None, options={}): + super().reset_(seed) self.dim, self.fid, self.iid, self.representation = self.instance self.objective = IOH_function( self.fid, self.dim, self.iid, target_precision=1e-8 @@ -26,13 +26,13 @@ def reset(self): self.objective, parameters=Parameters.from_config_array(self.dim, self.representation), ) - return self.get_state(self) + return self.get_state(self), {} def step(self, action): - done = super().step_() + truncated = super().step_() self.es.parameters.sigma = action - done = not self.es.step() or done - return self.get_state(self), self.get_reward(self), done, {} + terminated = not self.es.step() + return self.get_state(self), self.get_reward(self), terminated, truncated, {} def close(self): return True diff --git a/dacbench/envs/fast_downward.py b/dacbench/envs/fast_downward.py index 5f3bdf606..4113cd375 100644 --- a/dacbench/envs/fast_downward.py +++ b/dacbench/envs/fast_downward.py @@ -294,8 +294,8 @@ def step(self, action: typing.Union[int, typing.List[int]]): Returns ---------- - np.array, float, bool, dict - state, reward, done, info + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info """ self.done = super(FastDownwardEnv, self).step_() if not np.issubdtype( @@ -311,19 +311,19 @@ def step(self, action: typing.Union[int, typing.List[int]]): else: msg = str(action) self.send_msg(str.encode(msg)) - s, r, d = self._process_data() + s, r, terminated = self._process_data() r = max(self.reward_range[0], min(self.reward_range[1], r)) info = {} - if d: + if terminated: self.done = True self.kill_connection() if self.c_step > self.n_steps: info["needs_reset"] = True self.send_msg(str.encode("END")) self.kill_connection() - return s, r, d or self.done, info + return s, r, terminated, self.done, info - def reset(self): + def reset(self, seed=None, options={}): """ Reset environment @@ -331,8 +331,10 @@ def reset(self): ---------- np.array State after reset + dict + Meta-info """ - super(FastDownwardEnv, self).reset_() + super(FastDownwardEnv, self).reset_(seed) self._prev_state = None self.__start_time = time.time() if not self.done: # This means we interrupt FD before a plan was found @@ -398,16 +400,16 @@ def reset(self): s, _, _ = self._process_data() if self.max_rand_steps > 1: for _ in range(self.np_random.randint(1, self.max_rand_steps + 1)): - s, _, _, _ = self.step(self.action_space.sample()) + s, _, _, _, _ = self.step(self.action_space.sample()) if self.conn is None: return self.reset() else: - s, _, _, _ = self.step(0) # hard coded to zero as initial step + s, _, _, _, _ = self.step(0) # hard coded to zero as initial step remove( fp ) # remove the port file such that there is no chance of loading the old port - return s + return s, {} def kill_connection(self): """Kill the connection""" diff --git a/dacbench/envs/geometric.py b/dacbench/envs/geometric.py index 0be86bcea..b0ddefac1 100644 --- a/dacbench/envs/geometric.py +++ b/dacbench/envs/geometric.py @@ -143,8 +143,8 @@ def step(self, action: int): Returns ------- - np.array, float, bool, dict - state, reward, done, info + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info """ self.done = super(GeometricEnv, self).step_() @@ -183,9 +183,9 @@ def step(self, action: int): if math.isnan(reward): raise ValueError(f"Reward NAN Coords: {coords}, step: {self.c_step}") - return next_state, reward, self.done, {} + return next_state, reward, False, self.done, {} - def reset(self) -> List[int]: + def reset(self, seed=None, options={}) -> List[int]: """ Resets env @@ -193,8 +193,10 @@ def reset(self) -> List[int]: ------- numpy.array Environment state + dict + Meta-info """ - super(GeometricEnv, self).reset_() + super(GeometricEnv, self).reset_(seed) self.functions.set_instance(self.instance, self.instance_index) if self.c_step: @@ -209,7 +211,7 @@ def reset(self) -> List[int]: ) self._prev_state = None - return self.get_state(self) + return self.get_state(self), {} def get_default_reward(self, _) -> float: """ @@ -493,8 +495,8 @@ def calculate_derivative(self, trajectory: List, c_step: int) -> np.array: derrivative = np.zeros(self.n_actions) for step in range(lower_bound, upper_bound): der = np.subtract( - np.array(trajectory[step], dtype=np.float), - np.array(trajectory[step - 1], dtype=np.float), + np.array(trajectory[step], dtype=np.float32), + np.array(trajectory[step - 1], dtype=np.float32), ) derrivative = np.add(derrivative, der) @@ -502,8 +504,8 @@ def calculate_derivative(self, trajectory: List, c_step: int) -> np.array: elif c_step == 1: derrivative = np.subtract( - np.array(trajectory[c_step], dtype=np.float), - np.array(trajectory[c_step - 1], dtype=np.float), + np.array(trajectory[c_step], dtype=np.float32), + np.array(trajectory[c_step - 1], dtype=np.float32), ) else: diff --git a/dacbench/envs/luby.py b/dacbench/envs/luby.py index 8f1590097..6e9ae3125 100644 --- a/dacbench/envs/luby.py +++ b/dacbench/envs/luby.py @@ -73,8 +73,8 @@ def step(self, action: int): Returns ------- - np.array, float, bool, dict - state, reward, done, info + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info """ self.done = super(LubyEnv, self).step_() self.prev_state = self._state.copy() @@ -95,9 +95,9 @@ def step(self, action: int): # the t+1 timestep. luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) self._next_goal = self._seq[luby_t - 1] - return self.get_state(self), reward, self.done, {} + return self.get_state(self), reward, False, self.done, {} - def reset(self) -> List[int]: + def reset(self, seed=None, options={}) -> List[int]: """ Resets env @@ -106,7 +106,7 @@ def reset(self) -> List[int]: numpy.array Environment state """ - super(LubyEnv, self).reset_() + super(LubyEnv, self).reset_(seed) self._start_shift = self.instance[0] self._sticky_shif = self.instance[1] self._r = 0 @@ -117,7 +117,7 @@ def reset(self) -> List[int]: luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) self._next_goal = self._seq[luby_t - 1] self.done = False - return self.get_state(self) + return self.get_state(self), {} def get_default_reward(self, _): if self.action == self._next_goal: diff --git a/dacbench/envs/modcma.py b/dacbench/envs/modcma.py index 3852a1673..20a484998 100644 --- a/dacbench/envs/modcma.py +++ b/dacbench/envs/modcma.py @@ -16,8 +16,8 @@ def __init__(self, config): self.get_reward = config.get("reward_function", self.get_default_reward) self.get_state = config.get("state_method", self.get_default_state) - def reset(self): - super().reset_() + def reset(self, seed=None, options={}): + super().reset_(seed) self.dim, self.fid, self.iid, self.representation = self.instance self.representation = np.array(self.representation) self.objective = IOH_function( @@ -29,16 +29,16 @@ def reset(self): self.dim, np.array(self.representation).astype(int) ), ) - return self.get_state(self) + return self.get_state(self), {} def step(self, action): - done = super().step_() + truncated = super().step_() new_parameters = Parameters.from_config_array(self.dim, action) self.es.parameters.update( {m: getattr(new_parameters, m) for m in Parameters.__modules__} ) - done = not self.es.step() - return self.get_state(self), self.get_reward(self), done, {} + terminated = not self.es.step() + return self.get_state(self), self.get_reward(self), terminated, truncated, {} def close(self): return True diff --git a/dacbench/envs/sgd.py b/dacbench/envs/sgd.py index 0d347e383..479034a70 100644 --- a/dacbench/envs/sgd.py +++ b/dacbench/envs/sgd.py @@ -250,11 +250,13 @@ def get_full_training_loss(self): @property def crash(self): self.crashed = True + truncated = False + terminated = False if self.c_step >= self.n_steps: - done = True + truncated = True else: - done = self.terminate_on_crash - return self.get_state(self), self.crash_penalty, done, {} + terminated = self.terminate_on_crash + return self.get_state(self), self.crash_penalty, terminated, truncated, {} def seed(self, seed=None, seed_action_space=False): """ @@ -287,10 +289,10 @@ def step(self, action): Returns ------- - np.array, float, bool, dict - state, reward, done, info + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info """ - done = super(SGDEnv, self).step_() + truncated = super(SGDEnv, self).step_() self.step_count += 1 index = 0 @@ -337,7 +339,7 @@ def step(self, action): for value in state.values(): if np.isnan(value): return self.crash - return state, reward, done, {} + return state, reward, False, truncated, {} def _architecture_constructor(self, arch_str): layer_specs = [] @@ -359,7 +361,7 @@ def model_constructor(): return model_constructor - def reset(self): + def reset(self, seed=None, options={}): """ Reset environment @@ -368,7 +370,7 @@ def reset(self): np.array Environment state """ - super(SGDEnv, self).reset_() + super(SGDEnv, self).reset_(seed) dataset = self.instance[0] instance_seed = self.instance[1] @@ -514,7 +516,7 @@ def init_weights(m): ) self.train_network() - return self.get_state(self) + return self.get_state(self), {} def set_writer(self, writer): self.writer = writer @@ -601,7 +603,7 @@ def get_default_state(self, _): return state def _train_batch_(self): - (data, target) = self.train_loader_it.next() + (data, target) = next(self.train_loader_it) data, target = data.to(self.device), target.to(self.device) self.current_batch_size = data.size()[0] output = self.model(data) @@ -648,7 +650,7 @@ def current_validation_loss(self): def _get_validation_loss_(self): with torch.no_grad(): - (data, target) = self.validation_loader_it.next() + (data, target) = next(self.validation_loader_it) data, target = data.to(self.device), target.to(self.device) output = self.val_model(data) validation_loss = self.val_loss_function(output, target).mean() diff --git a/dacbench/envs/sigmoid.py b/dacbench/envs/sigmoid.py index 9672a942e..562b6b5f4 100644 --- a/dacbench/envs/sigmoid.py +++ b/dacbench/envs/sigmoid.py @@ -70,8 +70,8 @@ def step(self, action: int): Returns ------- - np.array, float, bool, dict - state, reward, done, info + np.array, float, bool, bool, dict + state, reward, terminated, truncated, info """ self.done = super(SigmoidEnv, self).step_() action = self.action_mapper[action] @@ -82,9 +82,9 @@ def step(self, action: int): self.action = action next_state = self.get_state(self) self._prev_state = next_state - return next_state, self.get_reward(self), self.done, {} + return next_state, self.get_reward(self), False, self.done, {} - def reset(self) -> List[int]: + def reset(self, seed=None, options={}) -> List[int]: """ Resets env @@ -93,11 +93,11 @@ def reset(self) -> List[int]: numpy.array Environment state """ - super(SigmoidEnv, self).reset_() + super(SigmoidEnv, self).reset_(seed) self.shifts = self.instance[: self.n_actions] self.slopes = self.instance[self.n_actions :] self._prev_state = None - return self.get_state(self) + return self.get_state(self), {} def get_default_reward(self, _): r = [ diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index 1548bcff5..09461101a 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -4,7 +4,7 @@ from collections import deque import uuid -import gym +import gymnasium as gym from dacbench import AbstractEnv @@ -364,7 +364,7 @@ def get_obs_domain_from_name(var_name): """ return 0, np.inf - def reset(self): + def reset(self, seed=None, options={}): """ Resets env @@ -373,7 +373,7 @@ def reset(self): numpy.array Environment state """ - super(RLSEnv, self).reset_() + super(RLSEnv, self).reset_(seed) # current problem size (n) & evaluation limit (max_evals) self.n = self.instance.size @@ -410,7 +410,7 @@ def reset(self): self.log_fx = [] self.init_obj = self.x.fitness - return self.get_state() + return self.get_state(), {} def get_state(self): return np.asarray([f() for f in self.state_functions]) @@ -426,10 +426,10 @@ def step(self, action): Returns ------- - state, reward, done, info - np.array, float, bool, dict + state, reward, terminated, truncated, info + np.array, float, bool, bool, dict """ - super(RLSEnv, self).step_() + truncated = super(RLSEnv, self).step_() fitness_before_update = self.x.fitness @@ -447,7 +447,7 @@ def step(self, action): # if we're in the training phase, we return a large negative reward and stop the episode if self.test_env is False: - done = True + terminated = True n_evals = 0 reward = -MAX_INT stop = True @@ -468,7 +468,7 @@ def step(self, action): self.total_evals += n_evals # check stopping criteria - done = (self.total_evals >= self.max_evals) or (self.x.is_optimal()) + terminated = (self.total_evals >= self.max_evals) or (self.x.is_optimal()) # calculate reward if self.reward_choice == "imp_div_evals": @@ -497,7 +497,7 @@ def step(self, action): self.log_reward.append(reward) returned_info = {"msg": "", "values": {}} - if done: + if terminated or truncated: if hasattr(self, "env_type"): msg = "Env " + self.env_type + ". " else: @@ -532,7 +532,7 @@ def step(self, action): "log_reward": [float(x) for x in self.log_reward], } - return self.get_state(), reward, done, returned_info + return self.get_state(), reward, truncated, terminated, returned_info def close(self) -> bool: """ diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index 9c3645b14..a9592636b 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -121,10 +121,11 @@ def step( - state : Dict[str, float] State with entries "remaining_budget", "gradient", "learning_rate", "momentum" - reward : float - - done : bool + - terminated : bool + - truncated : bool - info : Dict """ - done = False + truncated = super(ToySGDEnv, self).step_() info = {} # parse action @@ -164,12 +165,10 @@ def step( # Stop criterion self.n_steps += 1 - if self.n_steps > self.n_steps_max: - done = True - return state, reward, done, info + return state, reward, False, truncated, info - def reset(self): + def reset(self, seed=None, options={}): """ Reset environment @@ -177,8 +176,10 @@ def reset(self): ------- np.array Environment state + dict + Meta-info """ - super(ToySGDEnv, self).reset_() + super(ToySGDEnv, self).reset_(seed) self.velocity = 0 self.gradient = 0 @@ -198,7 +199,7 @@ def reset(self): "gradient": self.gradient, "learning_rate": self.learning_rate, "momentum": self.momentum, - } + }, {} def render(self, **kwargs): import matplotlib.pyplot as plt diff --git a/dacbench/runner.py b/dacbench/runner.py index 058d00d6b..cc2764b41 100644 --- a/dacbench/runner.py +++ b/dacbench/runner.py @@ -27,12 +27,12 @@ def run_benchmark(env, agent, num_episodes, logger=None): logger.set_env(env) for _ in range(num_episodes): - state = env.reset() - done = False + state, _ = env.reset() + terminated, truncated = False, False reward = 0 - while not done: + while not (terminated or truncated): action = agent.act(state, reward) - next_state, reward, done, _ = env.step(action) + next_state, reward, terminated, truncated, _ = env.step(action) agent.train(next_state, reward) state = next_state if logger is not None: diff --git a/dacbench/wrappers/action_tracking_wrapper.py b/dacbench/wrappers/action_tracking_wrapper.py index fda256473..9963a58d0 100644 --- a/dacbench/wrappers/action_tracking_wrapper.py +++ b/dacbench/wrappers/action_tracking_wrapper.py @@ -1,8 +1,8 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from gym import Wrapper -from gym import spaces +from gymnasium import Wrapper +from gymnasium import spaces from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas sb.set_style("darkgrid") @@ -106,7 +106,7 @@ def step(self, action): np.array, float, bool, dict state, reward, done, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) self.overall_actions.append(action) if self.logger is not None: self.logger.log_space("action", action) @@ -117,7 +117,7 @@ def step(self, action): else: self.action_intervals.append(self.current_actions) self.current_actions = [action] - return state, reward, done, info + return state, reward, terminated, truncated, info def get_actions(self): """ diff --git a/dacbench/wrappers/episode_time_tracker.py b/dacbench/wrappers/episode_time_tracker.py index dd99dacf4..bab927cee 100644 --- a/dacbench/wrappers/episode_time_tracker.py +++ b/dacbench/wrappers/episode_time_tracker.py @@ -1,4 +1,4 @@ -from gym import Wrapper +from gymnasium import Wrapper import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas @@ -120,11 +120,11 @@ def step(self, action): Returns ------- - np.array, float, bool, dict - state, reward, done, metainfo + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo """ start = time.time() - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) stop = time.time() duration = stop - start self.episode.append(duration) @@ -139,7 +139,7 @@ def step(self, action): else: self.step_intervals.append(self.current_step_interval) self.current_step_interval = [duration] - if done: + if terminated or truncated: self.overall_times.append(self.episode) if self.logger is not None: self.logger.log("episode_duration", sum(self.episode)) @@ -151,7 +151,7 @@ def step(self, action): self.time_intervals.append(self.current_times) self.current_times = [] self.episode = [] - return state, reward, done, info + return state, reward, terminated, truncated, info def get_times(self): """ diff --git a/dacbench/wrappers/observation_wrapper.py b/dacbench/wrappers/observation_wrapper.py index c02b79a0c..57d8e27fe 100644 --- a/dacbench/wrappers/observation_wrapper.py +++ b/dacbench/wrappers/observation_wrapper.py @@ -74,12 +74,12 @@ def step(self, action): Returns ------- - np.array, float, bool, dict - state, reward, done, metainfo + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) state = self.flatten(state) - return state, reward, done, info + return state, reward, terminated, truncated, info def reset(self): """ @@ -87,12 +87,12 @@ def reset(self): Returns ------- - np.array - state + np.array, dict + state, info """ - state = self.env.reset() + state, info = self.env.reset() state = self.flatten(state) - return state + return state, info def flatten(self, state_dict): keys = sorted(list(state_dict.keys())) diff --git a/dacbench/wrappers/performance_tracking_wrapper.py b/dacbench/wrappers/performance_tracking_wrapper.py index beb967d90..187e22e85 100644 --- a/dacbench/wrappers/performance_tracking_wrapper.py +++ b/dacbench/wrappers/performance_tracking_wrapper.py @@ -126,10 +126,10 @@ def step(self, action): np.array, float, bool, dict state, reward, done, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) self.episode_performance += reward - if done: + if terminated or truncated: self.overall_performance.append(self.episode_performance) if self.logger is not None: self.logger.log( @@ -147,7 +147,7 @@ def step(self, action): key = "".join(str(e) for e in self.env.instance) self.instance_performances[key].append(self.episode_performance) self.episode_performance = 0 - return state, reward, done, info + return state, reward, terminated, truncated, info def get_performance(self): """ diff --git a/dacbench/wrappers/policy_progress_wrapper.py b/dacbench/wrappers/policy_progress_wrapper.py index fb5aced9a..e8fcb6773 100644 --- a/dacbench/wrappers/policy_progress_wrapper.py +++ b/dacbench/wrappers/policy_progress_wrapper.py @@ -84,18 +84,18 @@ def step(self, action): Returns ------- - np.array, float, bool, dict - state, reward, done, metainfo + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) self.episode.append(action) - if done: + if terminated or truncated: optimal = self.compute_optimal(self.env.instance) self.policy_progress.append( np.linalg.norm(np.array(optimal) - np.array(self.episode)) ) self.episode = [] - return state, reward, done, info + return state, reward,terminated, truncated, info def render_policy_progress(self): """ Plot progress """ diff --git a/dacbench/wrappers/reward_noise_wrapper.py b/dacbench/wrappers/reward_noise_wrapper.py index 25d886459..779482800 100644 --- a/dacbench/wrappers/reward_noise_wrapper.py +++ b/dacbench/wrappers/reward_noise_wrapper.py @@ -82,13 +82,13 @@ def step(self, action): Returns ------- - np.array, float, bool, dict - state, reward, done, metainfo + np.array, float, bool, bool, dict + state, reward, terminated, truncated, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) reward += self.noise_function() reward = max(self.env.reward_range[0], min(self.env.reward_range[1], reward)) - return state, reward, done, info + return state, reward, terminated, truncated, info def add_noise(self, dist, args): """ diff --git a/dacbench/wrappers/state_tracking_wrapper.py b/dacbench/wrappers/state_tracking_wrapper.py index 705407d1d..c769c96cc 100644 --- a/dacbench/wrappers/state_tracking_wrapper.py +++ b/dacbench/wrappers/state_tracking_wrapper.py @@ -1,5 +1,5 @@ -from gym import spaces -from gym import Wrapper +from gymnasium import spaces +from gymnasium import Wrapper import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas @@ -112,10 +112,10 @@ def reset(self): Returns ------- - np.array - state + np.array, {} + state, info """ - state = self.env.reset() + state, info = self.env.reset() self.overall_states.append(state) if self.state_interval: if len(self.current_states) < self.state_interval: @@ -123,7 +123,7 @@ def reset(self): else: self.state_intervals.append(self.current_states) self.current_states = [state] - return state + return state, info def step(self, action): """ @@ -139,7 +139,7 @@ def step(self, action): np.array, float, bool, dict state, reward, done, metainfo """ - state, reward, done, info = self.env.step(action) + state, reward, terminated, truncated, info = self.env.step(action) self.overall_states.append(state) if self.logger is not None: self.logger.log_space("state", state, self.state_description) @@ -149,7 +149,7 @@ def step(self, action): else: self.state_intervals.append(self.current_states) self.current_states = [state] - return state, reward, done, info + return state, reward, terminated, truncated, info def get_states(self): """ @@ -235,6 +235,9 @@ def plot_single(ax=None, index=None, title=None, x=False, y=False): ax.legend(loc="upper left") return p, p2 + print(self.state_type) + print(spaces.Tuple) + print(self.state_type==spaces.Tuple) if self.state_type == spaces.Discrete: figure = plt.figure(figsize=(20, 20)) canvas = FigureCanvas(figure) @@ -282,6 +285,8 @@ def plot_single(ax=None, index=None, title=None, x=False, y=False): y = i % state_length // dim == 0 p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) canvas.draw() + else: + raise ValueError('Unknown state type') width, height = figure.get_size_inches() * figure.get_dpi() img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( int(height), int(width), 3 diff --git a/other_requirements/cma.json b/other_requirements/cma.json index b4904e58a..c27210f3d 100644 --- a/other_requirements/cma.json +++ b/other_requirements/cma.json @@ -1,3 +1,5 @@ { - "cma": ["cma == 2.7"] + "cma": [ + "cma" + ] } \ No newline at end of file diff --git a/other_requirements/geometric.json b/other_requirements/geometric.json index cb0935982..e91984b3f 100644 --- a/other_requirements/geometric.json +++ b/other_requirements/geometric.json @@ -1,3 +1,7 @@ { - "geometric": ["matplotlib>=3.1", "numpy==1.19.2", "seaborn>=0.11"] + "geometric": [ + "matplotlib", + "numpy", + "seaborn" + ] } \ No newline at end of file diff --git a/other_requirements/modcma.json b/other_requirements/modcma.json index 8909e1c12..01b05eca3 100644 --- a/other_requirements/modcma.json +++ b/other_requirements/modcma.json @@ -1,3 +1,7 @@ { - "modcma": ["modcma == 0.0.2.8.2", "pandas==1.0.3", "IOHexperimenter == 0.2.9.2"] + "modcma": [ + "modcma", + "pandas", + "IOHexperimenter" + ] } \ No newline at end of file diff --git a/other_requirements/modea.json b/other_requirements/modea.json index a9c36cadf..b964faa34 100644 --- a/other_requirements/modea.json +++ b/other_requirements/modea.json @@ -1,3 +1,7 @@ { - "modea": ["modea==0.4.0", "pandas==1.0.3", "openml==0.10.2"] -} + "modea": [ + "modea", + "pandas", + "openml" + ] +} \ No newline at end of file diff --git a/other_requirements/sgd.json b/other_requirements/sgd.json index 67695b0c9..25ca5132c 100644 --- a/other_requirements/sgd.json +++ b/other_requirements/sgd.json @@ -1,3 +1,8 @@ { - "sgd": ["scikit-learn==0.23.2", "torchvision==0.10.0", "torch==1.9.0", "backpack-for-pytorch==1.2.0"] + "sgd": [ + "scikit-learn", + "torchvision", + "torch", + "backpack-for-pytorch" + ] } \ No newline at end of file diff --git a/other_requirements/theory.json b/other_requirements/theory.json index 6114a3708..33047d4b8 100644 --- a/other_requirements/theory.json +++ b/other_requirements/theory.json @@ -1,3 +1,5 @@ { - "theory": ["uuid==1.30"] + "theory": [ + "uuid" + ] } \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 4325c54b5..000000000 --- a/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -gym==0.15.3 -numpy==1.19.2 -scipy==1.4.1 -cma==2.7 -pandas==1.0.3 -matplotlib>=3.1 -seaborn>=0.11 -modea==0.4.0 -sobol_seq==0.2.0 -torchvision==0.10.0 -torch==1.9.0 -backpack-for-pytorch==1.2.0 -modcma == 0.0.2.8.2 -IOHexperimenter == 0.2.9.2 -Pyro4==4.80 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index a49e2a1fe..d9e2d5e8c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ [metadata] name = DACBench -version = 0.0.1 -author_email = eimer@tnt.uni-hannover.de +version = 0.2.0 +author_email = t.eimer@ai.uni-hannover.de author = Theresa Eimer <{author_email}> home_page = https://github.com/automl/{name} project_urls = @@ -28,86 +28,75 @@ classifiers = Topic :: Software Development [options] -python_requires= >=3.6 +python_requires= >=3.10 install_requires = - gym==0.15.3 - numpy==1.19.2 - scipy==1.4.1 - pandas==1.0.3 - matplotlib>=3.1 - seaborn>=0.11 - configspace==0.4.19 - Pyro4==4.80 + gymnasium==0.27.1 + numpy==1.24.2 + scipy=~1.10.1 + pandas=~1.5.3 + matplotlib=~3.7.1 + seaborn=~0.12.2 + configspace==0.6.1 + Pyro4==4.82 # Should be added # [options.packages.find] [options.extras_require] dev = - black>=20.8b1 - scikit-learn==0.23.2 - flake8>=3.8.4 - pytest==6.0.1 - pytest-html==3.1.1 - pytest-cov==2.7.0 - coverage[toml]>=4.0 - pre-commit==2.7.1 + black=~23.1.0 + scikit-learn=~1.2.2 + flake8=~6.0.0 + pytest==7.1.0 + pytest-html==3.2.0 + pytest-cov==4.0.0 + coverage[toml]=~7.2.1 + pre-commit=~3.1.1 example = - chainerrl==0.7.0 - ray==1.0.0 - tabulate==0.8.7 - dm-tree==0.1.5 - opencv-python==4.2.0.32 - stable-baselines - jupyter==1.0.0 + chainerrl + ray + tabulate + dm-tree + opencv-python + stable-baselines3 + jupyter docs = - sphinxcontrib-napoleon==0.7 - sphinx-rtd-theme>=0.5.1 - sphinx-autoapi==1.7.0 - docutils==0.16 - cma==2.7 - modea==0.4.0 - sobol_seq==0.2.0 - modcma==0.0.2.8.2 - IOHexperimenter == 0.2.9.2 - scikit-learn==0.23.2 - torchvision==0.10.0 - torch==1.9.0 - backpack-for-pytorch==1.2.0 + sphinxcontrib-napoleon + sphinx-rtd-theme + sphinx-autoapi + docutils + cma==3.3.0 + modcma==0.0.2.8.4 + IOHexperimenter==0.2.9.2 + scikit-learn=~1.2.2 + torchvision==0.14.1 + torch==1.13.1 + backpack-for-pytorch==1.5.2 all= - gym==0.15.3 - numpy==1.19.2 - scipy==1.4.1 - cma==2.7 - pandas==1.0.3 - matplotlib>=3.1 - seaborn>=0.11 - modea==0.4.0 - sobol_seq==0.2.0 - torchvision==0.10.0 - torch==1.9.0 - backpack-for-pytorch==1.2.0 - modcma == 0.0.2.8.2 - IOHexperimenter == 0.2.9.2 - Pyro4==4.80 + gymnasium==0.27.1 + numpy==1.24.2 + scipy=~1.10.1 + cma==3.3.0 + pandas=~1.5.3 + matplotlib=~3.7.1 + seaborn=~0.12.2 + configspace==0.6.1 + scikit-learn=~1.2.2 + torchvision==0.14.1 + torch==1.13.1 + backpack-for-pytorch==1.5.2 + modcma==0.0.2.8.4 + IOHexperimenter==0.2.9.2 + Pyro4==4.82 #Benchmarks cma= - cma==2.7 -modea= - modea==0.4.0 - sobol_seq==0.2.0 + cma==3.3.0 modcma= - modcma==0.0.2.8.2 - IOHexperimenter == 0.2.9.2 + modcma==0.0.2.8.4 + IOHexperimenter==0.2.9.2 sgd= - scikit-learn==0.23.2 - torchvision==0.10.0 - torch==1.9.0 - backpack-for-pytorch==1.2.0 -theory= - uuid==1.30 -geometric= - matplotlib>=3.1 - numpy==1.19.2 - seaborn>=0.11 + scikit-learn=~1.2.2 + torchvision==0.14.1 + torch==1.13.1 + backpack-for-pytorch==1.5.2 diff --git a/tests/agents/test_dynamic_random_agent.py b/tests/agents/test_dynamic_random_agent.py index eecf6c356..ce6f4c3b4 100644 --- a/tests/agents/test_dynamic_random_agent.py +++ b/tests/agents/test_dynamic_random_agent.py @@ -20,22 +20,23 @@ def test_init(self): def test_deterministic(self): switching_interval = 2 agent, env = self.get_agent(switching_interval) + env.seed_action_space(0) - state = env.reset() + state, _ = env.reset() reward = 0 actions = [] - for i in range(6): + for _ in range(6): action = agent.act(state, reward) state, reward, *_ = env.step(action) actions.append(action) - assert actions == [48, 48, 14, 14, 6, 6] + assert actions == [42, 42, 42, 42, 31, 31] def test_switing_interval(self): switching_interval = 3 agent, env = self.get_agent(switching_interval) - state = env.reset() + state, _ = env.reset() reward = 0 actions = [] for i in range(21): diff --git a/tests/benchmarks/test_fd_benchmark.py b/tests/benchmarks/test_fd_benchmark.py index fba46efb6..f027c5b9f 100644 --- a/tests/benchmarks/test_fd_benchmark.py +++ b/tests/benchmarks/test_fd_benchmark.py @@ -30,9 +30,10 @@ def test_scenarios(self): bench = FastDownwardBenchmark(path) self.assertTrue(bench.config is not None) env = bench.get_environment() - state = env.reset() + state, info = env.reset() self.assertTrue(state is not None) - state, _, _, _ = env.step(0) + self.assertTrue(info is not None) + state, _, _, _, _ = env.step(0) self.assertTrue(state is not None) def test_save_conf(self): diff --git a/tests/benchmarks/test_luby_benchmark.py b/tests/benchmarks/test_luby_benchmark.py index f90bb46d0..9ed2e2fc6 100644 --- a/tests/benchmarks/test_luby_benchmark.py +++ b/tests/benchmarks/test_luby_benchmark.py @@ -21,9 +21,10 @@ def test_scenarios(self): bench = LubyBenchmark(path) self.assertTrue(bench.config is not None) env = bench.get_environment() - state = env.reset() + state, info = env.reset() self.assertTrue(state is not None) - state, _, _, _ = env.step(0) + self.assertTrue(info is not None) + state, _, _, _, _ = env.step(0) self.assertTrue(state is not None) def test_save_conf(self): @@ -54,7 +55,7 @@ def test_benchmark_env(self): env = bench.get_benchmark() self.assertTrue(issubclass(type(env), RewardNoiseWrapper)) env.reset() - _, r, _, _ = env.step(1) + _, r, _, _, _ = env.step(1) self.assertTrue(r != 0 and r != -1) def test_cutoff_setting(self): diff --git a/tests/benchmarks/test_modea_benchmark.py b/tests/benchmarks/test_modea_benchmark.py deleted file mode 100644 index eee3eaa93..000000000 --- a/tests/benchmarks/test_modea_benchmark.py +++ /dev/null @@ -1,48 +0,0 @@ -import unittest -import json -import os - -from dacbench.benchmarks import ModeaBenchmark -from dacbench.envs import ModeaEnv - - -class TestModeaBenchmark(unittest.TestCase): - def test_get_env(self): - bench = ModeaBenchmark() - env = bench.get_environment() - self.assertTrue(issubclass(type(env), ModeaEnv)) - - def test_setup(self): - bench = ModeaBenchmark() - self.assertTrue(bench.config is not None) - - config = {"dummy": 0} - with open("test_conf.json", "w+") as fp: - json.dump(config, fp) - bench = ModeaBenchmark("test_conf.json") - self.assertTrue(bench.config.dummy == 0) - os.remove("test_conf.json") - - def test_save_conf(self): - bench = ModeaBenchmark() - bench.save_config("test_conf.json") - with open("test_conf.json", "r") as fp: - recovered = json.load(fp) - for k in bench.config.keys(): - self.assertTrue(k in recovered.keys()) - os.remove("test_conf.json") - - def test_read_instances(self): - bench = ModeaBenchmark() - bench.read_instance_set() - self.assertTrue(len(bench.config.instance_set.keys()) == 100) - inst = bench.config.instance_set[0] - bench2 = ModeaBenchmark() - env = bench2.get_environment() - self.assertTrue(len(env.instance_set.keys()) == 100) - self.assertTrue(inst == env.instance_set[0]) - - def test_from_to_json(self): - bench = ModeaBenchmark() - restored_bench = ModeaBenchmark.from_json(bench.to_json()) - self.assertEqual(bench, restored_bench) diff --git a/tests/benchmarks/test_sigmoid_benchmark.py b/tests/benchmarks/test_sigmoid_benchmark.py index 2f2eab703..9bf91eed1 100644 --- a/tests/benchmarks/test_sigmoid_benchmark.py +++ b/tests/benchmarks/test_sigmoid_benchmark.py @@ -24,9 +24,10 @@ def test_scenarios(self): bench = SigmoidBenchmark(path) self.assertTrue(bench.config is not None) env = bench.get_environment() - state = env.reset() + state, info = env.reset() self.assertTrue(state is not None) - state, _, _, _ = env.step(0) + self.assertTrue(info is not None) + state, _, _, _, _ = env.step(0) self.assertTrue(state is not None) def test_save_conf(self): diff --git a/tests/container/test_container_utils.py b/tests/container/test_container_utils.py index 1b82f21d7..934d8b847 100644 --- a/tests/container/test_container_utils.py +++ b/tests/container/test_container_utils.py @@ -2,7 +2,7 @@ import unittest import numpy as np -from gym.spaces import Box, Discrete, Tuple, MultiDiscrete, MultiBinary, Dict +from gymnasium.spaces import Box, Discrete, Tuple, MultiDiscrete, MultiBinary, Dict from dacbench.container.container_utils import Encoder, Decoder @@ -20,13 +20,7 @@ def test_spaces(self): serialized = json.dumps(space, cls=Encoder) restored_space = json.loads(serialized, cls=Decoder) self.assertEqual(space, restored_space) - TestEncoder.helper_test_sample(space, restored_space) - @staticmethod - def helper_test_sample(space1, space2): - s1 = space1.sample() - s2 = space2.sample() - np.testing.assert_equal(s1, s2) def test_recursive_spaces(self): tuple_space = Tuple((Box(low=-1, high=1, shape=(2,)), Box(low=-1, high=1, shape=(2,)))) @@ -39,12 +33,4 @@ def test_recursive_spaces(self): serialized = json.dumps(space, cls=Encoder) restored_space = json.loads(serialized, cls=Decoder) self.assertEqual(space, restored_space) - TestEncoder.helper_test_sample(space, restored_space) - - def test_random_state(self): - state = np.random.RandomState(42) - serialized = json.dumps(state, cls=Encoder) - restored_state = json.loads(serialized, cls=Decoder) - np.testing.assert_equal(state.get_state(), restored_state.get_state()) - np.testing.assert_equal(state.random(10), restored_state.random(10)) diff --git a/tests/envs/test_cma.py b/tests/envs/test_cma.py index 5dbe32b3c..a10b19f3f 100644 --- a/tests/envs/test_cma.py +++ b/tests/envs/test_cma.py @@ -1,4 +1,3 @@ - import unittest import numpy as np from dacbench import AbstractEnv @@ -33,17 +32,19 @@ def test_reset(self): def test_step(self): env = self.make_env() env.reset() - state, reward, done, meta = env.step([1]) + _, reward, terminated, truncated, meta = env.step([1]) self.assertTrue(reward >= env.reward_range[0]) print(reward) self.assertTrue(reward <= env.reward_range[1]) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) def test_get_default_state(self): env = self.make_env() - state = env.reset() + state, info = env.reset() self.assertTrue(issubclass(type(state), dict)) + self.assertTrue(issubclass(type(info), dict)) self.assertTrue( np.array_equal( list(state.keys()), @@ -65,7 +66,7 @@ def test_get_default_state(self): self.assertTrue(len(state["history_deltas"]) == 2 * env.history_len) env.step([1]) - state, _, _, _ = env.step([1]) + state, _, _, _, _ = env.step([1]) self.assertTrue(issubclass(type(state), dict)) self.assertTrue( np.array_equal( diff --git a/tests/envs/test_deterministic.py b/tests/envs/test_deterministic.py index a4afb7b22..8f18ecb84 100644 --- a/tests/envs/test_deterministic.py +++ b/tests/envs/test_deterministic.py @@ -14,7 +14,8 @@ def assert_state_space_equal(state1, state2): elif isinstance(state1, dict): assert state1.keys() == state2.keys() for key in state1.keys(): - assert_almost_equal(state1[key], state2[key]) + if 'history' not in key: + assert_almost_equal(state1[key], state2[key]) else: raise NotImplementedError(f"State space type {type(state1)} not comparable") @@ -26,17 +27,17 @@ def run_deterministic_test(self, benchmark_name, seed=42): action = run_baselines.DISCRETE_ACTIONS[benchmark_name][0] env1 = bench.get_benchmark(seed=seed) - init_state1 = env1.reset() - state1, reward1, done1, info1 = env1.step(action) + init_state1, info1 = env1.reset() + _, reward1, terminated1, truncated1, info1 = env1.step(action) env2 = bench.get_benchmark(seed=seed) - init_state2 = env2.reset() - state2, reward2, done2, info2 = env2.step(action) + init_state2, info2 = env2.reset() + _, reward2, terminated2, truncated2, info2 = env2.step(action) assert_state_space_equal(init_state1, init_state2) - assert_state_space_equal(state1, state2) - self.assertEqual(reward1, reward2) - self.assertEqual(done1, done2) + self.assertEqual(info1, info2) + self.assertEqual(terminated1, terminated2) + self.assertEqual(truncated1, truncated2) self.assertEqual(info1, info2) def test_LubyBenchmark(self): @@ -52,19 +53,21 @@ def test_FastDownwardBenchmark(self): action = run_baselines.DISCRETE_ACTIONS[benchmark_name][0] env1 = bench.get_benchmark(seed=seed) - init_state1 = env1.reset() - state1, reward1, done1, info1 = env1.step(action) + init_state1, info1 = env1.reset() + state1, reward1, terminated1, truncated1, info1 = env1.step(action) env1.close() env2 = bench.get_benchmark(seed=seed) - init_state2 = env2.reset() - state2, reward2, done2, info2 = env2.step(action) + init_state2, info2 = env2.reset() + state2, reward2, terminated2, truncated2, info2 = env2.step(action) env2.close() assert_state_space_equal(init_state1, init_state2) assert_state_space_equal(state1, state2) self.assertEqual(reward1, reward2) - self.assertEqual(done1, done2) + self.assertEqual(info1, info2) + self.assertEqual(terminated1, terminated2) + self.assertEqual(truncated1, truncated2) self.assertEqual(info1, info2) def test_CMAESBenchmark(self): diff --git a/tests/envs/test_fd.py b/tests/envs/test_fd.py index 19a12d6f3..d45dd2d15 100644 --- a/tests/envs/test_fd.py +++ b/tests/envs/test_fd.py @@ -22,10 +22,11 @@ def test_reset(self): def test_step(self): env = self.make_env() env.reset() - state, reward, done, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(1) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) self.assertTrue(len(state) == 10) diff --git a/tests/envs/test_geometric.py b/tests/envs/test_geometric.py index 9271d8790..af3580e97 100644 --- a/tests/envs/test_geometric.py +++ b/tests/envs/test_geometric.py @@ -72,8 +72,9 @@ def test_setup(self): def test_reset(self): env = self.make_env(DEFAULTS_STATIC) - state = env.reset() + state, info = env.reset() self.assertTrue(state[0] == DEFAULTS_STATIC["cutoff"]) + self.assertTrue(issubclass(type(info), dict)) self.assertFalse(env._prev_state) self.assertTrue(type(env.action_trajectory) == list) self.assertTrue(type(env.action_trajectory_set) == dict) @@ -81,13 +82,14 @@ def test_reset(self): def test_step(self): env = self.make_env(DEFAULTS_STATIC) env.reset() - state, reward, done, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(1) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[0] == 9) self.assertTrue(type(state) == np.ndarray) self.assertTrue(len(state) == 2 + 2 * env.n_actions) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) def test_close(self): diff --git a/tests/envs/test_luby.py b/tests/envs/test_luby.py index 2d3325252..17d0fc685 100644 --- a/tests/envs/test_luby.py +++ b/tests/envs/test_luby.py @@ -28,7 +28,8 @@ def test_setup(self): def test_reset(self): env = self.make_env() - state = env.reset() + state, info = env.reset() + self.assertTrue(issubclass(type(info), dict)) self.assertTrue(env._start_shift, 1) self.assertTrue(env._sticky_shif, 1) self.assertTrue( @@ -38,28 +39,30 @@ def test_reset(self): def test_step(self): env = self.make_env() env.reset() - state, reward, done, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(1) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[-1] == 0) self.assertTrue(state[0] == 1) self.assertTrue(np.array_equal(state[1:-1], -1 * np.ones(4))) self.assertTrue(len(state) == env._hist_len + 1) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) config = LUBY_DEFAULTS config["instance_set"] = {1: [-4, -4]} env = LubyEnv(config) env.reset() - state, reward, done, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(1) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[-1] == 0) self.assertTrue(state[0] == 1) self.assertTrue(np.array_equal(state[1:-1], -1 * np.ones(4))) self.assertTrue(len(state) == env._hist_len + 1) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) def test_close(self): diff --git a/tests/envs/test_modcma.py b/tests/envs/test_modcma.py index 14aedd735..d266be565 100644 --- a/tests/envs/test_modcma.py +++ b/tests/envs/test_modcma.py @@ -3,7 +3,7 @@ from dacbench import AbstractEnv from dacbench.envs import ModCMAEnv from dacbench.abstract_benchmark import objdict -from gym import spaces +from gymnasium import spaces class TestModCMAEnv(unittest.TestCase): @@ -29,19 +29,22 @@ def test_setup(self): def test_reset(self): env = self.make_env() - env.reset() + state, info = env.reset() + self.assertTrue(issubclass(type(info), dict)) + self.assertTrue(state is not None) def test_step(self): env = self.make_env() env.reset() - state, reward, done, meta = env.step(np.ones(11, dtype=int)) + state, reward, terminated, truncated, meta = env.step(np.ones(11, dtype=int)) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) self.assertTrue(len(state) == 5) - while not done: - _, _, done, _ = env.step(env.action_space.sample()) + while not (terminated or truncated): + _, _, terminated, truncated, _ = env.step(env.action_space.sample()) def test_close(self): env = self.make_env() diff --git a/tests/envs/test_modea.py b/tests/envs/test_modea.py deleted file mode 100644 index f964fed3c..000000000 --- a/tests/envs/test_modea.py +++ /dev/null @@ -1,48 +0,0 @@ -import unittest -import numpy as np -from dacbench import AbstractEnv -from dacbench.envs import ModeaEnv -from dacbench.abstract_benchmark import objdict -from gym import spaces - - -class TestModeaEnv(unittest.TestCase): - def make_env(self): - config = objdict({}) - config.budget = 20 - config.datapath = "." - config.threshold = 1e-8 - config.instance_set = {2: [10, 12, 0, np.ones(11)]} - config.cutoff = 10 - config.benchmark_info = None - config.action_space = spaces.MultiDiscrete([2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3]) - config.observation_space = spaces.Box( - low=-np.inf * np.ones(5), high=np.inf * np.ones(5) - ) - config.reward_range = (-(10 ** 12), 0) - env = ModeaEnv(config) - return env - - def test_setup(self): - env = self.make_env() - self.assertTrue(issubclass(type(env), AbstractEnv)) - - def test_reset(self): - env = self.make_env() - env.reset() - - def test_step(self): - env = self.make_env() - env.reset() - state, reward, done, meta = env.step(np.ones(14)) - self.assertTrue(reward >= env.reward_range[0]) - self.assertTrue(reward <= env.reward_range[1]) - self.assertFalse(done) - self.assertTrue(len(meta.keys()) == 0) - self.assertTrue(len(state) == 5) - while not done: - _, _, done, _ = env.step(env.action_space.sample()) - - def test_close(self): - env = self.make_env() - self.assertTrue(env.close()) diff --git a/tests/envs/test_sgd.py b/tests/envs/test_sgd.py index 431c1adde..6b200ac17 100644 --- a/tests/envs/test_sgd.py +++ b/tests/envs/test_sgd.py @@ -64,16 +64,17 @@ def test_step(self): self.assertTrue(env.reward_range == reward_type.func.frange) env.reset() - state, reward, done, meta = env.step(1.0) + _, reward, terminated, truncated, meta = env.step(1.0) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) def test_crash(self): env = ObservationWrapper(self.env) env.reset() - state, reward, done, _ = env.step(np.nan) + state, reward, terminated, truncated, _ = env.step(np.nan) self.assertTrue(env.crashed) self.assertFalse(any(np.isnan(state))) self.assertTrue(reward == env.crash_penalty) @@ -87,13 +88,13 @@ def test_stateless(self): env.reset() instance_idxs.append(env.instance_index) - done = False + terminated, truncated = False, False mem = [] step = 0 - while not done and step < 5: + while not (terminated or truncated) and step < 5: action = np.exp(rng.integers(low=-10, high=1)) - state, reward, done, _ = env.step(action) - mem.append(np.concatenate([state, [reward, int(done), action]])) + state, reward, terminated, truncated, _ = env.step(action) + mem.append(np.concatenate([state, [reward, int(truncated), action]])) step += 1 mems.append(np.array(mem)) @@ -103,13 +104,13 @@ def test_stateless(self): env.reset() self.assertTrue(env.instance_index == idx) - done = False + terminated, truncated = False, False mem = [] step = 0 - while not done and step < 5: + while not (terminated or truncated) and step < 5: action = mems[-(i + 1)][step][-1] - state, reward, done, _ = env.step(action) - mem.append(np.concatenate([state, [reward, int(done), action]])) + state, reward, terminated, truncated, _ = env.step(action) + mem.append(np.concatenate([state, [reward, int(truncated), action]])) step += 1 np.testing.assert_allclose(mems[-(i + 1)], np.array(mem)) @@ -125,13 +126,13 @@ def test_reproducibility(self): env.reset() - done = False + terminated, truncated = False, False mem = [] step = 0 - while not done and step < 5: + while not (terminated or truncated) and step < 5: action = np.exp(rng.integers(low=-10, high=1)) - state, reward, done, _ = env.step(action) - mem.append(np.concatenate([state, [reward, int(done), action]])) + state, reward, terminated, truncated, _ = env.step(action) + mem.append(np.concatenate([state, [reward, int(truncated), action]])) step += 1 mems.append(np.array(mem)) self.assertEqual(mems[0].size, mems[1].size) @@ -140,7 +141,7 @@ def test_reproducibility(self): def test_get_default_state(self): self.env.reset() - state, _, _, _ = self.env.step(0.5) + state, _, _, _, _ = self.env.step(0.5) self.assertTrue(issubclass(type(state), dict)) self.assertTrue( np.array_equal( diff --git a/tests/envs/test_sigmoid.py b/tests/envs/test_sigmoid.py index 7ee3690d2..52cae6678 100644 --- a/tests/envs/test_sigmoid.py +++ b/tests/envs/test_sigmoid.py @@ -34,7 +34,8 @@ def test_setup(self): def test_reset(self): env = self.make_env() - state = env.reset() + state, info = env.reset() + self.assertTrue(issubclass(type(info), dict)) self.assertTrue(np.array_equal(env.shifts, [0, 1])) self.assertTrue(np.array_equal(env.slopes, [2, 3])) self.assertTrue(state[0] == SIGMOID_DEFAULTS["cutoff"]) @@ -45,14 +46,15 @@ def test_reset(self): def test_step(self): env = self.make_env() env.reset() - state, reward, done, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(1) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[0] == 9) self.assertTrue(np.array_equal([state[1], state[3]], env.shifts)) self.assertTrue(np.array_equal([state[2], state[4]], env.slopes)) self.assertTrue(len(state) == 7) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(meta.keys()) == 0) def test_close(self): diff --git a/tests/envs/test_theory_env.py b/tests/envs/test_theory_env.py index f6f7bb9e0..f746ff492 100644 --- a/tests/envs/test_theory_env.py +++ b/tests/envs/test_theory_env.py @@ -1,6 +1,6 @@ from dacbench.benchmarks import TheoryBenchmark import unittest -import gym +import gymnasium as gym class TestTheoryEnv(unittest.TestCase): @@ -15,7 +15,7 @@ def test_discrete_env(self): env = bench.get_environment() # check observation space - s = env.reset() # default observation space: n, f(x) + s, _ = env.reset() # default observation space: n, f(x) assert len(s) == 2 assert s[0] == env.n assert s[1] == env.x.fitness @@ -45,7 +45,7 @@ def test_non_discrete_env(self): env = bench.get_environment() # check observation space - s = env.reset() # default observation space: n, f(x) + s, _ = env.reset() # default observation space: n, f(x) assert len(s) == 2 assert s[0] == env.n assert s[1] == env.x.fitness @@ -63,11 +63,11 @@ def test_non_discrete_env(self): env.reset() # check behaviour with out-of-range action - s, r, d, info = env.step( + s, r, terminated, truncated, info = env.step( 100 ) # a large negative reward will be returned and the epsidoe will end assert r < -1e4 - assert d + assert terminated or truncated if __name__ == "__main__": diff --git a/tests/test_abstract_benchmark.py b/tests/test_abstract_benchmark.py index cafa4446e..b13e0cf93 100644 --- a/tests/test_abstract_benchmark.py +++ b/tests/test_abstract_benchmark.py @@ -2,7 +2,7 @@ import json import os import numpy as np -from gym.spaces import Box, Discrete, Dict, MultiDiscrete, MultiBinary +from gymnasium.spaces import Box, Discrete, Dict, MultiDiscrete, MultiBinary from dacbench.abstract_benchmark import AbstractBenchmark, objdict import tempfile diff --git a/tests/test_abstract_env.py b/tests/test_abstract_env.py index f12b4f0be..f84facd79 100644 --- a/tests/test_abstract_env.py +++ b/tests/test_abstract_env.py @@ -2,7 +2,7 @@ import unittest import numpy as np -from gym import spaces +from gymnasium import spaces from dacbench.abstract_env import AbstractEnv @@ -18,7 +18,7 @@ def test_not_implemented_methods(self): def test_exceptions(self): config = { "action_space_class": "Discrete", - "action_space_args": np.array([4]).astype(np.float32), + "action_space_args": [4], "observation_space_class": "Dict", "observation_space_type": np.float32, "observation_space_args": [ @@ -35,7 +35,7 @@ def test_exceptions(self): config = { "action_space_class": "Discrete", - "action_space_args": np.array([4]).astype(np.float32), + "action_space_args": [4], "observation_space_class": "Box", "observation_space_type": np.float32, "reward_range": (-1, 0), @@ -48,7 +48,7 @@ def test_exceptions(self): config = { "action_space_class": "Discrete", - "action_space_args": np.array([4]).astype(np.float32), + "action_space_args": [4], "observation_space_type": np.float32, "observation_space_args": [ np.array([-1, -1, -1], dtype=np.float32), @@ -98,7 +98,7 @@ def test_exceptions(self): def make_env(self): config = { "action_space_class": "Discrete", - "action_space_args": np.array([4]).astype(np.float32), + "action_space_args": [4], "observation_space_class": "Box", "observation_space_type": np.float32, "observation_space_args": [ diff --git a/tests/test_logger.py b/tests/test_logger.py index 6fcce3283..d1b3ee331 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -36,11 +36,11 @@ def setUp(self) -> None: logger.reset_episode() for episode in range(episodes): - state = env.reset() - done = False + state, _ = env.reset() + terminated, truncated = False, False reward = 0 step = 0 - while not done: + while not (terminated or truncated): action = agent.act(state, reward) env_logger.log( "logged_step", @@ -54,14 +54,18 @@ def setUp(self) -> None: "logged_episode", episode, ) - next_state, reward, done, _ = env.step(action) + next_state, reward, terminated, truncated, _ = env.step(action) env_logger.log( "reward", reward, ) env_logger.log( - "done", - done, + "terminated", + terminated, + ) + env_logger.log( + "truncated", + truncated, ) agent.train(next_state, reward) state = next_state diff --git a/tests/test_runner.py b/tests/test_runner.py index 769038722..904c946e4 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -3,7 +3,7 @@ import pytest import unittest -from gym import spaces +from gymnasium import spaces import os import numpy as np diff --git a/tests/wrappers/test_action_tracking_wrapper.py b/tests/wrappers/test_action_tracking_wrapper.py index 54dc19a0a..37790be80 100644 --- a/tests/wrappers/test_action_tracking_wrapper.py +++ b/tests/wrappers/test_action_tracking_wrapper.py @@ -2,17 +2,17 @@ import unittest from pathlib import Path -import gym +import gymnasium as gym import numpy as np import pandas as pd -from dacbench.agents import RandomAgent +from dacbench.agents import StaticAgent from dacbench.benchmarks import ( LubyBenchmark, FastDownwardBenchmark, CMAESBenchmark, - ModeaBenchmark, + ModCMABenchmark ) from dacbench.logger import Logger, load_logs, log2dataframe from dacbench.runner import run_benchmark @@ -31,13 +31,14 @@ def test_logging_multi_discrete(self): episode_write_frequency=1, ) - bench = ModeaBenchmark() + bench = ModCMABenchmark() bench.set_seed(seed) env = bench.get_environment() env.seed_action_space(seed) action_logger = logger.add_module(ActionFrequencyWrapper) wrapped = ActionFrequencyWrapper(env, logger=action_logger) - agent = RandomAgent(env) + action = env.action_space.sample() + agent = StaticAgent(env, action) logger.set_env(env) run_benchmark(wrapped, agent, 1, logger) @@ -48,149 +49,17 @@ def test_logging_multi_discrete(self): expected_actions = pd.DataFrame( { - "action_0": { - 0: 0, - 1: 1, - 2: 0, - 3: 1, - 4: 1, - 5: 0, - 6: 1, - 7: 1, - 8: 0, - 9: 0, - 10: 0, - }, - "action_1": { - 0: 1, - 1: 0, - 2: 1, - 3: 0, - 4: 0, - 5: 1, - 6: 0, - 7: 1, - 8: 0, - 9: 0, - 10: 1, - }, - "action_10": { - 0: 0, - 1: 0, - 2: 1, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 2, - 8: 1, - 9: 2, - 10: 1, - }, - "action_2": { - 0: 1, - 1: 1, - 2: 1, - 3: 0, - 4: 1, - 5: 1, - 6: 1, - 7: 1, - 8: 0, - 9: 0, - 10: 1, - }, - "action_3": { - 0: 0, - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 1, - 7: 0, - 8: 0, - 9: 1, - 10: 1, - }, - "action_4": { - 0: 0, - 1: 1, - 2: 1, - 3: 0, - 4: 1, - 5: 0, - 6: 0, - 7: 1, - 8: 0, - 9: 1, - 10: 0, - }, - "action_5": { - 0: 1, - 1: 0, - 2: 0, - 3: 0, - 4: 1, - 5: 1, - 6: 1, - 7: 0, - 8: 0, - 9: 0, - 10: 1, - }, - "action_6": { - 0: 0, - 1: 1, - 2: 1, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 1, - 9: 0, - 10: 0, - }, - "action_7": { - 0: 1, - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 1, - 8: 1, - 9: 1, - 10: 0, - }, - "action_8": { - 0: 0, - 1: 1, - 2: 0, - 3: 1, - 4: 1, - 5: 1, - 6: 0, - 7: 1, - 8: 0, - 9: 0, - 10: 1, - }, - "action_9": { - 0: 1, - 1: 2, - 2: 1, - 3: 0, - 4: 0, - 5: 1, - 6: 1, - 7: 1, - 8: 2, - 9: 0, - 10: 2, - }, + "action_0": [action[0]]*10, + "action_1": [action[1]]*10, + "action_10": [action[10]]*10, + "action_2": [action[2]]*10, + "action_3": [action[3]]*10, + "action_4": [action[4]]*10, + "action_5": [action[5]]*10, + "action_6": [action[6]]*10, + "action_7": [action[7]]*10, + "action_8": [action[8]]*10, + "action_9": [action[9]]*10, } ) @@ -224,7 +93,8 @@ def test_logging_discrete(self): action_logger = logger.add_module(ActionFrequencyWrapper) wrapped = ActionFrequencyWrapper(env, logger=action_logger) - agent = RandomAgent(env) + action = env.action_space.sample() + agent = StaticAgent(env, action) logger.set_env(env) run_benchmark(wrapped, agent, 10, logger) @@ -233,89 +103,8 @@ def test_logging_discrete(self): logs = load_logs(action_logger.get_logfile()) dataframe = log2dataframe(logs, wide=True) - expected_actions = [ - 0, - 3, - 5, - 4, - 3, - 5, - 5, - 5, - 3, - 3, - 2, - 1, - 0, - 1, - 2, - 0, - 1, - 1, - 0, - 1, - 2, - 4, - 3, - 0, - 1, - 3, - 0, - 3, - 3, - 3, - 4, - 4, - 4, - 5, - 4, - 0, - 4, - 2, - 1, - 3, - 4, - 2, - 1, - 3, - 3, - 2, - 0, - 5, - 2, - 5, - 2, - 1, - 5, - 3, - 2, - 5, - 1, - 0, - 2, - 3, - 1, - 3, - 2, - 3, - 2, - 4, - 3, - 4, - 0, - 5, - 5, - 1, - 5, - 0, - 1, - 5, - 5, - 3, - 3, - 2, - ] - + expected_actions = [action]*80 + self.assertListEqual(dataframe.action.to_list(), expected_actions) temp_dir.cleanup() @@ -340,13 +129,15 @@ def test_step(self): env = bench.get_environment() wrapped = ActionFrequencyWrapper(env, 10) - state = wrapped.reset() + state, info = wrapped.reset() + self.assertTrue(issubclass(type(info), dict)) self.assertTrue(len(state) > 1) - state, reward, done, _ = wrapped.step(1) + state, reward, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(state) > 1) self.assertTrue(reward <= 0) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(wrapped.overall_actions) == 1) self.assertTrue(wrapped.overall_actions[0] == 1) @@ -412,10 +203,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} def step(self, action): - return 1, 1, 1, 1 + return 1, 1, 1, 1, {} env = dict_action_env() wrapped = ActionFrequencyWrapper(env) @@ -436,10 +227,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} def step(self, action): - return 1, 1, 1, 1 + return 1, 1, 1, 1, {} env = tuple_action_env() wrapped = ActionFrequencyWrapper(env) @@ -455,10 +246,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} def step(self, action): - return 1, 1, 1, 1 + return 1, 1, 1, 1, {} env = multi_discrete_action_env() wrapped = ActionFrequencyWrapper(env, 5) @@ -476,10 +267,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} def step(self, action): - return 1, 1, 1, 1 + return 1, 1, 1, 1, {} env = multi_binary_action_env() wrapped = ActionFrequencyWrapper(env) @@ -496,10 +287,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} def step(self, action): - return 1, 1, 1, 1 + return 1, 1, 1, 1, {} env = large_action_env() wrapped = ActionFrequencyWrapper(env) diff --git a/tests/wrappers/test_observation_wrapper.py b/tests/wrappers/test_observation_wrapper.py index edb56215f..44d2b08e1 100644 --- a/tests/wrappers/test_observation_wrapper.py +++ b/tests/wrappers/test_observation_wrapper.py @@ -26,21 +26,21 @@ def test_conversion_wrapper(self): action = 0.2 env = self.get_test_env() - reset_state_env = env.reset() + reset_state_env, info = env.reset() step_state_env, *rest_env = env.step(action) self.assertIsInstance(reset_state_env, dict) + self.assertTrue(issubclass(type(info), dict)) wrapped_env = ObservationWrapper(self.get_test_env()) - reset_state_wrapped = wrapped_env.reset() - step_state_wrapped, *reset_wrapped = wrapped_env.step(action) + reset_state_wrapped, info = wrapped_env.reset() + step_state_wrapped, *rest_wrapped = wrapped_env.step(action) self.assertIsInstance(reset_state_wrapped, np.ndarray) - - self.assertListEqual(rest_env, reset_wrapped) + self.assertListEqual(rest_env[1:], rest_wrapped[1:]) np.testing.assert_array_equal( - wrapped_env.flatten(reset_state_env), reset_state_wrapped + wrapped_env.flatten(reset_state_env).shape, reset_state_wrapped.shape ) np.testing.assert_array_equal( - wrapped_env.flatten(step_state_env), step_state_wrapped + wrapped_env.flatten(step_state_env).shape, step_state_wrapped.shape ) diff --git a/tests/wrappers/test_performance_tracking_wrapper.py b/tests/wrappers/test_performance_tracking_wrapper.py index 3db7eaf3d..6c72de0f3 100644 --- a/tests/wrappers/test_performance_tracking_wrapper.py +++ b/tests/wrappers/test_performance_tracking_wrapper.py @@ -28,50 +28,52 @@ def test_step(self): env = bench.get_environment() wrapped = PerformanceTrackingWrapper(env, 2) - state = wrapped.reset() + state, info = wrapped.reset() self.assertTrue(len(state) > 1) + self.assertTrue(issubclass(type(info), dict)) - state, reward, done, _ = wrapped.step(1) + state, reward, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(state) > 1) self.assertTrue(reward <= 0) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) - while not done: - _, _, done, _ = wrapped.step(1) + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.overall_performance) == 1) self.assertTrue(len(wrapped.performance_intervals) == 0) self.assertTrue(len(wrapped.current_performance) == 1) self.assertTrue(len(wrapped.instance_performances.keys()) == 1) - done = False - while not done: - _, _, done, _ = wrapped.step(1) - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.performance_intervals) == 1) self.assertTrue(len(wrapped.current_performance) == 1) wrapped.reset() - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) wrapped.reset() - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.instance_performances.keys()) == 3) wrapped.reset() - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) wrapped.reset() - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.instance_performances.keys()) == 4) def test_get_performance(self): @@ -79,14 +81,14 @@ def test_get_performance(self): env = bench.get_environment() wrapped = PerformanceTrackingWrapper(env) wrapped.reset() - done = False - while not done: - _, _, done, _ = wrapped.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) wrapped2 = PerformanceTrackingWrapper(env, 2) wrapped2.reset() - done = False - while not done: - _, _, done, _ = wrapped2.step(1) + terminated, truncated = False, False + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped2.step(1) wrapped3 = PerformanceTrackingWrapper(env, 2, track_instance_performance=False) wrapped3.reset() for i in range(5): @@ -129,10 +131,10 @@ def test_render(self, mock_plt): env = bench.get_environment() env = PerformanceTrackingWrapper(env) for _ in range(10): - done = False + terminated, truncated = False, False env.reset() - while not done: - _, _, done, _ = env.step(1) + while not (terminated or truncated): + _, _, terminated, truncated, _ = env.step(1) env.render_performance() self.assertTrue(mock_plt.show.called) env.render_instance_performance() diff --git a/tests/wrappers/test_policy_progress_wrapper.py b/tests/wrappers/test_policy_progress_wrapper.py index df84627e5..6637247d0 100644 --- a/tests/wrappers/test_policy_progress_wrapper.py +++ b/tests/wrappers/test_policy_progress_wrapper.py @@ -34,10 +34,10 @@ def test_step(self): wrapped = PolicyProgressWrapper(env, compute_optimal_sigmoid) wrapped.reset() - _, _, done, _ = wrapped.step(1) + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.episode) == 1) - while not done: - _, _, done, _ = wrapped.step(1) + while not (terminated or truncated): + _, _, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(wrapped.episode) == 0) self.assertTrue(len(wrapped.policy_progress) == 1) @@ -48,9 +48,9 @@ def test_render(self, mock_plt): env = bench.get_environment() env = PolicyProgressWrapper(env, compute_optimal_sigmoid) for _ in range(2): - done = False + terminated, truncated = False, False env.reset() - while not done: - _, _, done, _ = env.step(1) + while not (terminated or truncated): + _, _, terminated, truncated, _ = env.step(1) env.render_policy_progress() self.assertTrue(mock_plt.show.called) diff --git a/tests/wrappers/test_reward_noise_wrapper.py b/tests/wrappers/test_reward_noise_wrapper.py index edb997c8d..1cc33ed9d 100644 --- a/tests/wrappers/test_reward_noise_wrapper.py +++ b/tests/wrappers/test_reward_noise_wrapper.py @@ -31,18 +31,18 @@ def test_step(self): bench.config.reward_range = (-10, 10) env = bench.get_environment() env.reset() - _, raw_reward, _, _ = env.step(1) + _, raw_reward, _, _, _ = env.step(1) wrapped = RewardNoiseWrapper(env) wrapped.reset() - _, reward, _, _ = wrapped.step(1) + _, reward, _, _, _ = wrapped.step(1) self.assertTrue(reward != raw_reward) wrapped = RewardNoiseWrapper(env, noise_dist="normal", dist_args=[0, 0.3]) wrapped.reset() env.reset() - _, raw_reward, _, _ = env.step(1) - _, reward, _, _ = wrapped.step(1) + _, raw_reward, _, _, _ = env.step(1) + _, reward, _, _, _ = wrapped.step(1) self.assertTrue(reward != raw_reward) def dummy(): @@ -50,7 +50,7 @@ def dummy(): wrapped = RewardNoiseWrapper(env, noise_function=dummy) wrapped.reset() - _, reward, _, _ = wrapped.step(1) + _, reward, _, _, _ = wrapped.step(1) self.assertTrue(reward == 0 or reward == -1) def test_getters_and_setters(self): diff --git a/tests/wrappers/test_state_tracking_wrapper.py b/tests/wrappers/test_state_tracking_wrapper.py index 23963472b..9d3723dee 100644 --- a/tests/wrappers/test_state_tracking_wrapper.py +++ b/tests/wrappers/test_state_tracking_wrapper.py @@ -3,7 +3,7 @@ from itertools import groupby from pathlib import Path -import gym +import gymnasium as gym import numpy as np @@ -126,20 +126,22 @@ def test_step_reset(self): env = bench.get_environment() wrapped = StateTrackingWrapper(env, 2) - state = wrapped.reset() + state, info = wrapped.reset() + self.assertTrue(issubclass(type(info), dict)) self.assertTrue(len(state) > 1) self.assertTrue(len(wrapped.overall_states) == 1) - state, reward, done, _ = wrapped.step(1) + state, reward, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(state) > 1) self.assertTrue(reward <= 0) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(wrapped.overall_states) == 2) self.assertTrue(len(wrapped.current_states) == 2) self.assertTrue(len(wrapped.state_intervals) == 0) - state = wrapped.reset() + state, _ = wrapped.reset() self.assertTrue(len(wrapped.overall_states) == 3) self.assertTrue(len(wrapped.current_states) == 1) self.assertTrue(len(wrapped.state_intervals) == 1) @@ -225,10 +227,10 @@ def __init__(self): self.metadata = {} def reset(self): - return 1 + return 1, {} - def step(self, action): - return 1, 1, 1, 1 + def step(self, _): + return 1, 1, 1, 1, {} env = discrete_obs_env() wrapped = StateTrackingWrapper(env, 2) @@ -245,10 +247,10 @@ def __init__(self): self.metadata = {} def reset(self): - return [1, 2] + return [1, 2], {} - def step(self, action): - return [1, 2], 1, 1, 1 + def step(self, _): + return [1, 2], 1, 1, 1, {} env = multi_discrete_obs_env() wrapped = StateTrackingWrapper(env) @@ -265,10 +267,10 @@ def __init__(self): self.metadata = {} def reset(self): - return [1, 1] + return [1, 1], {} - def step(self, action): - return [1, 1], 1, 1, 1 + def step(self, _): + return [1, 1], 1, 1, 1, {} env = multi_binary_obs_env() wrapped = StateTrackingWrapper(env) diff --git a/tests/wrappers/test_time_tracking_wrapper.py b/tests/wrappers/test_time_tracking_wrapper.py index c63d5c2e7..2d832d7c5 100644 --- a/tests/wrappers/test_time_tracking_wrapper.py +++ b/tests/wrappers/test_time_tracking_wrapper.py @@ -69,13 +69,15 @@ def test_step(self): env = bench.get_environment() wrapped = EpisodeTimeWrapper(env, 10) - state = wrapped.reset() + state, info = wrapped.reset() + self.assertTrue(issubclass(type(info), dict)) self.assertTrue(len(state) > 1) - state, reward, done, _ = wrapped.step(1) + state, reward, terminated, truncated, _ = wrapped.step(1) self.assertTrue(len(state) > 1) self.assertTrue(reward <= 0) - self.assertFalse(done) + self.assertFalse(terminated) + self.assertFalse(truncated) self.assertTrue(len(wrapped.all_steps) == 1) self.assertTrue(len(wrapped.current_step_interval) == 1) From 9e8f68a28f8ce784c29dd03986a9e1d63b6c13fd Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 13:29:55 +0100 Subject: [PATCH 02/44] MA interface draft --- dacbench/__init__.py | 6 +- dacbench/abstract_env.py | 138 ++++++++++++++++++ dacbench/benchmarks/geometric_benchmark.py | 10 +- dacbench/benchmarks/modcma_benchmark.py | 1 + dacbench/benchmarks/sigmoid_benchmark.py | 14 +- dacbench/benchmarks/toysgd_benchmark.py | 1 + dacbench/envs/geometric.py | 24 +-- dacbench/envs/modcma.py | 4 +- dacbench/envs/sigmoid.py | 83 +---------- dacbench/envs/toysgd.py | 4 +- .../wrappers/multidiscrete_action_wrapper.py | 34 +++++ tests/benchmarks/test_sigmoid_benchmark.py | 9 +- tests/test_multi_agent_interface.py | 66 +++++++++ 13 files changed, 268 insertions(+), 126 deletions(-) create mode 100644 dacbench/wrappers/multidiscrete_action_wrapper.py create mode 100644 tests/test_multi_agent_interface.py diff --git a/dacbench/__init__.py b/dacbench/__init__.py index 08e6071b6..31d9d5c01 100644 --- a/dacbench/__init__.py +++ b/dacbench/__init__.py @@ -1,8 +1,8 @@ """DACBench: a benchmark library for Dynamic Algorithm Configuration""" -__version__ = "0.0.1" +__version__ = "0.2.0" __contact__ = "automl.org" -from dacbench.abstract_env import AbstractEnv +from dacbench.abstract_env import AbstractEnv, AbstractMADACEnv from dacbench.abstract_benchmark import AbstractBenchmark -__all__ = ["AbstractEnv", "AbstractBenchmark"] +__all__ = ["AbstractEnv", "AbstractMADACEnv", "AbstractBenchmark"] diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index 350515744..5268d4ef1 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -379,3 +379,141 @@ def use_training_set(self): self.instance_id_list = self.training_id_list self.inst_id = self.training_inst_id self.instance = self.training_instance + + +class AbstractMADACEnv(AbstractEnv): + def __init__(self, config): + """ + Initialize environment + + Parameters + ------- + config : dict + Environment configuration + If to seed the action space as well + """ + super(AbstractMADACEnv, self).__init__(config) + self.multi_agent = False + if 'multi_agent' in config.keys(): + self.multi_agent = config.multi_agent + + if self.multi_agent: + space_class = type(self.env.action_space) + if space_class == gym.spaces.Box: + num_hps = len(self.env.action_space.low) + elif space_class == gym.spaces.MultiDiscrete: + num_hps = len(self.env.action_space.nvec) + else: + print( + "The MultiAgent environment currently only supports action spaces of types Box and MultiDiscrete" + ) + raise TypeError + self.possible_agents = np.arange(num_hps) + self.hp_names = [] + if 'config_space' self.config.keys(): + self.hp_names = self.config['config_space'].get_hyperparameter_names() + self.max_num_agent = len(self.possible_agents) + self.env_step = self.step + self.env_reset = self.reset + self.step = self.multi_agent_step + self.reset = self.multi_agent_reset + self.agents = [] + self.current_agent = None + self.observation = None + self.reward = None + self.termination = False + self.truncation = False + self.info = None + # TODO: this should be set to a reasonable default, ideally + # Else playing with less than the full number of agents will be really hard + self.action = self.env.action_space.sample() + + def multi_agent_reset(self, seed: int = None): + self.observation, self.info = self.env_reset(seed) + + def last(self): + return self.observation, self.reward, self.termination, self.truncation, self.info + + def multi_agent_step(self, action): + self.action[self.current_agent] = action + self.current_agent = self.agents.index(self.current_agent) + 1 + if self.current_agent >= len(self.agents): + self.observation, self.reward, self.termination, self.truncation, self.info = self.env_step(self.action) + self.current_agent = self.agents[0] + + def register_agent(self, agent_id): + if type(agent_id) == str: + if len(agent_id) > 1: + if agent_id in self.hp_names: + agent_id = self.hp_names.index(agent_id) + else: + agent_id = int(agent_id) + assert agent_id not in self.agents + assert agent_id in self.possible_agents + self.agents.append(agent_id) + if self.current_agent is None: + self.current_agent = agent_id + + def remove_agent(self, agent_id): + if agent_id in self.agents: + self.agents.remove(agent_id) + + @property + def num_agents(self): + return len(self.agents) + + @property + def agent_selection(self): + return self.current_agent + + @property + def action_spaces(self): + space_class = type(self.env.action_space) + if space_class == gym.spaces.Box: + lowers = self.env.action_space.low + uppers = self.env.action_space.high + else: + num_options = [len(n) for n in self.env.action_space.nvec] + action_spaces = {} + for a in self.agents: + if space_class == gym.spaces.Box: + subspace = gym.spaces.Box(low=[lowers[a]], high=[uppers[a]]) + else: + subspace = gym.spaces.Discrete(num_options[a]) + action_spaces[a] = subspace + return action_spaces + + @property + def observation_spaces(self): + obs_spaces = {} + for a in self.agents: + obs_spaces[a] = self.env.observation_space + return obs_spaces + + @property + def infos(self): + infos = {} + for a in self.agents: + infos[a] = self.info + return infos + + @property + def rewards(self): + rewards = {} + for a in self.agents: + rewards[a] = self.rewards + return rewards + + @property + def terminations(self): + terminations = {} + for a in self.agents: + terminations[a] = self.termination + return terminations + + @property + def truncations(self): + truncations = {} + for a in self.agents: + truncations[a] = self.truncation + return truncations diff --git a/dacbench/benchmarks/geometric_benchmark.py b/dacbench/benchmarks/geometric_benchmark.py index 4db8224e4..470fa4f1f 100644 --- a/dacbench/benchmarks/geometric_benchmark.py +++ b/dacbench/benchmarks/geometric_benchmark.py @@ -28,6 +28,7 @@ "observation_space_args": [], "reward_range": (0, 1), "seed": 0, + "multi_agent": False, "cutoff": 10, "action_values": [], "action_value_default": 4, @@ -233,10 +234,11 @@ def set_action_values(self): self.config.action_values = values cs = CS.ConfigurationSpace() - actions = CSH.UniformIntegerHyperparameter( - name="curve_values", lower=0, upper=int(np.prod(values)) - ) - cs.add_hyperparameter(actions) + for i, v in enumerate(values): + actions = CSH.UniformIntegerHyperparameter( + name=f"curve_values_dim_{i}", lower=0, upper=v + ) + cs.add_hyperparameter(actions) self.config.config_space = cs num_info = 2 diff --git a/dacbench/benchmarks/modcma_benchmark.py b/dacbench/benchmarks/modcma_benchmark.py index 16c2dc10b..9e3da38a8 100644 --- a/dacbench/benchmarks/modcma_benchmark.py +++ b/dacbench/benchmarks/modcma_benchmark.py @@ -70,6 +70,7 @@ "budget": 100, "cutoff": 1e6, "seed": 0, + "multi_agent": False, "instance_set_path": os.path.join( os.path.dirname(os.path.abspath(__file__)), "../instance_sets/modea/modea_train.csv", diff --git a/dacbench/benchmarks/sigmoid_benchmark.py b/dacbench/benchmarks/sigmoid_benchmark.py index a6a9366e6..21342816a 100644 --- a/dacbench/benchmarks/sigmoid_benchmark.py +++ b/dacbench/benchmarks/sigmoid_benchmark.py @@ -10,8 +10,9 @@ ACTION_VALUES = (5, 10) DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -X = CSH.UniformIntegerHyperparameter(name='value_index', lower=0, upper=int(np.prod(ACTION_VALUES))) -DEFAULT_CFG_SPACE.add_hyperparameter(X) +for i, d in enumerate(ACTION_VALUES): + X = CSH.UniformIntegerHyperparameter(name=f'value_dim_{i}', lower=0, upper=d-1) + DEFAULT_CFG_SPACE.add_hyperparameter(X) INFO = { "identifier": "Sigmoid", @@ -31,8 +32,8 @@ SIGMOID_DEFAULTS = objdict( { "config_space": DEFAULT_CFG_SPACE, - "action_space_class": "Discrete", - "action_space_args": [int(np.prod(ACTION_VALUES))], + "action_space_class": "MultiDiscrete", + "action_space_args": list(int(ACTION_VALUES)), "observation_space_class": "Box", "observation_space_type": np.float32, "observation_space_args": [ @@ -44,6 +45,7 @@ "action_values": ACTION_VALUES, "slope_multiplier": 2.0, "seed": 0, + "multi_agent": False, "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", "test_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_test.csv", "benchmark_info": INFO, @@ -102,7 +104,7 @@ def get_environment(self): ): # ... in both actions and x-axis state, only ... env = ContinuousSigmoidEnv(self.config) elif ( - self.config["action_space"] == "Discrete" + self.config["action_space"] == "MultiDiscrete" ): # ... continuous in the x-axis state or ... env = ContinuousStateSigmoidEnv(self.config) else: @@ -130,7 +132,7 @@ def set_action_values(self, values): A list of possible actions per dimension """ self.config.action_values = values - self.config.action_space_args = [int(np.prod(values))] + self.config.action_space_args = list(int(values)) self.config.observation_space_args = [ np.array([-np.inf for _ in range(1 + len(values) * 3)]), np.array([np.inf for _ in range(1 + len(values) * 3)]), diff --git a/dacbench/benchmarks/toysgd_benchmark.py b/dacbench/benchmarks/toysgd_benchmark.py index 716a4f9c4..b19dcc010 100644 --- a/dacbench/benchmarks/toysgd_benchmark.py +++ b/dacbench/benchmarks/toysgd_benchmark.py @@ -46,6 +46,7 @@ "reward_range": (-np.inf, np.inf), "cutoff": 10, "seed": 0, + "multi_agent": False, "instance_set_path": "../instance_sets/toysgd/toysgd_default.csv", "benchmark_info": INFO, } diff --git a/dacbench/envs/geometric.py b/dacbench/envs/geometric.py index b0ddefac1..5620a7c99 100644 --- a/dacbench/envs/geometric.py +++ b/dacbench/envs/geometric.py @@ -50,7 +50,6 @@ def __init__(self, config) -> None: self._prev_state = None self.action = None self.n_actions = len(self.action_vals) - self.action_mapper = {} # Functions self.functions = Functions( @@ -73,13 +72,6 @@ def __init__(self, config) -> None: self.derivative = [] self.derivative_set = {} - # Map actions from int to vector representation - for idx, prod_idx in zip( - range(np.prod(config["action_values"])), - itertools.product(*[np.arange(val) for val in config["action_values"]]), - ): - self.action_mapper[idx] = prod_idx - if "reward_function" in config.keys(): self.get_reward = config["reward_function"] else: @@ -124,12 +116,6 @@ def get_optimal_policy( ) optimal_policy = optimal_policy.astype(int) - if not vector_action: - reverse_action_mapper = {v: k for k, v in self.action_mapper.items()} - optimal_policy = [ - reverse_action_mapper[tuple(vec)] for vec in optimal_policy - ] - return optimal_policy def step(self, action: int): @@ -147,17 +133,11 @@ def step(self, action: int): state, reward, terminated, truncated, info """ self.done = super(GeometricEnv, self).step_() - - # map integer action to vector - action_vec = self.action_mapper[action] - assert self.n_actions == len( - action_vec - ), f"action should be of length {self.n_actions}." - self.action = action_vec + self.action = action coords = self.functions.get_coordinates_at_time_step(self.c_step) self.coord_trajectory.append(coords) - self.action_trajectory.append(np.array(action_vec)) + self.action_trajectory.append(action) self.coord_trajectory_set[self.inst_id] = self.coord_trajectory self.action_trajectory_set[self.inst_id] = self.action_trajectory diff --git a/dacbench/envs/modcma.py b/dacbench/envs/modcma.py index 20a484998..a3cd02573 100644 --- a/dacbench/envs/modcma.py +++ b/dacbench/envs/modcma.py @@ -2,10 +2,10 @@ from modcma import ModularCMAES, Parameters from IOHexperimenter import IOH_function -from dacbench import AbstractEnv +from dacbench import AbstractMADACEnv -class ModCMAEnv(AbstractEnv): +class ModCMAEnv(AbstractMADACEnv): def __init__(self, config): super().__init__(config) diff --git a/dacbench/envs/sigmoid.py b/dacbench/envs/sigmoid.py index 562b6b5f4..875b9b98d 100644 --- a/dacbench/envs/sigmoid.py +++ b/dacbench/envs/sigmoid.py @@ -4,18 +4,16 @@ by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. Original environment authors: André Biedenkapp, H. Furkan Bozkurt """ - -import itertools from typing import List import matplotlib.cm as cm import matplotlib.pyplot as plt import numpy as np -from dacbench import AbstractEnv +from dacbench import AbstractMADACEnv -class SigmoidEnv(AbstractEnv): +class SigmoidEnv(AbstractMADACEnv): """ Environment for tracing sigmoid curves """ @@ -38,14 +36,7 @@ def __init__(self, config) -> None: self.shifts = [self.n_steps / 2 for _ in config["action_values"]] self.slopes = [-1 for _ in config["action_values"]] self.slope_multiplier = config["slope_multiplier"] - self.action_vals = config["action_values"] - self.n_actions = len(self.action_vals) - self.action_mapper = {} - for idx, prod_idx in zip( - range(np.prod(config["action_values"])), - itertools.product(*[np.arange(val) for val in config["action_values"]]), - ): - self.action_mapper[idx] = prod_idx + self.n_actions = len(self.action_space.nvec) self._prev_state = None self.action = None @@ -74,11 +65,6 @@ def step(self, action: int): state, reward, terminated, truncated, info """ self.done = super(SigmoidEnv, self).step_() - action = self.action_mapper[action] - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - self.action = action next_state = self.get_state(self) self._prev_state = next_state @@ -194,11 +180,6 @@ def step(self, action: int): np.array, float, bool, dict state, reward, done, info """ - action = self.action_mapper[action] - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - self.action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along # the x-axis instead of always advancing + 1 @@ -218,6 +199,7 @@ def step(self, action: int): self._prev_state = next_state return next_state, r, self.done, {} + class ContinuousSigmoidEnv(SigmoidEnv): """ Environment for tracing sigmoid curves with a continuous state on the x-axis @@ -248,10 +230,6 @@ def step(self, action: np.ndarray): np.array, float, bool, dict state, reward, done, info """ - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - self.action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along # the x-axis instead of always advancing + 1 @@ -270,56 +248,3 @@ def step(self, action: np.ndarray): next_state = self.get_state(self) self._prev_state = next_state return next_state, r, self.done, {} - - -if __name__ == '__main__': - from dacbench.abstract_benchmark import objdict - config = objdict( - { - "action_space_class": "Box", - "action_space_args": [ - np.array([-np.inf for _ in range(1 + 2 * 3)]), - np.array([np.inf for _ in range(1 + 2 * 3)]), - ], - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [ - np.array([-np.inf for _ in range(1 + 2 * 3)]), - np.array([np.inf for _ in range(1 + 2 * 3)]), - ], - "reward_range": (0, 1), - "cutoff": 10, - "action_values": (2, 2), - "slope_multiplier": 2.0, - "seed": 0, - "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", - "benchmark_info": None, - 'instance_set': {0:[5.847291747472278,6.063505157165379,5.356361033331866,8.473324526654427], - 1:[5.699459023308639,0.17993881762205755,3.4218338308013356,8.486280024502191], - 2:[5.410536230957515,5.700091608324946,-5.3540400976249165,2.76787147719077], - 3:[1.5799464875295817,6.374885201056433,1.0378986341827443,4.219330699379608], - 4:[2.61235568666599,6.478051235772757,7.622760392199338,-3.0898869570275167]}, - } - ) - env = ContinuousSigmoidEnv(config) - done = False - s = env.reset() - env.render(mode='human') - while not done: - a = [np.random.rand(), np.random.rand()] - print(env.c_step, a) - s, r, done, _ = env.step(a) - env.render('human') - - - config['action_space'] = "Discrete" - config["action_space_args"] = [int(np.prod((2, 2)))], - env = ContinuousStateSigmoidEnv(config) - done = False - s = env.reset() - env.render(mode='human') - while not done: - a = np.random.randint(4) - print(env.c_step, a) - s, r, done, _ = env.step(a) - env.render('human') diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index a9592636b..19d9f1a28 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -1,4 +1,4 @@ -from dacbench import AbstractEnv +from dacbench import AbstractMADACEnv import numpy as np from numpy.polynomial import Polynomial from typing import Union, Tuple, Optional, Dict @@ -36,7 +36,7 @@ def sample_coefficients(order: int = 2, low: float = -10, high: float = 10): return coeffs -class ToySGDEnv(AbstractEnv): +class ToySGDEnv(AbstractMADACEnv): """ Optimize toy functions with SGD + Momentum. diff --git a/dacbench/wrappers/multidiscrete_action_wrapper.py b/dacbench/wrappers/multidiscrete_action_wrapper.py new file mode 100644 index 000000000..47f07fa9d --- /dev/null +++ b/dacbench/wrappers/multidiscrete_action_wrapper.py @@ -0,0 +1,34 @@ +import itertools +import numpy as np +from gymnasium import Wrapper +from gymnasium import spaces + + +class MultiDiscreteActionWrapper(Wrapper): + """ + Wrapper to cast MultiDiscrete action spaces to Discrete. + This should improve usability with standard RL libraries. + """ + + def __init__(self, env): + """ + Initialize wrapper + + Parameters + ------- + env : gym.Env + Environment to wrap + """ + super().__init__(env) + self.n_actions = len(self.env.action_space.nvec) + self.action_space = spaces.Discrete(np.prod(self.env.action_space.nvec)) + self.action_mapper = {} + for idx, prod_idx in zip( + range(np.prod(self.env.action_space.nvec)), + itertools.product(*[np.arange(val) for val in self.env.action_space.nvec]), + ): + self.action_mapper[idx] = prod_idx + + def step(self, action): + action = self.action_mapper[action] + return self.env.step(action) \ No newline at end of file diff --git a/tests/benchmarks/test_sigmoid_benchmark.py b/tests/benchmarks/test_sigmoid_benchmark.py index 9bf91eed1..247381b12 100644 --- a/tests/benchmarks/test_sigmoid_benchmark.py +++ b/tests/benchmarks/test_sigmoid_benchmark.py @@ -27,7 +27,7 @@ def test_scenarios(self): state, info = env.reset() self.assertTrue(state is not None) self.assertTrue(info is not None) - state, _, _, _, _ = env.step(0) + state, _, _, _, _ = env.step(env.action_space.sample()) self.assertTrue(state is not None) def test_save_conf(self): @@ -57,10 +57,3 @@ def test_read_instances(self): self.assertTrue(len(env.instance_set[0]) == 4) self.assertTrue(env.instance_set[0] == first_inst) self.assertTrue(len(env.instance_set.keys()) == 300) - - def test_action_value_setting(self): - bench = SigmoidBenchmark() - bench.set_action_values([1, 2, 3]) - self.assertTrue(bench.config.action_values == [1, 2, 3]) - self.assertTrue(bench.config.action_space_args == [6]) - self.assertTrue(len(bench.config.observation_space_args[0]) == 10) diff --git a/tests/test_multi_agent_interface.py b/tests/test_multi_agent_interface.py new file mode 100644 index 000000000..528ff9121 --- /dev/null +++ b/tests/test_multi_agent_interface.py @@ -0,0 +1,66 @@ +import unittest +from dacbench.benchmarks import SigmoidBenchmark, ToySGDBenchmark, ModCMABenchmark +from dacbench.envs import SigmoidEnv, ToySGDEnv + +class TestMultiAgentInterface(unittest.TestCase): + def test_make_env(self): + bench = SigmoidBenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + self.assertTrue(issubclass(type(env), SigmoidEnv)) + + bench = ToySGDBenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + self.assertTrue(issubclass(type(env), ToySGDEnv)) + + def test_empty_reset_step(self): + bench = ModCMABenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + out = env.reset() + self.assertTrue(out is None) + env.register_agent(max(env.possible_agents)) + out = env.step(0) + self.assertTrue(out is None) + + def test_last(self): + bench = ModCMABenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + env.reset() + state, reward, terminated, truncated, info = env.last() + self.assertFalse(state is None) + self.assertTrue(reward is None) + self.assertTrue(info is None) + self.assertFalse(terminated) + self.assertFalse(truncated) + env.register_agent(max(env.possible_agents)) + env.step(0) + _, reward, _, _, info = env.last() + self.assertFalse(reward is None) + self.assertFalse(info is None) + + def test_agent_registration(self): + bench = SigmoidBenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + state, _, _, _, _ = env.last() + env.register_agent(0) + env.register_agent(max(env.possible_agents)) + self.assertTrue(len(env.agents)==2) + self.assertTrue(0 in env.agents) + self.assertTrue(max(env.possible_agents) in env.agents) + self.assertTrue(env.current_agent==0) + env.step(0) + state2, _, _, _, _ = env.last() + self.assertEqual(state, state2) + self.assertTrue(env.current_agent==max(env.possible_agents)) + state3, _, _, _, _ = env.last() + self.assertNotEqual(state, state3) + env.remove_agent(0) + self.assertTrue(len(env.agents)==1) + self.assertFalse(0 in env.agents) + env.register_agent('value_dim_2') + self.assertTrue(len(env.agents)==2) + self.assertTrue(1 in env.agents) \ No newline at end of file From ec91104df9eeda9fc7b7a1e05fe81939c0c939e3 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 13:51:08 +0100 Subject: [PATCH 03/44] Documentation Update --- dacbench/abstract_env.py | 42 ++++++++----------- docs/source/benchmark_docs/modea.rst | 28 ------------- docs/source/benchmarks.rst | 3 +- docs/source/multi_agent_dac.rst | 63 ++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 54 deletions(-) delete mode 100644 docs/source/benchmark_docs/modea.rst create mode 100644 docs/source/multi_agent_dac.rst diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index 5268d4ef1..431263d54 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -428,6 +428,24 @@ def __init__(self, config): # Else playing with less than the full number of agents will be really hard self.action = self.env.action_space.sample() + self.observation_spaces = {} + for a in self.possible_agents: + self.observation_spaces[a] = self.env.observation_space + + space_class = type(self.env.action_space) + if space_class == gym.spaces.Box: + lowers = self.env.action_space.low + uppers = self.env.action_space.high + else: + num_options = [len(n) for n in self.env.action_space.nvec] + self.action_spaces = {} + for a in self.possible_agents: + if space_class == gym.spaces.Box: + subspace = gym.spaces.Box(low=[lowers[a]], high=[uppers[a]]) + else: + subspace = gym.spaces.Discrete(num_options[a]) + self.action_spaces[a] = subspace + def multi_agent_reset(self, seed: int = None): self.observation, self.info = self.env_reset(seed) @@ -466,30 +484,6 @@ def num_agents(self): def agent_selection(self): return self.current_agent - @property - def action_spaces(self): - space_class = type(self.env.action_space) - if space_class == gym.spaces.Box: - lowers = self.env.action_space.low - uppers = self.env.action_space.high - else: - num_options = [len(n) for n in self.env.action_space.nvec] - action_spaces = {} - for a in self.agents: - if space_class == gym.spaces.Box: - subspace = gym.spaces.Box(low=[lowers[a]], high=[uppers[a]]) - else: - subspace = gym.spaces.Discrete(num_options[a]) - action_spaces[a] = subspace - return action_spaces - - @property - def observation_spaces(self): - obs_spaces = {} - for a in self.agents: - obs_spaces[a] = self.env.observation_space - return obs_spaces - @property def infos(self): infos = {} diff --git a/docs/source/benchmark_docs/modea.rst b/docs/source/benchmark_docs/modea.rst deleted file mode 100644 index 46d933ee1..000000000 --- a/docs/source/benchmark_docs/modea.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _modea: - -=================== -The ModEA Benchmark -=================== - -| **Task:** control the algorithm components of CMA-ES on BBOB functions -| **Cost:** negative objective value -| **Number of hyperparameters to control:** 11 categorical -| **State Information:** generation size, step size, remaining budget, function ID, instance ID -| **Noise Level:** fairly large, depends on target function -| **Instance space:** the BBOB functions with ids, starting point and starting sigma as well as population size - -This benchmark uses the ModEA package to enable dynamic control of several algorithm components of CMA-ES. -The components of the algorithm that can be selected or changed are: sequential execution, active update, elitism, orthogonal sampling, convergence threshold enabled, -step size adaption scheme, mirrored sampling, the base sampler, weight option, local restarts and bound correction. -The goal in the optimization is to find the global function minimum before the cutoff, so the cost is defined as the current negativ objective value. - -Just like the ModCMA benchmark (which provides a very similar problem with a different backend), this benchmark is challenging due to the large configuration space. -It is an advanced benchmark that should likely not be the starting point for the development of DAC methods. - -.. automodule:: dacbench.benchmarks.modea_benchmark - :members: - :show-inheritance: - -.. automodule:: dacbench.envs.modea - :members: - :show-inheritance: \ No newline at end of file diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index bd3722e35..a25867fda 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -34,11 +34,10 @@ and more costly to run and thus present a real challenge for DAC algorithms: * :doc:`FastDownward benchmark `: Heuristic selection for the FastDownward Planner on competition tasks. * :doc:`CMA-ES `: Step-size adpation for CMA-ES. -* :doc:`ModEA `: Selection of Algorithm Components for EAs. * :doc:`ModCMA `: Step-size & algorithm component control for EAs backed by IOHProfiler. * :doc:`SGD-DL `: Learning rate adaption for neural networks. -Our benchmarks are based on OpenAI's gym interface for Reinforcement Learning. +Our benchmarks are based on the `gymnasium interface `_ for Reinforcement Learning. That means to run a benchmark, you need to create an environment of that benchmark to then interact with it. We include examples of this interaction between environment and DAC methods in our diff --git a/docs/source/multi_agent_dac.rst b/docs/source/multi_agent_dac.rst new file mode 100644 index 000000000..dddfb7384 --- /dev/null +++ b/docs/source/multi_agent_dac.rst @@ -0,0 +1,63 @@ +.. _multi_agent_dac: + +================ +Multi-Agent DAC +================ + +.. role:: python(code) + :language: python + +As `Xue et al. `_ have shown, multiple controllers collaborating to configure a single hyperparameter of the same algorithm each is a promising approach for solving DAC. +To support further innovation in that direction, all of our environments with multiple configurable hyperparameters can be used as a Multi-Agent version. +This allows users to specify hyperparameters one by one instead of in a single step and thus is especially useful for those interfacing existing libraries. + +In order to create a Multi-Agent DACBench environment, select either of the following benchmarks: + +- :doc:`Sigmoid ` (Artificial Benchmark): + Sigmoid function approximation in multiple dimensions. +- :doc:`ToySGD ` (Artificial Benchmark): + Controlling the learning rate in gradient descent. +- :doc:`Geometric ` (Artificial Benchmark): + Approximating several functions at once. +- :doc:`ModCMA `: Step-size & algorithm component control for EAs backed by IOHProfiler. + +To instantiate a benchmark environment, first set the 'multi_agent' key in the configuration to True and then create the environment as usual: + +.. code-block:: python + + from dacbench.benchmarks import SigmoidBenchmark + bench = SigmoidBenchmark() + bench.config["multi_agent"] = True + env = bench.get_environment() + +Running the benchmark is similar, but not quite the same as running a normal DACBench environment. First, you need to register the agents. +Note that for this application, it makes sense to use an agent per hyperparameter even though it's technically possible to register less agents. +The remaining hyperparameters will be randomly, sampled, however, which could lead to adversarial effects. +To register an agent, use the ID of the hyperparameter you want to control. If using ConfigSpace, you can also use the hyperparameter's name: + +.. code-block:: python + + from dacbench.agents import StaticAgent + + Agent_zero = StaticAgent(env, env.action_spaces[0].sample()) + Agent_one = StaticAgent(env, env.action_spaces[1].sample()) + agents = [Agent_zero, Agent_one] + + env.register_agent(0) + env.register_agent(1) + +The episode loop is slightly different as well: + +.. code-block:: python + + env.reset() + for agent in agents: + observation, reward, terminated, truncated, info = env.last() + action = agent.act(state, reward) + env.step(action) + +For more information on this interface, consult the `PettingZoo Documentation `_ on which our interface is based. + +.. automodule:: dacbench.abstract_env + :members: + :show-inheritance: \ No newline at end of file From 0d5ba40d96281cc3de09b626ca0c265966b38512 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:34:30 +0100 Subject: [PATCH 04/44] example update --- Getting started.ipynb | 467 ++++ examples/benchmarks/baselines_ppo_sigmoid.py | 2 +- examples/benchmarks/chainerrl_cma.py | 10 +- examples/benchmarks/theory/README.md | 146 -- examples/benchmarks/theory/examples.py | 301 --- .../results/n100_evenly_spread/k10/dqn.txt | 2000 ----------------- .../n100_evenly_spread/k10/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k10/random.txt | 0 .../k10/trained_ddqn/best.pt | Bin 14871 -> 0 bytes .../k10/trained_ddqn/best_seed_1.pt | Bin 14871 -> 0 bytes .../k10/trained_ddqn/best_seed_2.pt | Bin 14871 -> 0 bytes .../results/n100_evenly_spread/k15/dqn.txt | 1 - .../n100_evenly_spread/k15/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k15/random.txt | 2000 ----------------- .../k15/trained_ddqn/best.pt | Bin 15831 -> 0 bytes .../k15/trained_ddqn/best_seed_1.pt | Bin 15831 -> 0 bytes .../k15/trained_ddqn/best_seed_2.pt | Bin 15831 -> 0 bytes .../results/n100_evenly_spread/k20/dqn.txt | 2000 ----------------- .../n100_evenly_spread/k20/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k20/random.txt | 0 .../k20/trained_ddqn/best.pt | Bin 16919 -> 0 bytes .../k20/trained_ddqn/best_seed_1.pt | Bin 16919 -> 0 bytes .../k20/trained_ddqn/best_seed_2.pt | Bin 16919 -> 0 bytes .../results/n100_evenly_spread/k3/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k3/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k3/random.txt | 2000 ----------------- .../k3/trained_ddqn/best.pt | Bin 13463 -> 0 bytes .../results/n100_evenly_spread/k4/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k4/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k4/random.txt | 2000 ----------------- .../k4/trained_ddqn/best.pt | Bin 13655 -> 0 bytes .../results/n100_evenly_spread/k5/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k5/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k5/random.txt | 2000 ----------------- .../k5/trained_ddqn/best.pt | Bin 13847 -> 0 bytes .../results/n100_evenly_spread/k6/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k6/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k6/random.txt | 2000 ----------------- .../k6/trained_ddqn/best.pt | Bin 14039 -> 0 bytes .../results/n100_evenly_spread/k7/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k7/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k7/random.txt | 2000 ----------------- .../k7/trained_ddqn/best.pt | Bin 14231 -> 0 bytes .../k7/trained_ddqn/best_seed_1.pt | Bin 14231 -> 0 bytes .../k7/trained_ddqn/best_seed_2.pt | Bin 14231 -> 0 bytes .../results/n100_evenly_spread/k8/dqn.txt | 2000 ----------------- .../results/n100_evenly_spread/k8/optimal.txt | 2000 ----------------- .../results/n100_evenly_spread/k8/random.txt | 2000 ----------------- .../k8/trained_ddqn/best.pt | Bin 14423 -> 0 bytes .../k8/trained_ddqn/best_seed_1.pt | Bin 14423 -> 0 bytes .../k8/trained_ddqn/best_seed_2.pt | Bin 14423 -> 0 bytes .../results/n150_evenly_spread/k3/optimal.txt | 2000 ----------------- .../k3/trained_ddqn/best_seed_0.pt | Bin 13463 -> 0 bytes .../k3/trained_ddqn/best_seed_1.pt | Bin 13463 -> 0 bytes .../k3/trained_ddqn/best_seed_2.pt | Bin 13463 -> 0 bytes .../results/n150_evenly_spread/k4/optimal.txt | 2000 ----------------- .../k4/trained_ddqn/best_seed_0.pt | Bin 13655 -> 0 bytes .../k4/trained_ddqn/best_seed_1.pt | Bin 13655 -> 0 bytes .../k4/trained_ddqn/best_seed_2.pt | Bin 13655 -> 0 bytes .../results/n150_evenly_spread/k5/optimal.txt | 2000 ----------------- .../k5/trained_ddqn/best_seed_0.pt | Bin 13847 -> 0 bytes .../k5/trained_ddqn/best_seed_1.pt | Bin 13847 -> 0 bytes .../k5/trained_ddqn/best_seed_2.pt | Bin 13847 -> 0 bytes .../results/n200_evenly_spread/k3/optimal.txt | 2000 ----------------- .../k3/trained_ddqn/best_seed_0.pt | Bin 13463 -> 0 bytes .../k3/trained_ddqn/best_seed_1.pt | Bin 13463 -> 0 bytes .../k3/trained_ddqn/best_seed_2.pt | Bin 13463 -> 0 bytes .../results/n200_evenly_spread/k4/optimal.txt | 2000 ----------------- .../k4/trained_ddqn/best_seed_0.pt | Bin 13655 -> 0 bytes .../k4/trained_ddqn/best_seed_1.pt | Bin 13655 -> 0 bytes .../k4/trained_ddqn/best_seed_2.pt | Bin 13655 -> 0 bytes .../results/n200_evenly_spread/k5/optimal.txt | 2000 ----------------- .../k5/trained_ddqn/best_seed_0.pt | Bin 13847 -> 0 bytes .../k5/trained_ddqn/best_seed_1.pt | Bin 13847 -> 0 bytes .../k5/trained_ddqn/best_seed_2.pt | Bin 13847 -> 0 bytes .../results/n50_evenly_spread/k10/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k10/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k10/random.txt | 2000 ----------------- .../k10/trained_ddqn/best.pt | Bin 14871 -> 0 bytes .../k10/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k15/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k15/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k15/random.txt | 2000 ----------------- .../k15/trained_ddqn/best.pt | Bin 15831 -> 0 bytes .../k15/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k20/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k20/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k20/random.txt | 2000 ----------------- .../k20/trained_ddqn/best.pt | Bin 16919 -> 0 bytes .../k20/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k3/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k3/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k3/random.txt | 2000 ----------------- .../n50_evenly_spread/k3/trained_ddqn/best.pt | Bin 13463 -> 0 bytes .../k3/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k4/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k4/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k4/random.txt | 2000 ----------------- .../n50_evenly_spread/k4/trained_ddqn/best.pt | Bin 13655 -> 0 bytes .../k4/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k5/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k5/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k5/random.txt | 2000 ----------------- .../n50_evenly_spread/k5/trained_ddqn/best.pt | Bin 13847 -> 0 bytes .../k5/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k6/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k6/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k6/random.txt | 2000 ----------------- .../n50_evenly_spread/k6/trained_ddqn/best.pt | Bin 14039 -> 0 bytes .../k6/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k7/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k7/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k7/random.txt | 2000 ----------------- .../n50_evenly_spread/k7/trained_ddqn/best.pt | Bin 14231 -> 0 bytes .../k7/trained_ddqn/config.yml | 27 - .../results/n50_evenly_spread/k8/dqn.txt | 2000 ----------------- .../results/n50_evenly_spread/k8/optimal.txt | 2000 ----------------- .../results/n50_evenly_spread/k8/random.txt | 2000 ----------------- .../n50_evenly_spread/k8/trained_ddqn/best.pt | Bin 14423 -> 0 bytes .../k8/trained_ddqn/config.yml | 27 - .../results/n50_initial_segment/k3/dqn.txt | 2000 ----------------- .../n50_initial_segment/k3/optimal.txt | 2000 ----------------- .../results/n50_initial_segment/k3/random.txt | 2000 ----------------- .../k3/trained_ddqn/best.pt | Bin 13669 -> 0 bytes .../results/n50_initial_segment/k4/dqn.txt | 2000 ----------------- .../n50_initial_segment/k4/optimal.txt | 2000 ----------------- .../results/n50_initial_segment/k4/random.txt | 2000 ----------------- .../k4/trained_ddqn/best.pt | Bin 13655 -> 0 bytes .../results/n50_initial_segment/k5/dqn.txt | 2000 ----------------- .../n50_initial_segment/k5/optimal.txt | 2000 ----------------- .../results/n50_initial_segment/k5/random.txt | 2000 ----------------- .../k5/trained_ddqn/best.pt | Bin 13847 -> 0 bytes .../results/n50_power_of_2/k3/dqn.txt | 2000 ----------------- .../results/n50_power_of_2/k3/optimal.txt | 2000 ----------------- .../results/n50_power_of_2/k3/random.txt | 2000 ----------------- .../n50_power_of_2/k3/trained_ddqn/best.pt | Bin 13669 -> 0 bytes .../results/n50_power_of_2/k4/dqn.txt | 2000 ----------------- .../results/n50_power_of_2/k4/optimal.txt | 2000 ----------------- .../results/n50_power_of_2/k4/random.txt | 2000 ----------------- .../n50_power_of_2/k4/trained_ddqn/best.pt | Bin 13655 -> 0 bytes .../results/n50_power_of_2/k5/dqn.txt | 2000 ----------------- .../results/n50_power_of_2/k5/optimal.txt | 2000 ----------------- .../results/n50_power_of_2/k5/random.txt | 2000 ----------------- .../n50_power_of_2/k5/trained_ddqn/best.pt | Bin 13847 -> 0 bytes .../theory/experiments/test_conf.yml | 5 - .../experiments/test_conf_non_discrete.yml | 7 - .../theory/experiments/train_conf.yml | 29 - .../calculatePolicy.d | 13 - .../calculate_optimal_policy/compile.sh | 5 - .../data_management.d | 526 ----- .../scripts/calculate_optimal_policy/eas.d | 316 --- .../scripts/calculate_optimal_policy/run.py | 66 - .../theory/scripts/ddqn_local/ddqn.py | 604 ----- .../theory/scripts/ddqn_local/ddqn_utils.py | 101 - .../theory/scripts/optimal_policies.txt | 63 - .../benchmarks/theory/scripts/rls_policies.py | 132 -- .../theory/scripts/run_experiment.py | 92 - .../benchmarks/theory/scripts/run_policy.py | 97 - .../theory/scripts/runtime_calculation.py | 77 - examples/benchmarks/theory/scripts/utils.py | 44 - examples/example_utils.py | 28 +- .../data/CMAESBenchmark/benchmark.json | 1 - ...ing_modea.py => action_tracking_modcma.py} | 4 +- setup.cfg | 32 +- tests/agents/test_generic_agent.py | 13 - tests/benchmarks/test_geometric_benchmark.py | 204 -- tests/benchmarks/test_theory_benchmark.py | 45 - tests/envs/data/sgd_config.hash | 1 - tests/envs/data/sgd_dynamic_test.npy | Bin 4928 -> 0 bytes tests/envs/data/sgd_static_test.npy | Bin 4928 -> 0 bytes 170 files changed, 505 insertions(+), 153170 deletions(-) create mode 100644 Getting started.ipynb delete mode 100644 examples/benchmarks/theory/README.md delete mode 100644 examples/benchmarks/theory/examples.py delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k6/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k6/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k6/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k6/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_0.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_1.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_2.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/config.yml delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k4/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k4/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k4/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/dqn.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/optimal.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/random.txt delete mode 100644 examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/trained_ddqn/best.pt delete mode 100644 examples/benchmarks/theory/experiments/test_conf.yml delete mode 100644 examples/benchmarks/theory/experiments/test_conf_non_discrete.yml delete mode 100755 examples/benchmarks/theory/experiments/train_conf.yml delete mode 100644 examples/benchmarks/theory/scripts/calculate_optimal_policy/calculatePolicy.d delete mode 100755 examples/benchmarks/theory/scripts/calculate_optimal_policy/compile.sh delete mode 100644 examples/benchmarks/theory/scripts/calculate_optimal_policy/data_management.d delete mode 100644 examples/benchmarks/theory/scripts/calculate_optimal_policy/eas.d delete mode 100644 examples/benchmarks/theory/scripts/calculate_optimal_policy/run.py delete mode 100755 examples/benchmarks/theory/scripts/ddqn_local/ddqn.py delete mode 100755 examples/benchmarks/theory/scripts/ddqn_local/ddqn_utils.py delete mode 100644 examples/benchmarks/theory/scripts/optimal_policies.txt delete mode 100644 examples/benchmarks/theory/scripts/rls_policies.py delete mode 100644 examples/benchmarks/theory/scripts/run_experiment.py delete mode 100644 examples/benchmarks/theory/scripts/run_policy.py delete mode 100644 examples/benchmarks/theory/scripts/runtime_calculation.py delete mode 100644 examples/benchmarks/theory/scripts/utils.py delete mode 100644 examples/plotting/data/CMAESBenchmark/benchmark.json rename examples/wrappers/{action_tracking_modea.py => action_tracking_modcma.py} (90%) delete mode 100644 tests/agents/test_generic_agent.py delete mode 100644 tests/benchmarks/test_geometric_benchmark.py delete mode 100644 tests/benchmarks/test_theory_benchmark.py delete mode 100644 tests/envs/data/sgd_config.hash delete mode 100644 tests/envs/data/sgd_dynamic_test.npy delete mode 100644 tests/envs/data/sgd_static_test.npy diff --git a/Getting started.ipynb b/Getting started.ipynb new file mode 100644 index 000000000..ef1d23671 --- /dev/null +++ b/Getting started.ipynb @@ -0,0 +1,467 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "import numpy as np\n", + "from chainerrl import wrappers\n", + "from pathlib import Path\n", + "import pandas as pd\n", + "\n", + "import seaborn\n", + "seaborn.set_context(\"talk\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from dacbench.benchmarks import LubyBenchmark, SigmoidBenchmark\n", + "from dacbench.wrappers import PerformanceTrackingWrapper, RewardNoiseWrapper\n", + "from dacbench.logger import Logger, load_logs, log2dataframe\n", + "from dacbench.plotting import plot_performance, plot_performance_per_instance\n", + "from examples.example_utils import make_chainer_dqn, train_chainer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# First steps: running an episode\n", + "\n", + "### Creating a benchmark object\n", + "Benchmarks are environments created by a benchmark object.\n", + "First, we take a look at that object and the configuration it holds:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "action_space_class: Discrete\n", + "action_space_args: [6]\n", + "observation_space_class: Box\n", + "observation_space_type: \n", + "observation_space_args: [array([-1, -1, -1, -1, -1, -1]), array([128., 128., 128., 128., 128., 128.])]\n", + "reward_range: (-1, 0)\n", + "cutoff: 64\n", + "hist_length: 5\n", + "min_steps: 8\n", + "seed: 0\n", + "instance_set_path: ../instance_sets/luby/luby_default.csv\n", + "benchmark_info: {'identifier': 'Luby', 'name': 'Luby Sequence Approximation', 'reward': 'Boolean sucess indication', 'state_description': ['Action t-2', 'Step t-2', 'Action t-1', 'Step t-1', 'Action t (current)Step t (current)']}\n" + ] + } + ], + "source": [ + "bench = LubyBenchmark()\n", + "for k in bench.config.keys():\n", + " print(f\"{k}: {bench.config[k]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Getting the benchmark environment\n", + "Now we can either get the default benchmark setting like this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = bench.get_benchmark(seed=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or first modify the the benchmark, e.g. by setting a different seed.\n", + "In that case, we use the get_environment() method to explicitly override the defaults." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bench.config.seed = 9\n", + "env = bench.get_environment()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To then save our modification as a config file to share with others, run:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bench.save_config(\"test_config.json\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also load an existing benchmark configuration (e.g. from our challenge benchmarks):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bench = LubyBenchmark(\"dacbench/challenge_benchmarks/reward_quality_challenge/level_1/luby.json\")\n", + "env = bench.get_environment()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Running the benchmark\n", + "To execute a run, first reset the environment. It will return an initial state as well as a dictonary that may or may not contain some meta-information:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-1 -1 -1 -1 -1 -1]\n" + ] + } + ], + "source": [ + "state, info = env.reset()\n", + "print(state)\n", + "print(info)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we can run steps until the algorithm run is done:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Episode 1/1...........................................Reward: -6\n" + ] + } + ], + "source": [ + "terminated, truncated = False, False\n", + "cum_reward = 0\n", + "while not (terminated or truncated):\n", + " state, reward, terminated, truncated, info = env.step(1)\n", + " cum_reward += reward\n", + "print(f\"Episode 1/1...........................................Reward: {cum_reward}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A more complex example: multiple seeds & logging\n", + "\n", + "### Creating env and logger object\n", + "Using a Logger object, we can track the performance on the environment over time.\n", + "To make the benchmark more difficult, we use a wrapper to add noise to the reward signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Automatically setting up env and logger\n", + "def setup_env(seed):\n", + " # Get benchmark env\n", + " bench = SigmoidBenchmark()\n", + " env = bench.get_benchmark(seed=seed)\n", + " \n", + " # Make logger to write results to file\n", + " logger = Logger(experiment_name=f\"Sigmoid_s{seed}\", output_path=Path(\"example\"))\n", + " perf_logger = logger.add_module(PerformanceTrackingWrapper)\n", + " \n", + " # Wrap the environment to add noise and track the reward\n", + " env = RewardNoiseWrapper(env, noise_dist=\"normal\", dist_args=[0, 0.3])\n", + " env = PerformanceTrackingWrapper(env, logger=perf_logger)\n", + " logger.set_env(env)\n", + " logger.set_additional_info(seed=seed)\n", + " \n", + " return env, logger" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we run the environment on 5 different seeds, logging the results of each one.\n", + "In this example, we use a simple RL agent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Episode 0/10...........................................Reward: 1.3011316427214563\n", + "Episode 1/10...........................................Reward: 3.3744850921123946\n", + "Episode 2/10...........................................Reward: 2.3631684324627718\n", + "Episode 3/10...........................................Reward: 4.317746116997824\n", + "Episode 4/10...........................................Reward: 1.6797188664568847\n", + "Episode 5/10...........................................Reward: 2.7827871422251107\n", + "Episode 6/10...........................................Reward: 2.5116556799296275\n", + "Episode 7/10...........................................Reward: 3.5007718971969197\n", + "Episode 8/10...........................................Reward: 4.106872497507007\n", + "Episode 9/10...........................................Reward: 4.793092410210768\n", + "Episode 0/10...........................................Reward: 3.031774376928836\n", + "Episode 1/10...........................................Reward: 3.531218880633655\n", + "Episode 2/10...........................................Reward: 4.167165087384353\n", + "Episode 3/10...........................................Reward: 5.233201705455833\n", + "Episode 4/10...........................................Reward: 2.188207601128754\n", + "Episode 5/10...........................................Reward: 1.8568553859700894\n", + "Episode 6/10...........................................Reward: 3.3535213565300914\n", + "Episode 7/10...........................................Reward: 3.9143173726764315\n", + "Episode 8/10...........................................Reward: 5.9210770071618875\n", + "Episode 9/10...........................................Reward: 1.7347809873492697\n", + "Episode 0/10...........................................Reward: 1.2267208210243266\n", + "Episode 1/10...........................................Reward: 4.272024200240991\n", + "Episode 2/10...........................................Reward: 4.018067293012267\n", + "Episode 3/10...........................................Reward: 6.092753761710156\n", + "Episode 4/10...........................................Reward: 2.8559608448320155\n", + "Episode 5/10...........................................Reward: 4.566827138251945\n", + "Episode 6/10...........................................Reward: 1.6729707197368913\n", + "Episode 7/10...........................................Reward: 3.294847132837542\n", + "Episode 8/10...........................................Reward: 4.483649588788299\n", + "Episode 9/10...........................................Reward: 2.38138037478034\n", + "Episode 0/10...........................................Reward: 1.6510698360234835\n", + "Episode 1/10...........................................Reward: 2.128216159693229\n", + "Episode 2/10...........................................Reward: 5.916633060036471\n", + "Episode 3/10...........................................Reward: 2.5946635073954556\n", + "Episode 4/10...........................................Reward: 1.9370437373865061\n", + "Episode 5/10...........................................Reward: 2.8583409558781687\n", + "Episode 6/10...........................................Reward: 2.709995561782036\n", + "Episode 7/10...........................................Reward: 4.22106134601858\n", + "Episode 8/10...........................................Reward: 4.00098190503663\n", + "Episode 9/10...........................................Reward: 3.8897015883042507\n", + "Episode 0/10...........................................Reward: 3.448686970958871\n", + "Episode 1/10...........................................Reward: 3.8641567543854487\n", + "Episode 2/10...........................................Reward: 4.055595574984241\n", + "Episode 3/10...........................................Reward: 1.1747168367918102\n", + "Episode 4/10...........................................Reward: 1.9570821025256233\n", + "Episode 5/10...........................................Reward: 1.4562154261767166\n", + "Episode 6/10...........................................Reward: 1.8993780855495175\n", + "Episode 7/10...........................................Reward: 2.3341211959967425\n", + "Episode 8/10...........................................Reward: 2.85351960011256\n", + "Episode 9/10...........................................Reward: 4.658324104566514\n", + "Episode 0/10...........................................Reward: 2.257800049332543\n", + "Episode 1/10...........................................Reward: 3.3820616461689674\n", + "Episode 2/10...........................................Reward: 0.8288001998682013\n", + "Episode 3/10...........................................Reward: 2.6205201908469493\n", + "Episode 4/10...........................................Reward: 3.1124064373231706\n", + "Episode 5/10...........................................Reward: 2.4906180892787058\n", + "Episode 6/10...........................................Reward: 2.120601125600685\n", + "Episode 7/10...........................................Reward: 2.5516422919869104\n", + "Episode 8/10...........................................Reward: 1.0484662491724799\n", + "Episode 9/10...........................................Reward: 6.036117355497821\n" + ] + } + ], + "source": [ + "for seed in [0, 1, 2, 3, 4]:\n", + " env, logger = setup_env(seed)\n", + " \n", + " # This could be any optimization or learning method\n", + " rl_agent = make_chainer_dqn(env.observation_space.low.size, env.action_space)\n", + " env = wrappers.CastObservationToFloat32(env)\n", + " \n", + " train_chainer(rl_agent, env, num_episodes=10, logger=logger)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After we're done training, we can load the results into a pandas DataFrame for further inspection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results = []\n", + "for seed in [0, 1, 2, 3, 4]:\n", + " logs = load_logs(f\"example/Sigmoid_s{seed}/PerformanceTrackingWrapper.jsonl\")\n", + " results.append(log2dataframe(logs, wide=True))\n", + "results = pd.concat(results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "DACBench includes plotting functionality for commonly used plots like performance over time:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot performance over time\n", + "plot = plot_performance(results, title=\"Reward on Sigmoid Benchmark (with 95% CI)\", aspect=2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This plot can also be split into the different seeded runs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot = plot_performance(results, title=\"Reward per seed on Sigmoid Benchmark (with 95% CI)\", hue=\"seed\", aspect=2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And as we're training on an instance set, we can also see how the mean performance per instance looks:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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BQF4/PiZIUIjIiIiHeTyQq2yJ0+eQSqVl0E09CaVp2tvb1+5yG1lNub2wYMHiIqKwp07dzTKnz9/DgCoVq1aWYRFRERERG+xMktuJRIJvvnmG2zZskWj/MCBAzA1NUXLli3LKDIiIiIieluV2bCE6tWrIyQkBJs3b4aNjQ1atWqF+Ph4rFy5EiEhIWjYsGFZhUZEREREb6kyHXM7ZcoU1KxZEzt27MDq1atRs2ZNjB8/Hp988klZhkVEREREb6kyTW7NzMwwcuRIjBw5sizDICIiIhLtbbiRwbusTG/iQERERPQ2eVtuZPAuY3JLREREJJJCIde6kYFCwWXQyhMmt0RERERUYTC5JSIiIqIKg8ktEREREVUYZbpaAhER0duIs+WJyi/23BIREemBs+WJyjcmt0RERHrgbHmi8o3JLRERERFVGExuiYiIiKjCYHJLRERERBUGk1siIiIiqjCY3BIRERFRhcHkloiIiIgqDCa3RERERFRhMLklIiIiogqDyS0RERERVRhMbomIiIiowmByS0REREQVBpNbIiIiIqowmNwSERERUYXB5JaIiIiIKgwmt0RERERUYZQquVUqlcjKykJBQYGh4yEiIiIiKjW9ktt///0X48aNQ8uWLdGpUyfEx8fj9OnTCA4ORlxcnLFiJCIiIiISRXRye/v2bQQHByM2NhYdO3aEIAgAAFNTU/zzzz8YMWIEzp8/b7RAiYiIiIhKIjq5XbRoESwsLHDgwAF8++236uS2TZs2OHDgAGrUqIFly5YZLVAiIiIiopKITm5jYmIwaNAg2NnZQSKRaGyrWbMmBg8ejKSkJIMHSEREREQklujktqCgAFWqVClyu5mZGfLz8w0SFBERERFRaYhObps2bYro6Gid2+RyOfbs2QNnZ2eDBUZEREREpC/Rye1nn32GU6dOITw8HDExMQCA1NRUHD58GB9//DGSk5MxfPhwowVKRERERFQSqdgd33//fXz//feYPXs29u/fDwD4+uuvIQgCKlWqhClTpiAgIMBogRIRERERlUR0cgsAffv2RdeuXXHq1CmkpKRAqVSibt26aN++PapVq2asGImIiIiIRNHrJg45OTnYu3cvfHx88Mknn+DTTz/Fs2fPsH//fjx//txYMRIRERERiSI6uU1NTUWfPn0wc+ZM3Lp1S11+7tw5zJo1C8HBwXj48KFR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X2P48OGYNGkSunTpAjs7O50TR1q3bm3QAImISH9SqQmUhfnISLltlPp13YI1/Z9rRrlVas0GjpCaVTJ4vURUMYn+FEpLS8PTp0+xf/9+HDhwQGu7IAiQSCQat+QlIqKyk5FyG1u+n26UupWCoFW29YeZMDHCahlD/jsDtZ2cDV4vEVVMopPbmTNn4smTJwgLC4Ojo6NR/jonIiIiInodojPU69evY+zYsRg5cqQx4yEiIiIiKjXRsw1q1arFtW2JiIiIqFwT3XP7ySefICIiAr6+vmjcuLExYyIiem1cLYCI6N0kOrm9cuUKJBIJevbsifr166NGjRowNdW81SBvv0tE5YVUagJBISAr9bFR6te1WkDWncdGmY9Qo25VoybqREQViehP4SNHjsDU1BS1atVCYWEh7t27Z8y4iIheW1bqY+xacdoodSuVCq2y31bFwMTEVMfer6fP6Hawb2Br8HqJiCoi0cntjh07UK1aNWPGQkRERET0WkT/ztWnTx8sX77cmLEQEREREb0W0cnto0ePUKNGDWPGQkRERET0WkQntz169EBUVBSysrKMGQ8RERERUamJHnNrYmKCGzduwNfXFw0aNICdnZ3WurdcLYGIiIiIypLo5PbkyZPqCWX5+flIS0szWlBERERERKUhOrmNjo42ZhxERERERK9N79XGFQoFkpKSkJqaCnNzc9SuXRsuLi6lalwQBGzcuBHbtm3DvXv34OjoiJEjRyIoKKhU9RERERHRu02v5PbIkSOYMWMGMjIyIAgCgBfjbB0cHDB9+nT4+/vr1fiqVavw448/Yty4cfD09MTx48cRHh4OU1NTBAYG6lUXEREREZHo5DYuLg7jxo2DnZ0dJkyYACcnJwiCgH/++Qdbt27F+PHjsWnTJrRo0UJUfYWFhVi/fj0GDRqE0aNHAwDatWuHpKQkbNmyhcktEREREelNdHIbERGBunXr4tdff0XlypU1tg0ePBj9+vXDihUrsGbNGlH1mZqaYvPmzbC11bylpJmZGfLy8sSGRURERESkJnqd2wsXLiA4OFgrsQUAGxsb9O/fH4mJieIbNjGBs7MzatasCUEQkJWVhdWrV+PUqVMYOHCg6HqIiIiIiFT0nlBWFIlEgsLCwlI9988//8T48eMBAH5+fujZs2cpYwCqVrUs1XOJSD+FhdofH1WqWMLMzKwMotEm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vn37oFQqu33YRq7Onz8PAANmvnRHXl4eUlJSoNFokJ2dLet36f4/vV6PhISEbsd5PnnyJAAMiFVLAIaVyi7nzp0DAFhbW4ueSUxmZmZYtWoV8vPzDWNtbW3Q6XTw9vZ+bFZuuS2hh6KiopCYmAgLCwsEBgbi8OHD2L9/v+wP4t912Ju7Pf3001CpVHB1dZUgkbgUCgXi4uKwfPlyxMXFYfbs2SgpKcH69esRHh4u+7eoLS0todVqsWXLFpibm8PLywvFxcX429/+Bq1WazhiiNxduHABgwcPlv0TGv2koaEB77//PqytraHValFaWmp0+ujRo2X9+29paYnXXnsNWVlZeOKJJ+Dq6ori4mJs2LABc+bM+Z/PDXLi4uKCoKAgvP/++7h58ybGjx+PkpISZGZmIiAgQPaHAlQqlXj11VfxySefwMrKCjY2NsjOzsbVq1eRmpoqdTwDltsemj17Njo6OpCTk4O8vDzY2toiNTV1QPyVloFuxowZUKlUyMzMxJIlSzB06FBERUVhyZIlUkcTRXx8PEaMGIH8/HxkZWVhxIgRiImJGRCfGO5SX18/oI6QQMDx48fx448/orq6Glqtttvpa9askf0hoRITE/HMM89gx44dyMjIwMiRIxETE4OIiAipo4kiLS0N69atw6ZNm9DQ0ABra2ssWrSo27F/5WrZsmUwMTHBxx9/jObmZri6umLTpk1wc3OTOpqBQvi5j/wTEREREfUT3HNLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRNQDO3fuhKOjI3bu3Nkn19/c3IzGxsY+uW4iIjliuSUiekyVlJRAo9Hg4sWLUkchIuo3WG6JiB5TFy5cQF1dndQxiIj6FZZbIiIiIpINllsiol40depUJCUlYffu3Zg5cyZcXV2hVquxdetWo/PduHEDCQkJCAwMxPPPP4+goCB8+OGHaG9vBwBkZGQgMTERALBgwQJMnTrVcNl//etfWLx4MSZNmgQXFxf4+/sjKSkJP/zwg+E8CQkJmD59Ov773/8iPDwc7u7ueOGFF/Dee++hra3NKEttbS3eeust+Pn5wdPTEy+//DKKioqMznPt2jW8+eab+NWvfgVXV1eEhoZiz549vXrfERH1BlOpAxARyc3x48dx4MABhIeHY9iwYdDpdFi1ahVsbGwwefJkAEBsbCxKS0uxYMECWFlZ4ezZs8jKykJTUxNWr16NadOm4fvvv4dOp8PSpUvh6uoKADhx4gR+//vfY8KECYiJiYFCocDJkyeh0+lw48YNpKenG3I0NjYiIiICGo0GISEh+OKLL7BlyxaoVCq8+eabAICmpiaEhYWhqakJWq0Wtra2KCwsRHR0NNatW4egoCDU1tZizpw5EAQB8+fPh4WFBQ4fPowVK1agrq4OixcvFv9OJiK6F4GIiB5Zfn6+4ODgIOTn5wuCIAhTpkwRHB0dhbKyMsN56urqBEdHR2H58uWCIAhCfX294ODgIGRnZxtdV0JCgrBw4cJu13369GnDWEREhDBlyhShvb3d6LJhYWGCp6en4fv4+HjBwcFB2Lx5s9H5NBqN4OfnZ/h+zZo1goODg3DmzBnDWFtbmxAUFCS8/PLLhuvy8fERamtrDefR6/XC8uXLheeff16or69/sDuLiEgEXLklIupl9vb2cHJyMnw/fPhwDBs2DPX19QCAIUOG4Mknn8Snn34KGxsb+Pv748knn0RycvLPXveGDRvwww8/QKVSGcauX78Oc3NztLa2dju/RqMx+t7JyQn79+83fH/06FG4uLhg4sSJhrFBgwYhKysLgwYNgl6vR1FRESZNmgRTU1Ojw5Kp1WoUFhbi5MmTCAkJeYB7hoio77HcEhH1MktLy25jKpUKer3e8O9Vq1Zh5cqViImJgUqlgo+PD9RqNUJDQzFo0KB7XrdSqURVVRXS09Nx6dIlVFZWora29oGz3J0DAKqrq43283axt7cHADQ0NODmzZsoKirqtg+3S01NzT1vn4hIbCy3RES9zMTk5z+rO2vWLPj7+6OoqAjHjh3DqVOncOLECXz66afIy8szWpm928aNG7FmzRrY29vDy8sLarUa7u7u2LJlC/bu3fvQWW7fvg2FQnHf0wEgODgYr7766v88j62t7X1vg4hITCy3REQia2lpQVlZGZ577jm88soreOWVV9DR0YG//OUv2Lx5M06cOPE/V1Pb29uRkZGBSZMmIScnB6amPz2E3/1BsocxatQoVFZWdhvftWsXiouLkZSUhMGDB6OzsxMvvPCC0XmuXr2K0tJSDB48+JFum4ioL/BQYEREIrt48SK0Wi127NhhGFOpVHB2dgZwZ+sB8NOqa9c2gra2Nvz444+ws7MzKrZlZWX497//DQDo7Ox8qCwBAQH4+uuvUVJSYhi7desWNm7ciJKSEqhUKgQEBODYsWP49ttvjS6bkpKCqKgoXL9+/aFuk4ioL3HllohIZO7u7vDy8kJaWhpqamrg6OiImpoa5ObmYuzYsfD19QXw037Zbdu2ob6+HrNmzYK7uzt27twJc3Nz2Nvb4+LFi8jLyzMU4ZaWFlhYWDxwlqVLl+LgwYNYuHAhwsPDYWVlhc8//xzfffcdcnJyAABxcXH48ssvodVqodVqMWrUKBw9ehRHjhzB3Llz8dxzz/XyPURE9OhYbomIRKZQKJCZmYl169bhyJEj0Ol0sLCwgFqtxrJlywz7bX19faHRaHDkyBGcPn0aarUa6enpSE5ORn5+Pjo6OmBtbY3IyEiMGzcOb7zxBk6fPo3g4OAHzjJ06FDodDp8+OGH+Oyzz9DR0QEnJyfk5OQYSvbo0aOxfft2rF27Ftu3b0draytsbW2RmJiI+fPn98l9RET0qBSCIAhShyAiIiIi6g3cc0tEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREsvF/oiHeogIsR/YAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_performance_per_instance(results, title=\"Performance per training instance (Sigmoid)\", aspect=2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (dacbench)", + "language": "python", + "name": "dacbench" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/benchmarks/baselines_ppo_sigmoid.py b/examples/benchmarks/baselines_ppo_sigmoid.py index 019453c86..7487f505d 100644 --- a/examples/benchmarks/baselines_ppo_sigmoid.py +++ b/examples/benchmarks/baselines_ppo_sigmoid.py @@ -1,6 +1,6 @@ import tensorflow as tf import warnings -from stable_baselines import PPO2 +from stable_baselines3 import PPO2 from dacbench.benchmarks import SigmoidBenchmark from dacbench.wrappers import PerformanceTrackingWrapper diff --git a/examples/benchmarks/chainerrl_cma.py b/examples/benchmarks/chainerrl_cma.py index e445a48c0..428f0d197 100644 --- a/examples/benchmarks/chainerrl_cma.py +++ b/examples/benchmarks/chainerrl_cma.py @@ -29,23 +29,23 @@ num_episodes = 3 for i in range(num_episodes): # Reset environment to begin episode - state = env.reset() + state, _ = env.reset() # Initialize episode - done = False + terminated, truncated = False, False r = 0 reward = 0 - while not done: + while not (terminated or truncated): # Select action action = agent.act_and_train(state, reward) # Execute action - next_state, reward, done, _ = env.step(action) + next_state, reward, terminated, truncated, _ = env.step(action) r += reward logger.next_step() state = next_state logger.next_episode() # Train agent after episode has ended - agent.stop_episode_and_train(state, reward, done=done) + agent.stop_episode_and_train(state, reward, done=terminated or truncated) # Log episode print( f"Episode {i+1}/{num_episodes}...........................................Reward: {r}" diff --git a/examples/benchmarks/theory/README.md b/examples/benchmarks/theory/README.md deleted file mode 100644 index d5e00836c..000000000 --- a/examples/benchmarks/theory/README.md +++ /dev/null @@ -1,146 +0,0 @@ -## Randomised Local Search (RLS) for the LeadingOnes problem as a Dynamic Algorithm Configuration (DAC) benchmark - -This folder contains example scripts for running experiments on the DAC-LeadingOnes benchmark, and some DDQN results. For more information about the benchmark and the DDQN results, please see: - -- Our paper ([arxiv version](https://arxiv.org/abs/2202.03259)), published at GECCO 2022. -- [blog post](https://andrebiedenkapp.github.io/blog/2022/gecco/) summarising the paper (written by André). -- [video](https://www.youtube.com/watch?v=xgljDu5qE-w) - -If you use this benchmark, please cite us: -``` -@inproceedings{10.1145/3512290.3528846, - author = {Biedenkapp, Andr\'{e} and Dang, Nguyen and Krejca, Martin S. and Hutter, Frank and Doerr, Carola}, - title = {Theory-Inspired Parameter Control Benchmarks for Dynamic Algorithm Configuration}, - year = {2022}, - publisher = {Association for Computing Machinery}, - doi = {10.1145/3512290.3528846}, - booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference}, - pages = {766–775}, - numpages = {10}, - location = {Boston, Massachusetts}, - series = {GECCO '22} -} -``` - -### 1. Benchmark Description: - -The RLS algorithm only has one parameter to be controlled, namely *r*. This is the number of bits being flipped at each iteration of RLS. The aim is to find a policy that decide which *r* to be used at each iteration such that the total number of evaluations required for reaching the optimal solution is minimised. - -The benchmark is configurable with multiple settings available: - -**Setting 1: DAC-LeadingOnes with discrete action space** - -This is the setting used in our paper mentioned above, where a list of possible values for *r* (a portfolio) is given as the action space. A portfolio *K* is defined via three properties: -- problem size *n* -- portfolio size *k* -- type of portfolio: how *k* values of *r* are chosen to added to the portfolio. There are three portfolio types: - + *evenly_spread*: *K* = {𝑖 · ⌊𝑛/𝑘⌋ + 1 | 𝑖 ∈ [0..𝑘 − 1]}, - + *initial_segment*: *K* = *[ 1..𝑘 ]*, - + and *powers of 2*: *K* = {$2^𝑖$ | 𝑖 ≤ 𝑛 ∧ 𝑖 ∈ [0..𝑘 − 1]} - -In our experiments, increasing either *n* or *k* would make it more difficult for the DDQN agent to learn a near-optimal policy. Even with the same *n* and *k*, switching between different portfolio types also has an effect on the learning behaviour. For more details, please see Section 4.4 in our paper. - -**Setting 2: DAC-LeadingOnes with continuous action space** - -It is possible to use this benchmark with a continuous action space. In such setting, *r* is an integer value chosen from the range of *[1..n]*. - -**Initial solution** - -For both settings, instead of starting each RLS run from a random initial solution, it is possible to start from a specific objective function value. This gives us another factor for controlling the difficult of the benchmark: starting from a very good solution would make the averge episode length shorter and make it easier for the RL agent to learn. - - -### 2. Getting Started: - -A benchmark is defined via a configuration object (a dictionary). The following code create a benchmark with discrete action space (setting 1), with *n=50*, *k=5*, *powers of 2* portfolio type, and a cutoff time of 1e5 evaluations for each episode. Various initial objective functions are used and are specified in `/dacbench/instance_sets/theory/lo_rls_50.csv` (the code will automatically look into that folder if it cannot find the instance file in the current running folder). - -``` -from dacbench.benchmarks import TheoryBenchmark -bench_config = {"instance_set_path":"lo_rls_50.csv", - "discrete_action": True, - "cutoff": 1e5, - "action_choices": [1,2,4,8,16]} -bench = TheoryBenchmark(config=bench_config) -env = bench.get_environment(test_env=True) -``` - -Note that `test_env` indicates whether we are using this environment for training an RL agent or for evaluating a (learnt or baseline) policy. The difference between `test_env=False` and `test_env=True` is that with the former one (used for training): (i) cutoff time for an episode is set to 0.8*n^2 (n: problem size); and (ii) if an action is out of range, we stop the episode immediately and return a large negative reward (see `envs/theory.py` for more details), while the latter one means that the benchmark's original cutoff time is used, and out-of-range action will be clipped to nearest valid value and the episode will continue. - -For a full example of how to run the benchmark with various settings, please have a look at the five examples in `examples.py`. To run those examples, set the `PYTHONPATH` environment variable to your DACBench folder: -``` -export PYTHONPATH=/:$PYTHONPATH -``` - -The five examples demonstrate how to: - -- Create a benchmark with different settings as described above. -- Evaluate a random policy and the optimal policies (discrete and non-discrete version) for a particular benchmark. -- Train a DDQN agent, evaluate the learnt agent and compare it with the optimal policy of the same setting. -- Calculate runtime (mean/std) of a policy without having to run the policy. The calculation is done using formulas derived from theoretical results. - -### 3. Running multiple experiments: - -We also provide scripts for reproducing all experiments used in our paper, and the results of our experiments. Please see the script - -- To run a DDQN training: - -``` -cd experiments/ -mkdir ddqn -python ../scripts/run_experiment.py --out-dir ddqn/ --setting-file train_conf.yml -``` - -The command above will train a DDQN agent with settings specified in `experiments/train_conf.yml` (current setting: `n=50, k=3`, `evenly_spread`). To switch to another setting or to change the hyper-parameters of DDQN, please change the options inside `experiments/train_conf.yml` accordingly. For example, to train a DDQN agent with `n=150`, `k=3`, and with `initial_segment` portfolio setting, you can update the following fields: - -``` -bench: - action_choices: [1,2,3] - instance_set_path: "lo_rls_150.csv" -``` - -- To evaluate a trained DDQN policy: - -``` -cd experiments/ -python ../scripts/run_policy.py --n-runs 2000 --bench test_conf.yml --policy DQNPolicy --policy-params results/n50_evenly_spread/k3/trained_ddqn/best.pt --out results/n50_evenly_spread/k3/dqn.pkl -``` -The command above will do 2000 repeated runs of RLS on LeadingOne using the trained DDQN agent located in `n50_evenly_spread/k3/ddqn/best.pt` - -- Steps to evaluate random/optimal policies: -``` -python ../scripts/run_policy.py --n-runs 2000 --bench test_conf.yml --policy RandomPolicy --out results/n50_evenly_spread/k3/random.pkl - -python ../scripts/run_policy.py --n-runs 2000 --bench test_conf.yml --policy RLSOptimalDiscretePolicy --out results/n50_evenly_spread/k3/optimal.pkl -``` - -#### 4. DDQN hyper-parameters: - -We built our choice of DDQN hyperparameters based on prior literature using RL for dynamic tuning, in particular, each Q-networks has two hidden layers with 50 units (per layer) and ReLU activation function. The epsilon-greedy value is set to 0.2 (default value for DDQN in many cases). To allow the agent to collect enough information before the learning starts, 10000 random steps are done at the beginning of the training phase. - -The batch size and and the discount factor are set based on a small prestudy with the evenly spread portfolio setting where n=50, k=3. We tried two batch sizes: 2048 and 8192, both of which were able to reach the optimal policy several times during the training. Based on that result, we decided to choose batch size of 2048 for all experiments due to computational resource constraints. For the discount factor, we tried two values: 0.99 (default value for DDQN in many cases) and 0.9998. The former one resulted in much less stable learning compared to the latter one. This can be explained by the fact that the episode lengths of our benchmark are typically large (several thousands of steps) and most of the important progress is made during the later parts of an episode. Therefore, the discount factor of 0.9998 was finally chosen for all experiments in the paper. - - -#### 5. Calculate the optimal policy for a given portfolio and problem size - -Given a problem size *n* and a portfolio of *r* values, the optimal policy can be calculated automatically. Note that the policy is found using a brute force approach, so it may some time to run depending on the specific scenarios. - -To run the calculation, you would first need to build an execution of the code (written in [D](https://dlang.org/)). The following bash script will download a D compiler ([DMD](https://dlang.org/download.html#dmd)), and compile the code for Linux. - -``` -cd scripts/calculate_optimal_policy/ -./compile.sh -``` - -Then you run the calculation using the scripts `run.py`: -``` -python run.py -``` -Example: -``` -python run.py 50 1,17,33 -``` - -The output of the calculation is the best radius for each objective value from 0 to n-1, for example, the output of the command above would be: -``` -33 17 17 17 17 17 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -``` -This means that we should flip 33 bits when f(x)=0, 17 bits when f(x)=1, etc. diff --git a/examples/benchmarks/theory/examples.py b/examples/benchmarks/theory/examples.py deleted file mode 100644 index 137fa98b5..000000000 --- a/examples/benchmarks/theory/examples.py +++ /dev/null @@ -1,301 +0,0 @@ -from dacbench.benchmarks import TheoryBenchmark -import sys -import os - -sys.path.append(os.path.dirname(__file__)) -from scripts.rls_policies import ( - RandomPolicy, - RLSOptimalPolicy, - RLSFixedOnePolicy, - DQNPolicy, - RLSOptimalDiscretePolicy, -) -from ddqn_local.ddqn import DQN -import shutil -import numpy as np - -from scripts.runtime_calculation import expected_run_time, variance_in_run_time - - -def example_01(): - """ - Example 1: run RLS optimal policy with n=50 and different initial solutions - """ - print( - "\n### Example 1: run RLSEnv optimal policy with n=50 and different initial solutions" - ) - - # benchmark configuration - bench_config = { - "instance_set_path": "lo_rls_50.csv", - "discrete_action": False, - "min_action": 1, - "max_action": 49, - } - - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = RLSOptimalPolicy(env) # run optimal policy - - for i in range(len(env.instance_set)): - s = env.reset() - print(f"\nproblem size: {env.n}, initial solution: {env.x.fitness}") - while True: - r = agent.get_next_action(s) - s, rw, d, info = env.step(r) - print( - f"f(x): {env.x.fitness:3d}, #evaluations: {env.total_evals}", end="\r" - ) - if d: - print("") - break - - -def example_02(): - """ - Example 2: run RLS discrete power of 2 optimal policy with n=50, portfolio size of 4, and different initial solutions - """ - print( - "\n### Example 2: run RLSEnvDiscrete power of 2 optimal policy with n=50, portfolio size of 4, and different initial solutions" - ) - - # benchmark configuration - bench_config = { - "instance_set_path": "lo_rls_50.csv", - "action_choices": [1, 2, 4, 8], - } - - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = RLSOptimalDiscretePolicy(env) # run optimal policy for discrete portfolio - - for i in range(len(env.instance_set)): - s = env.reset() - print(f"\nproblem size: {env.n}, initial solution: {env.x.fitness}") - while True: - r = agent.get_next_action(s) - s, rw, d, info = env.step(r) - print( - f"f(x): {env.x.fitness:3d}, #evaluations: {env.total_evals}", end="\r" - ) - if d: - print("") - break - - -def example_03(): - """ - Example 3: run RLS discrete evenly_spread random policy with n=50, portfolio size of 3 and random initial solution - """ - print( - "\n### Example 3: run RLS discrete evenly_spread random policy with n=50, portfolio size of 3 and random initial solution" - ) - - # benchmark configuration - bench_config = { - "instance_set_path": "lo_rls_50_random.csv", - "action_choices": [1, 17, 33], - "seed_action_space": True, # set this to True for reproducibility - "cutoff": 1e5, # random policy can sometime perform badly so we put a reasonable cutoff here to be safe. - } - - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = RandomPolicy(env) - - for i in range(len(env.instance_set)): - s = env.reset() - print(f"\nproblem size: {env.n}, initial solution: {env.x.fitness}") - while True: - r = agent.get_next_action(s) - s, rw, d, info = env.step(r) - print( - f"f(x): {env.x.fitness:3d}, #evaluations: {env.total_evals}", end="\r" - ) - if d: - print("") - break - - -def example_04(): - """ - Example 4: train a DDQN agent for RLS discrete power of 2 policy with n=50, portfolio size of 4 and initial solution of 40. Get the final trained agent and compare with the optimal policy for the same scenario. - """ - print( - "\n### Example 4: train a DDQN agent for RLS discrete power of 2 policy with n=50, portfolio size of 4 and initial solution of 40. Get the final trained agent and compare with the optimal policy for the same scenario." - ) - - # benchmark configuration - bench_config = { - "instance_set_path": "lo_rls_50_easy.csv", - "action_choices": [1, 2, 4, 8], - "seed_action_space": True, # set this to True for reproducibility - } - - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=False) - - # initialise DQN agent - state_dim = env.observation_space.shape[0] - action_dim = env.action_space.n - gamma = 0.995 - out_dir = "./ddqn-output" - if os.path.isdir(out_dir): - shutil.rmtree(out_dir) - os.mkdir(out_dir) - agent = DQN(state_dim, action_dim, gamma, env=env, eval_env=env, out_dir=out_dir) - - # start the training - print("\nTraining a DDQN agent...") - agent.train( - episodes=100, - eval_every_n_steps=1000, - begin_learning_after=1024, - batch_size=1024, - save_model_interval=1000, - ) - - # save the final model - print(f"Training is complete. Saving the final model to {out_dir}/final.pt") - agent.save_model("final") - - # create an evaluation environment - eval_env = bench.get_environment(test_env=True) - - # evaluate the final agent - print("\nEvaluating the final DDQN agent...") - eval_agent = DQNPolicy(env=eval_env, model=f"{out_dir}/best.pt") - nRuns = 500 - ddqn_results = [] - for i in range(nRuns): - s = eval_env.reset() - while True: - r = eval_agent.get_next_action(s) - s, rw, d, info = eval_env.step(r) - if d: - # print(f"ddqn eval run {i:3d}, optimal: {eval_env.x.is_optimal()}, evals: {eval_env.total_evals}") - ddqn_results.append( - {"optimal": eval_env.x.is_optimal(), "evals": eval_env.total_evals} - ) - break - n_optimals = sum([rs["optimal"] for rs in ddqn_results]) - ls_evals = np.asarray([rs["evals"] for rs in ddqn_results]) - print(f"#runs that reach optimal: {n_optimals}/{nRuns}") - print( - f"Running time (#evaluations): mean {np.mean(ls_evals):.3f}, std {np.std(ls_evals):.3f}" - ) - - # compare with the optimal policy for the same scenario - print("\nEvaluating the optimal policy") - optimal_policy = RLSOptimalDiscretePolicy(eval_env) - opt_results = [] - for i in range(nRuns): - s = eval_env.reset() - while True: - r = optimal_policy.get_next_action(s) - s, rw, d, info = eval_env.step(r) - if d: - opt_results.append( - {"optimal": eval_env.x.is_optimal(), "evals": eval_env.total_evals} - ) - break - n_optimals = sum([rs["optimal"] for rs in opt_results]) - ls_evals = [rs["evals"] for rs in opt_results] - print(f"#runs that reach optimal: {n_optimals}/{nRuns}") - print( - f"Running time (#evaluations): mean {np.mean(ls_evals):.3f}, std {np.std(ls_evals):.3f}" - ) - - -def example_05(): - """ - Example 5: calculate average and variance of runtime of a policy without having to run the policy - """ - print( - "\n### Example 5: calculate average and variance of runtime of a policy without having to run the policy" - ) - - # We run each policy nRuns times and compare the mean/std with the theoretical calculations. - nRuns = 500 - - def run_policy(): - # run policy and collect mean/std - print(f"\nRunning policy for {nRuns} times.") - lsTotalEvals = [] - for i in range(nRuns): - s = env.reset() - while True: - r = agent.get_next_action(s) - s, rw, d, info = env.step(r) - if d: - if env.x.is_optimal(): - lsTotalEvals.append(env.total_evals) - else: - lsTotalEvals.append(np.inf) - print(f"Done: {i+1:4d}/{nRuns}", end="\r") - break - print("") - ls = [x for x in lsTotalEvals if ~np.isinf(x)] - print( - f"#non-optimal runs: {sum([np.isinf(x) for x in lsTotalEvals]):4d}/{nRuns}" - ) - print(f"Mean: {np.mean(ls):7.2f}, std: {np.std(ls):7.2f}") - - # calculate mean/std with theoretical formulas - print(f"\nCalculate runtime based on theoretical formulas") - pi = agent.get_predictions() - m = expected_run_time(pi, env.n) - sd = np.sqrt(variance_in_run_time(pi, env.n)) - print(f"Mean: {m:7.2f}, std: {sd:7.2f}") - - ### Test case 1: optimal policy with continuous action space - print( - "\n--- Test case 1: optimal policy (n=50, un-restricted portfolio, random initial solution)" - ) - bench_config = { - "instance_set_path": "lo_rls_50_random.csv", - "discrete_action": False, - "min_action": 1, - "max_action": 49, - } - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = RLSOptimalPolicy(env) - run_policy() - - ### Test case 2: optimal policy with evenly_spread portfolio - print( - "\n--- Test case 2: optimal policy (n=50, k=3, evenly_spread portfolio, random initial solution)" - ) - bench_config = { - "instance_set_path": "lo_rls_50_random.csv", - "discrete_action": True, - "action_choices": [1, 17, 33], - } - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = RLSOptimalDiscretePolicy(env) - run_policy() - - ### Test case 3: an example DDQN learnt policy - print( - "\n--- Test case 3: an example DDQN learnt policy (n=50, k=3, evenly_spread portfolio, random initial solution)" - ) - bench_config = { - "instance_set_path": "lo_rls_50_random.csv", - "discrete_action": True, - "action_choices": [1, 17, 33], - } - bench = TheoryBenchmark(config=bench_config) - env = bench.get_environment(test_env=True) - agent = DQNPolicy( - env=env, model="experiments/results/n50_evenly_spread/k3/trained_ddqn/best.pt" - ) - run_policy() - - -example_01() -example_02() -example_03() -example_04() -example_05() diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/dqn.txt deleted file mode 100644 index 4395568f8..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -5233 -4853 -4750 -4035 -3856 -5125 -5375 -5070 -3418 -4016 -4354 -3904 -5446 -4267 -2364 -4954 -4668 -3926 -2823 -4185 -4030 -6007 -3981 -4906 -4295 -5717 -3789 -4300 -5419 -3298 -3623 -5055 -5374 -4559 -4725 -3730 -4199 -3461 -4668 -4270 -3915 -4585 -3853 -5041 -4549 -3641 -3981 -3809 -4688 -4420 -5034 -4598 -4082 -5627 -3698 -4690 -3538 -4030 -5630 -5281 -5423 -4143 -3852 -4043 -2966 -3845 -5089 -3403 -4492 -2279 -3326 -4074 -4921 -4765 -4793 -4244 -3626 -3414 -4293 -3099 -5034 -3658 -4190 -4668 -3437 -4556 -4001 -4419 -5079 -3332 -5263 -4144 -6370 -3415 -5203 -4903 -3544 -4755 -5203 -6308 -4502 -4361 -4338 -5590 -4258 -3281 -3428 -3591 -4663 -4663 -5239 -4907 -3804 -4814 -4445 -4046 -5155 -4728 -3924 -4442 -4888 -4119 -3849 -4068 -4706 -6199 -5270 -4853 -5318 -3314 -4405 -4177 -4646 -4306 -4534 -5342 -3579 -5924 -4421 -3331 -3611 -4312 -3745 -3121 -2941 -5222 -4035 -4724 -3797 -3371 -4588 -4567 -4916 -4992 -4688 -4225 -4635 -4155 -3570 -3427 -4248 -2213 -2620 -4241 -2967 -5567 -3159 -3874 -3989 -2567 -5650 -4348 -4987 -4354 -3871 -4792 -2757 -4262 -5575 -4586 -4436 -4942 -4956 -3301 -4372 -4581 -4426 -4479 -4394 -4988 -3469 -3443 -4035 -3061 -3209 -3777 -3874 -4596 -3266 -4148 -3656 -4918 -4831 -3922 -4808 -3811 -5076 -3493 -3737 -4636 -5221 -4540 -3898 -4109 -4714 -3948 -5023 -4373 -4829 -3348 -5689 -4396 -4470 -4378 -4004 -3796 -5093 -4093 -5325 -4169 -4018 -5129 -3751 -4489 -5903 -4285 -5449 -4680 -4164 -4958 -4197 -2697 -3256 -3250 -4551 -3778 -3691 -4400 -5191 -5013 -4550 -5103 -4709 -5275 -4096 -3922 -5352 -3946 -4165 -4690 -3670 -5903 -3838 -3574 -4280 -4402 -4411 -3562 -4182 -3726 -4108 -3536 -3243 -4119 -5829 -3073 -2668 -3714 -3043 -3874 -3277 -3966 -4298 -4465 -3799 -5158 -3466 -6374 -4581 -4343 -2509 -3201 -3691 -3122 -3338 -4093 -3408 -5251 -4913 -4033 -3540 -5046 -3283 -3275 -5277 -4805 -4832 -3259 -5495 -4171 -3735 -3706 -3927 -4210 -5383 -3404 -4203 -4178 -4504 -3608 -2995 -3477 -5373 -2590 -4240 -5001 -3660 -4374 -3086 -4024 -2351 -3923 -4774 -5066 -3482 -5780 -3345 -4279 -3614 -5088 -3933 -4545 -4310 -5576 -5094 -4831 -4159 -4043 -4270 -4764 -5230 -3783 -3535 -5695 -4138 -4371 -4057 -3650 -5559 -4482 -4794 -3157 -4038 -2642 -4656 -3067 -4149 -6081 -4564 -5590 -3545 -4656 -3260 -4057 -4934 -3983 -3622 -4696 -5527 -3219 -5184 -3587 -4249 -5374 -5209 -3995 -4190 -5775 -5007 -3923 -4493 -4887 -4122 -4559 -5056 -5016 -4210 -4243 -3550 -3896 -4176 -3685 -4633 -4608 -5600 -4460 -4622 -3393 -4539 -3649 -4007 -4833 -3517 -4211 -4247 -4535 -3690 -4471 -4715 -4250 -4079 -5328 -2961 -3443 -4335 -4128 -4470 -4020 -5423 -4275 -5032 -4031 -4982 -5054 -4787 -2994 -4369 -4944 -4866 -3560 -4110 -3990 -5059 -3840 -3923 -4346 -3431 -4837 -4784 -3711 -3029 -3730 -4065 -3413 -3592 -5054 -4271 -4544 -5306 -4173 -3974 -4866 -4007 -5253 -4524 -3908 -6022 -4763 -5531 -5019 -3572 -3631 -4067 -4317 -4098 -4098 -5257 -3987 -4088 -5449 -4616 -3545 -4991 -4087 -4832 -3635 -3909 -3407 -4506 -2959 -3901 -4038 -3755 -3498 -5130 -5564 -4121 -3937 -4679 -4675 -4914 -5151 -3640 -3827 -4775 -2672 -3904 -4044 -3543 -3284 -4086 -4128 -3442 -3893 -4521 -3360 -4487 -4143 -5607 -4835 -5321 -4530 -3438 -4554 -4080 -5226 -3856 -4728 -4061 -5364 -4568 -4061 -4881 -4450 -6096 -5029 -2662 -4862 -5268 -4229 -4480 -4556 -4336 -4937 -3689 -3275 -5114 -6466 -4700 -3825 -3662 -3227 -3812 -3424 -4474 -4686 -5191 -4236 -4746 -4597 -4976 -3265 -3835 -4733 -5459 -3526 -4362 -4950 -4454 -4878 -4607 -5225 -5190 -3742 -3874 -4559 -4497 -3190 -4363 -4694 -5451 -3770 -3539 -4073 -4084 -3157 -4157 -4853 -4078 -5227 -3786 -3718 -6009 -4128 -5267 -4873 -3570 -3672 -5017 -5062 -4612 -4017 -3231 -5743 -2744 -5072 -4790 -5756 -3084 -4318 -3830 -4505 -4287 -4663 -4353 -5840 -4781 -3980 -4278 -4750 -5492 -4600 -4716 -5255 -5397 -4324 -4476 -4501 -5031 -4584 -4736 -3662 -4527 -4976 -5829 -3081 -5245 -3045 -4482 -4770 -3456 -4602 -3265 -4427 -4131 -4828 -4137 -4856 -4489 -4219 -3042 -3460 -4395 -5347 -4337 -5625 -3863 -4564 -4774 -4082 -4610 -4821 -4691 -4205 -4745 -4543 -3552 -3784 -4760 -4200 -4208 -4449 -4218 -5887 -5080 -2963 -3588 -4620 -5220 -6513 -3736 -3280 -5106 -3985 -4266 -5002 -4843 -4251 -4972 -5637 -3086 -4074 -4582 -3833 -4514 -3399 -4517 -5192 -4161 -4523 -4729 -3546 -4717 -5151 -3605 -3831 -5105 -4065 -4913 -3363 -3730 -3805 -3762 -3593 -3406 -5077 -5933 -4800 -3516 -3143 -3387 -5083 -5648 -3730 -6321 -5056 -4926 -4101 -4973 -4315 -4029 -4960 -3481 -4313 -4217 -4470 -5334 -4923 -6411 -6195 -4268 -4238 -4150 -5656 -3762 -4088 -2868 -2515 -3878 -4934 -6879 -3255 -4476 -3383 -3735 -4704 -2764 -3649 -3466 -5025 -4005 -3851 -2610 -4013 -4110 -5431 -3495 -4901 -4468 -4701 -2922 -4712 -6351 -4434 -4327 -4399 -4662 -4902 -3585 -5284 -4309 -4643 -7192 -3874 -3328 -3469 -4271 -5915 -4413 -3658 -4983 -4629 -4034 -4143 -4972 -3279 -4869 -4703 -5405 -3547 -3720 -4301 -4201 -5112 -3900 -5670 -4664 -5272 -4035 -3472 -4262 -4500 -4449 -3398 -4367 -4469 -3830 -5058 -3060 -4052 -3407 -4840 -3850 -2803 -4658 -3975 -5048 -5021 -5047 -3880 -3148 -4330 -3630 -4353 -3567 -5825 -4118 -3334 -4058 -3870 -3405 -4433 -4400 -6379 -4353 -3994 -4003 -5042 -4156 -4394 -3247 -2749 -4164 -3596 -3757 -3421 -3278 -3543 -3699 -3433 -4277 -4631 -4840 -3847 -4415 -2855 -5008 -4895 -4724 -4441 -3495 -4457 -3418 -5541 -4562 -3890 -3859 -3995 -3598 -3800 -4040 -3910 -4790 -5802 -3492 -3632 -3595 -3291 -4814 -3812 -5022 -4675 -4074 -4594 -4821 -4305 -4352 -4044 -6162 -1968 -4618 -4514 -5649 -3903 -4243 -3942 -5581 -3640 -6009 -5421 -4233 -3213 -4587 -2970 -4694 -4371 -4460 -4171 -4458 -4711 -3383 -4239 -4568 -4140 -3877 -3791 -5033 -4698 -5215 -4357 -4596 -4323 -4888 -3515 -4211 -4119 -3977 -4777 -4754 -5121 -3740 -4924 -4779 -3706 -3094 -3895 -3537 -4050 -4385 -4193 -2967 -4731 -3828 -6626 -3730 -2918 -4710 -3985 -3479 -5288 -3539 -4974 -3884 -5210 -3354 -6026 -4126 -3824 -4221 -4126 -3647 -5530 -3742 -5166 -4974 -3643 -3868 -3495 -5239 -4582 -4029 -4348 -2659 -4473 -3415 -2583 -3845 -3746 -4320 -6296 -2437 -3603 -3769 -3868 -4441 -4555 -3734 -3388 -3780 -3254 -4081 -4227 -4058 -5573 -4383 -4059 -4375 -1961 -3340 -3172 -3846 -3647 -5053 -4861 -4972 -3753 -3560 -5013 -3789 -4196 -2892 -3966 -3782 -4634 -4554 -3080 -3940 -3735 -4965 -4269 -3870 -5209 -4403 -3738 -4893 -3920 -4098 -5321 -4575 -3015 -4103 -3484 -4090 -3444 -4369 -4167 -4135 -4556 -3478 -4544 -5068 -5216 -3727 -3695 -2537 -5372 -3030 -4429 -4401 -4121 -3972 -3486 -6011 -4553 -4683 -3282 -2826 -3607 -3562 -3775 -4427 -4243 -5099 -3835 -5189 -4716 -4110 -2512 -4644 -3121 -4130 -2888 -5077 -4457 -5271 -4159 -4470 -3949 -4219 -3996 -4717 -4456 -3954 -4115 -4417 -4487 -4116 -4859 -4553 -3566 -4154 -3766 -2943 -4951 -3346 -4429 -3547 -3830 -2776 -4015 -4087 -3693 -4088 -5389 -4240 -4222 -5203 -5071 -3704 -4940 -4510 -3158 -4119 -4058 -5095 -5050 -3921 -5500 -4144 -4966 -3523 -3994 -3962 -5230 -5324 -4430 -3575 -4101 -5209 -3819 -3715 -4072 -4740 -3535 -4197 -4748 -4867 -3222 -3753 -4640 -4212 -4721 -3583 -3660 -4742 -2962 -4189 -4214 -4703 -4153 -4731 -4948 -4665 -5394 -5814 -4220 -4105 -4765 -4951 -4280 -5399 -4295 -4283 -4336 -5589 -4804 -3458 -4736 -4471 -3594 -3485 -6649 -3851 -4199 -3895 -7347 -4425 -4887 -4634 -4530 -6227 -4078 -3752 -3399 -4428 -4182 -5823 -3638 -4636 -4333 -3937 -4921 -4632 -4846 -4748 -4129 -4548 -3992 -4258 -3858 -3937 -4348 -4156 -4907 -2975 -4811 -3710 -4307 -3708 -3297 -3334 -2977 -4300 -4895 -3060 -4282 -3241 -4133 -4284 -5852 -5659 -5226 -4620 -2916 -4789 -5015 -5736 -4941 -3691 -5081 -4162 -3974 -4314 -3995 -4561 -3390 -4293 -3976 -4015 -4721 -4382 -3438 -4503 -4287 -3389 -3300 -4233 -6068 -4674 -4116 -4575 -4104 -4812 -6036 -3537 -7009 -3599 -4917 -3008 -3565 -5933 -4893 -4964 -5372 -3973 -5484 -3670 -4750 -6685 -4534 -4540 -4748 -4522 -5197 -3533 -4451 -5454 -4743 -4569 -3502 -4646 -5270 -2880 -5445 -6246 -4716 -5564 -4339 -4351 -5564 -3985 -3803 -5428 -4553 -6553 -5583 -4633 -4110 -4081 -3991 -4391 -3284 -4364 -4414 -4720 -2456 -3353 -4089 -4216 -5025 -4087 -4012 -3899 -4129 -3934 -4755 -4924 -5143 -4253 -2403 -3845 -4020 -4786 -4327 -3604 -4264 -3772 -2600 -4589 -4227 -4093 -4473 -3335 -3229 -4293 -4300 -3714 -3947 -4888 -4768 -3980 -4932 -4188 -4105 -2457 -4238 -3368 -4541 -5868 -5245 -3808 -3704 -4213 -5034 -3566 -4362 -5432 -3661 -4805 -3923 -4138 -4657 -4692 -4664 -4071 -3801 -3071 -3911 -2668 -5543 -3638 -3796 -3918 -4877 -4903 -4961 -4058 -4905 -4199 -4803 -3805 -4952 -3422 -4253 -3987 -3230 -4154 -4902 -4431 -4594 -4676 -3314 -3806 -4178 -3728 -5183 -5456 -5554 -3736 -2794 -4110 -3824 -3382 -4284 -3489 -3929 -4446 -3419 -4773 -5256 -3444 -3345 -3756 -3938 -4032 -4343 -3804 -4870 -4239 -4227 -4355 -4706 -3485 -4086 -4143 -3156 -4665 -3738 -4214 -3407 -4393 -4754 -4069 -5436 -3663 -3556 -3793 -4098 -3963 -2947 -4953 -5312 -4021 -3320 -5569 -3993 -4572 -4452 -3857 -3685 -4258 -3707 -5572 -4059 -5231 -4834 -4390 -4027 -3465 -4500 -3936 -3923 -3343 -4485 -3123 -4584 -5437 -3564 -4149 -4237 -4348 -4253 -5392 -3403 -4450 -6221 -3585 -5200 -3486 -4532 -6172 -4075 -6061 -3419 -3824 -3919 -3940 -4522 -4236 -4492 -5063 -2725 -4327 -4601 -3639 -4188 -4865 -3151 -5213 -4127 -3409 -4387 -4680 -5014 -4839 -4273 -3384 -5414 -3739 -4226 -4201 -3436 -3950 -5345 -4673 -5647 -4156 -3298 -3775 -3863 -4014 -5364 -4109 -3705 -3559 -4896 -4774 -4148 -4318 -4389 -4125 -3924 -4807 -4451 -3418 -4420 -4390 -4259 -5165 -3765 -4950 -5868 -5589 -3515 -4005 -5267 -4969 -3700 -6543 -5573 -4270 -4967 -4126 -5633 -5733 -4770 -3548 -3779 -4591 -2618 -2239 -4109 -4015 -5593 -3967 -6038 -4179 -4867 -3709 -4099 -5414 -4967 -4803 -2376 -4557 -3769 -5699 -3508 -4132 -5320 -5578 -3205 -3370 -3471 -5084 -3987 -6199 -3963 -3848 -4120 -4284 -4595 -5493 -5177 -4444 -3677 -5124 -4244 -5238 -5393 -4585 -5297 -4155 -3661 -3847 -3675 -6293 -5351 -4589 -7209 -5654 -3285 -2239 -3395 -4397 -3809 -3679 -3031 -4441 -4987 -2589 -5546 -3800 -3153 -3854 -4362 -4828 -4769 -2356 -2926 -2731 -5036 -4507 -3989 -3415 -3607 -3070 -4137 -3569 -4630 -3858 -5176 -5546 -3764 -4761 -3523 -4592 -4235 -6032 -3943 -3051 -5023 -4263 -4002 -5226 -4032 -4068 -4307 -4809 -3318 -4383 -4200 -4781 -3825 -3110 -3576 -3970 -5109 -4464 -4076 -3989 -2533 -4963 -4153 -5169 -4635 -4068 -5697 -3821 -2980 -3623 -4710 -4621 -4463 -3815 -3665 -2962 -5871 -4816 -3589 -2335 -4652 -3964 -3897 -5106 -4669 -4761 -4753 -3631 -3736 -4156 -3991 -4265 -4575 -4998 -4069 -4304 -4376 -4406 -3764 -2856 -5140 -4553 -3753 -4968 -4580 -5386 -5465 -4491 -4310 -4861 -3677 -4163 -5064 -4666 -2856 -5117 -4548 -4589 -4449 -3915 -5015 -3856 -5584 -5482 -4971 -5626 -3815 -4280 -6673 -4411 -4283 -4079 -3179 -4738 -3810 -4225 -4655 -5352 -4812 -3967 -4515 -4527 -6190 -3639 -5642 -4093 -5255 -4920 -4603 -3317 -5261 -3985 -4651 -3876 -3931 -3616 -3543 -3973 -3390 -3957 -4006 -5582 -5436 -4720 -4348 -4977 -5037 -4667 -3947 -3563 -3946 -4348 -4776 -3721 -4834 -4767 -3436 -3965 -3586 -4091 -3528 -3726 -4416 -5067 -5399 -4034 -4669 -4247 -3664 -2939 -4413 -4244 -3366 -4561 -4510 -3208 -3656 -5367 -3851 -3222 -4627 -5132 -3667 -4250 -5314 -3701 -4388 -4403 -4352 -3511 -5527 -5084 -3799 -3648 -3570 -4551 -4404 -3627 -3654 -3881 -4799 -4418 -5327 -3773 -3720 -5141 -3448 -5513 -5202 -3247 -4102 -4413 -4208 -4397 -4719 -5317 -3878 -4629 -3790 -4330 -3575 -3390 -6245 -4686 -3296 -3491 -4272 -4309 -4747 -3757 -2816 -5401 -3765 -4725 -3767 -5388 -3242 -5122 -5494 -4162 -4283 -4503 -5631 -4021 -4087 -4029 -3225 -4816 -3917 -4955 -5129 -4981 -3657 -4201 -4337 -3744 -4926 -4850 -4226 -5378 -3153 -3403 -5286 -3340 -4182 -3888 -4005 -3746 -3369 -5334 -3782 -6279 -4981 -4750 -4043 -4469 -5292 -4474 -4755 -4070 -4710 -2969 -4023 -5027 -5535 -4195 -3074 -4142 -4216 -3245 -4234 -4004 -1764 -3786 -3921 -4349 -4945 -5728 -5509 -3693 -3365 -3908 -4543 -4492 -3874 -2964 -4510 -5114 -3044 -3081 -5216 -4344 -4208 -4427 -4221 -2211 -3286 -5618 -3106 -4635 -4874 -4076 -3833 -4597 -4036 -4019 -3487 -3575 -4644 -4512 -4427 -3203 -3577 -3133 -5998 -4419 -5279 -3934 -3788 -3848 -6331 -5212 -4557 -5051 -4652 -4394 -4860 -4472 -4424 -3562 -5088 -3754 -3375 -5219 -3667 -4528 -4002 -4358 -3032 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/optimal.txt deleted file mode 100644 index 7f9ec339a..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4399 -3677 -4399 -3741 -3329 -4779 -4466 -2724 -2813 -3586 -3717 -3790 -4331 -4752 -4819 -3478 -3627 -3766 -3898 -4289 -5327 -3725 -3962 -4326 -4362 -4467 -4433 -4874 -2541 -2743 -2284 -3555 -4761 -4493 -3217 -2704 -4337 -6018 -3722 -3311 -5377 -4298 -3987 -3905 -3643 -3787 -3971 -3497 -4242 -6191 -4371 -3839 -3409 -3951 -3140 -5988 -4185 -4535 -4474 -3846 -3561 -4687 -4967 -3232 -3974 -5461 -4255 -4415 -3656 -3848 -5193 -3651 -5140 -4007 -3684 -3230 -3606 -4421 -5228 -2535 -3811 -4592 -2793 -4384 -5948 -5648 -4665 -4538 -4585 -4481 -5078 -5490 -4166 -5228 -3678 -5897 -3887 -4787 -4350 -3037 -5336 -5338 -3205 -6014 -4078 -3225 -6214 -4853 -3238 -5619 -5555 -3884 -3919 -4289 -4892 -6038 -5302 -2859 -4912 -4266 -3190 -5007 -4428 -5636 -4202 -3915 -6465 -6178 -3586 -3273 -3906 -3553 -2600 -5588 -3749 -3317 -3830 -3543 -4259 -3792 -3704 -4160 -4599 -5090 -4765 -4668 -4588 -3638 -3406 -4630 -3170 -3790 -3709 -5007 -5461 -4089 -4635 -4741 -4287 -5243 -3994 -3982 -5360 -4235 -4528 -4095 -4633 -3415 -3750 -4246 -4421 -5500 -6143 -4351 -3532 -4441 -3089 -4082 -4136 -3781 -4431 -4810 -3593 -3638 -2886 -3676 -4124 -4031 -4555 -4583 -3409 -2411 -3739 -4491 -3540 -4371 -4759 -4561 -5003 -3692 -5072 -4688 -4838 -3457 -4366 -4357 -3827 -5553 -5597 -4761 -4490 -3681 -5035 -5567 -4244 -4108 -3105 -4558 -3715 -4539 -3151 -3456 -5524 -5198 -5200 -4126 -3830 -4087 -4642 -3762 -4239 -4379 -3992 -3836 -3496 -4005 -3051 -3867 -4918 -3850 -3919 -4011 -4217 -4078 -3030 -4035 -3409 -3771 -4100 -4870 -3922 -4631 -5856 -4567 -3787 -5652 -4328 -4658 -4542 -4056 -3860 -2570 -4004 -3653 -3363 -4293 -4694 -3602 -4180 -3181 -3765 -4194 -4257 -4127 -5403 -4292 -5125 -3805 -4472 -5151 -3473 -4501 -5164 -4211 -6590 -3781 -4759 -4877 -5477 -4433 -3090 -3960 -5478 -3700 -5958 -3704 -3864 -4164 -4413 -4198 -4265 -5046 -5055 -5016 -3009 -4717 -3343 -4413 -3738 -4998 -3511 -4553 -4232 -3759 -4823 -3726 -4892 -5045 -2951 -2616 -4231 -4798 -3216 -5057 -6025 -4124 -4409 -3862 -3057 -3071 -4047 -4231 -4040 -3785 -4059 -3822 -4005 -4527 -6307 -3637 -2960 -5218 -3013 -3886 -4540 -4781 -5323 -5227 -3983 -5865 -4642 -4210 -5141 -3642 -3330 -4091 -6483 -5026 -5766 -3405 -5650 -5153 -4295 -2985 -3688 -4956 -4927 -4128 -3914 -4918 -5705 -3513 -4750 -4666 -4579 -4958 -4164 -3856 -3684 -3168 -3393 -5024 -3852 -3680 -3939 -4499 -3931 -4675 -4837 -3882 -4128 -4443 -4418 -5115 -5293 -5326 -4783 -5151 -4956 -3818 -4180 -2671 -4553 -3756 -4655 -3421 -4296 -4119 -3173 -3827 -4706 -3437 -4049 -4229 -4233 -3929 -4770 -4479 -4310 -6125 -5571 -4176 -3955 -4703 -3499 -4416 -3743 -4617 -3677 -3692 -4436 -5255 -3589 -3595 -3781 -5582 -4126 -3853 -3993 -5132 -4387 -3305 -4002 -5556 -3716 -4798 -3453 -5904 -4283 -5820 -4416 -4900 -3437 -5227 -4422 -3588 -4271 -3394 -5311 -4553 -5648 -3941 -2851 -5248 -4587 -4570 -4273 -3468 -4599 -4390 -5926 -3172 -3554 -2802 -3750 -2821 -4861 -3590 -3636 -4325 -4583 -5819 -3711 -2619 -4961 -5222 -5124 -3924 -5185 -5184 -4147 -3519 -5391 -4232 -4058 -5175 -4654 -5455 -5930 -3792 -4309 -4547 -3981 -4184 -5683 -3819 -3885 -4329 -4562 -5558 -5396 -5421 -4005 -5073 -3881 -4374 -4633 -4330 -4168 -4236 -3215 -4290 -4784 -3299 -6025 -4400 -4947 -4095 -5283 -4617 -4027 -4180 -4326 -4615 -3756 -3782 -4662 -5686 -5059 -4187 -5188 -3629 -3960 -4211 -3512 -4982 -3846 -4950 -4976 -3729 -3686 -5597 -4834 -3935 -4558 -4699 -4010 -3870 -4824 -6131 -3942 -3749 -4309 -4578 -4278 -3881 -4034 -3517 -4094 -3766 -4947 -3636 -4949 -3596 -4141 -2949 -4192 -3377 -3733 -5131 -3420 -5234 -4189 -5600 -3581 -5587 -4731 -3089 -3108 -3894 -4829 -4551 -4260 -5924 -4561 -5180 -4857 -3136 -4281 -3959 -3768 -5068 -4227 -5743 -3874 -4287 -3308 -4961 -4689 -3819 -5496 -3988 -3424 -5902 -4140 -4402 -3940 -3579 -5804 -5378 -4771 -3453 -4753 -4841 -4194 -5064 -4948 -2832 -3965 -2840 -4694 -3685 -4913 -4775 -3685 -4418 -4220 -3082 -4782 -5562 -5621 -4331 -6333 -4974 -3388 -4896 -5775 -3228 -3898 -4296 -3641 -4550 -3966 -3980 -3481 -3454 -4754 -4526 -4831 -4263 -4424 -5075 -3677 -5225 -5449 -4969 -4159 -5108 -5624 -3860 -3345 -4152 -3249 -4116 -4682 -5977 -4880 -3706 -5163 -4835 -3695 -5164 -4792 -4369 -4767 -3846 -4155 -3765 -5149 -5674 -3660 -5372 -5098 -4659 -4354 -3727 -4548 -4196 -3875 -4869 -3803 -3433 -4038 -4131 -4928 -3036 -4231 -4173 -5395 -4837 -4649 -4842 -4263 -4501 -2714 -4763 -5186 -5112 -3629 -4474 -5749 -3973 -3590 -4135 -3899 -4498 -4926 -5100 -3187 -5714 -5395 -4728 -3749 -4533 -3801 -2889 -4037 -3101 -4605 -5684 -3390 -4329 -3448 -4268 -4832 -5541 -4294 -4492 -3452 -3935 -4813 -4102 -3330 -3842 -3048 -4052 -4501 -4319 -4707 -4352 -3938 -4742 -3035 -3262 -4286 -3708 -4352 -4646 -4147 -4697 -4587 -4012 -3705 -4254 -4260 -4632 -4793 -4441 -4492 -3479 -4214 -3213 -2652 -4701 -2957 -4112 -5164 -2983 -4817 -4521 -4505 -4706 -3793 -3978 -4807 -3872 -4665 -4649 -4879 -2651 -3927 -5125 -3938 -5261 -3175 -4474 -4112 -3193 -4800 -5066 -4998 -4408 -4508 -5166 -3325 -5721 -3377 -3726 -5027 -4087 -3299 -2865 -4931 -4019 -4172 -4151 -4517 -5883 -5047 -5152 -4998 -3258 -4399 -5006 -4231 -3465 -4478 -2376 -4432 -5404 -4894 -2819 -4802 -3573 -4313 -4667 -4896 -4545 -3634 -3070 -4543 -3425 -3612 -3919 -2605 -4453 -5032 -4850 -5444 -4763 -5270 -5350 -4920 -4405 -4090 -4396 -3676 -3752 -3864 -6144 -4739 -3899 -5078 -4501 -5099 -5229 -3296 -4100 -5448 -4501 -4485 -5044 -4259 -3894 -3399 -3372 -4385 -2273 -5122 -4728 -5895 -4426 -3589 -4130 -4496 -5462 -3747 -4617 -4204 -3947 -4899 -5686 -3887 -3840 -5388 -4019 -5378 -4542 -3835 -3749 -4530 -4258 -3466 -4454 -5297 -4746 -4119 -4148 -2967 -4170 -4505 -4841 -5421 -5182 -2618 -4946 -4250 -6107 -5008 -4796 -4750 -3697 -4199 -4535 -3185 -5485 -4244 -4513 -5577 -3050 -4164 -4346 -3217 -4701 -4951 -4846 -3565 -3227 -4239 -5336 -4498 -4143 -3009 -6582 -4356 -3976 -5590 -4094 -5059 -4420 -4182 -4089 -3239 -4503 -3557 -4096 -3425 -4699 -3900 -3687 -3626 -3968 -3400 -4056 -4530 -3526 -4179 -4962 -4903 -3893 -4463 -3953 -4933 -4310 -5361 -4782 -4829 -4411 -3705 -4875 -3987 -3720 -4833 -3526 -4162 -5597 -4056 -6106 -3913 -3914 -3500 -4526 -2944 -3918 -5030 -3597 -4592 -4596 -4370 -3829 -3156 -4544 -4224 -3101 -3255 -4013 -5225 -3937 -4338 -3800 -3506 -2960 -4176 -3948 -3760 -3698 -2849 -4230 -4887 -5286 -3483 -3770 -4553 -5888 -4159 -2673 -4394 -3941 -3840 -6766 -4907 -4796 -3677 -2942 -4411 -3693 -4702 -3496 -5043 -4322 -4057 -3438 -3722 -3968 -4394 -5550 -4520 -3999 -4467 -3628 -5781 -3834 -4661 -3841 -3079 -4093 -4060 -4498 -3992 -5999 -4279 -5259 -4647 -4476 -4644 -3397 -4506 -5220 -4319 -4709 -4487 -4693 -4304 -4391 -4002 -3450 -4716 -4448 -4452 -4629 -5157 -3671 -4245 -4903 -4244 -4479 -4667 -3876 -5183 -3623 -5625 -4348 -4136 -3684 -3545 -4815 -5469 -5786 -4196 -3347 -3531 -5480 -4621 -4340 -4974 -4287 -4103 -5413 -3523 -4921 -4932 -4227 -3964 -3723 -3692 -3747 -4114 -3746 -4127 -4137 -3309 -4638 -6334 -5566 -4099 -3340 -4306 -5213 -3712 -5556 -4467 -4550 -4538 -5204 -4203 -5547 -5629 -4732 -3614 -4736 -3936 -6247 -5268 -3585 -3760 -4977 -4062 -3603 -4053 -4363 -3787 -3778 -4053 -3481 -4155 -4943 -2982 -4515 -4510 -3947 -4199 -3366 -4436 -3631 -4424 -4965 -4656 -5063 -3070 -5098 -4382 -4789 -3451 -4447 -4686 -4785 -4203 -5413 -4500 -4320 -4742 -4038 -4036 -5071 -3706 -3534 -4611 -4696 -3276 -5405 -4265 -3659 -4385 -4084 -4938 -3588 -2653 -3243 -4052 -3127 -5209 -6195 -4076 -5152 -5335 -4690 -3781 -3520 -3974 -3400 -4006 -4451 -4465 -5133 -4043 -4808 -3146 -4018 -4315 -5063 -4600 -4092 -3116 -4247 -3773 -3512 -4414 -3070 -4403 -3416 -4919 -2595 -6259 -5686 -5844 -4525 -3245 -5106 -6005 -3830 -4062 -3753 -3611 -3148 -5033 -3874 -4233 -4507 -5929 -3096 -3895 -6117 -3439 -4168 -3700 -7009 -4426 -3321 -2545 -5357 -4025 -5017 -4636 -4529 -4291 -4754 -3342 -3476 -3419 -3411 -3681 -2369 -4017 -5732 -3533 -5938 -3266 -4902 -4825 -2702 -4130 -3847 -4275 -5582 -5800 -3893 -3560 -4708 -3233 -4960 -5498 -5861 -5901 -5018 -4120 -4396 -4768 -4261 -5771 -4897 -5054 -3105 -3847 -2953 -4701 -3372 -4201 -4189 -5816 -4922 -4393 -4243 -3894 -4069 -4659 -4541 -5215 -4280 -2391 -4287 -2475 -3572 -5137 -3609 -4851 -3950 -4090 -3745 -3080 -3418 -5514 -3508 -3724 -3480 -6703 -3788 -5390 -4108 -5273 -3747 -4610 -3194 -3773 -3093 -4125 -4229 -4466 -4462 -4304 -5366 -4515 -4187 -4710 -4406 -3197 -4838 -5259 -6289 -4748 -3941 -5130 -5488 -2855 -4070 -4348 -3727 -3673 -4660 -3463 -3708 -4186 -3390 -4836 -4046 -5359 -3075 -4936 -5054 -4080 -3950 -5125 -3918 -4962 -4025 -4939 -5145 -4301 -4957 -4431 -3259 -4496 -4399 -4624 -5430 -5172 -5128 -3161 -2259 -3856 -2838 -5775 -4365 -5964 -5725 -4748 -3909 -5185 -3419 -3160 -4956 -4400 -4467 -5087 -3151 -4592 -4068 -4624 -4837 -4191 -4875 -4397 -3851 -3645 -4285 -4243 -3964 -6355 -4034 -5334 -3221 -6621 -4770 -3578 -3913 -5765 -4027 -3828 -4499 -4521 -4027 -4152 -3489 -5259 -3865 -4341 -5097 -4383 -5318 -2995 -3655 -4824 -6406 -4769 -6068 -3737 -5038 -6443 -3570 -3565 -4701 -3640 -4915 -4376 -4256 -3878 -4149 -4603 -3419 -3971 -4044 -2801 -4390 -3982 -5143 -4548 -2658 -3585 -6582 -4286 -3881 -5590 -4855 -2811 -3798 -4404 -4124 -4470 -2775 -4207 -4266 -3652 -5136 -4894 -4144 -4441 -3325 -4055 -3537 -4188 -2787 -5163 -3740 -3412 -3706 -4317 -5133 -4132 -5097 -2797 -4654 -5424 -3658 -4887 -3273 -3892 -5012 -3132 -3963 -4914 -5580 -4835 -4323 -3897 -4208 -5231 -4131 -4871 -4062 -4867 -3677 -3849 -4327 -3961 -3933 -3543 -4218 -4883 -3061 -4150 -4112 -3698 -5203 -4927 -4679 -5069 -4367 -3036 -4224 -3286 -4030 -6413 -4319 -4666 -4310 -4138 -3767 -4348 -4834 -5492 -4813 -4347 -3603 -4491 -3398 -4708 -3921 -5755 -3391 -3629 -4099 -5164 -4964 -4372 -6029 -3737 -4460 -3105 -4569 -5885 -4060 -4638 -3282 -5116 -3088 -4552 -5359 -4314 -3700 -4063 -4052 -5052 -4086 -4143 -4879 -4088 -5403 -3751 -4454 -4544 -4119 -5201 -3963 -3525 -3448 -5856 -4992 -5413 -5181 -3989 -4698 -4451 -4452 -4343 -4187 -5373 -5220 -5342 -4852 -4702 -4144 -3625 -5089 -5079 -4709 -5128 -3262 -5063 -4112 -3608 -3895 -3849 -3974 -4408 -4675 -4315 -2822 -3884 -4301 -4249 -3914 -5229 -4032 -3730 -5032 -4404 -3645 -6086 -4808 -4035 -5151 -4184 -4907 -4713 -4198 -5366 -3807 -3377 -4740 -4921 -4630 -4837 -5060 -4775 -4196 -5112 -2849 -3682 -3776 -3702 -4244 -4292 -2815 -3051 -4640 -4644 -4345 -4171 -3751 -3716 -2927 -4693 -4002 -3671 -4472 -4411 -4340 -5177 -4557 -3601 -4400 -4070 -5275 -4659 -3596 -4006 -3785 -5766 -3999 -4585 -3981 -4510 -3686 -2532 -3372 -3425 -3809 -4912 -6158 -5001 -5064 -3923 -3321 -3663 -3852 -3601 -3117 -3025 -3953 -4562 -4169 -5049 -3378 -3925 -3112 -4020 -3950 -6607 -5022 -4428 -3777 -4474 -3581 -5022 -5289 -4300 -4888 -5443 -5196 -4289 -4954 -4379 -5174 -4233 -5338 -3877 -3752 -3326 -3145 -3197 -5350 -3734 -4225 -4133 -3031 -3788 -4170 -6531 -5119 -3288 -3463 -3701 -5018 -3712 -4735 -3991 -4719 -3978 -4021 -3961 -5309 -4535 -3568 -2956 -3857 -4024 -2640 -4703 -4442 -5725 -5057 -3520 -4713 -3648 -4129 -3731 -3995 -4629 -3986 -3624 -3294 -3768 -3835 -3552 -3471 -4928 -3623 -3381 -4669 -5097 -3452 -3039 -4074 -6054 -3948 -5484 -4587 -5139 -5474 -4680 -3960 -3682 -5251 -3818 -5873 -3421 -4838 -4802 -3970 -2794 -5192 -5038 -3220 -3891 -5405 -3909 -4844 -5458 -3655 -4347 -4026 -3305 -5427 -4540 -4221 -4431 -4127 -4636 -4804 -3924 -3847 -5550 -3740 -3812 -4532 -3529 -6262 -4964 -3659 -5360 -5060 -4668 -5133 -3671 -4050 -3310 -3359 -3770 -4138 -3505 -4592 -3658 -5204 -3894 -4328 -4233 -4052 -3811 -4894 -5393 -2790 -4460 -3739 -5705 -3752 -5067 -3470 -5522 -4917 -4448 -3939 -3624 -4819 -4540 -4103 -4746 -5397 -5112 -3007 -5112 -3771 -4617 -3857 -4741 -4506 -4055 -5124 -4345 -6508 -4560 -3376 -4414 -3353 -4210 -4229 -5299 -4899 -3517 -5268 -3631 -5257 -5566 -4090 -5201 -2352 -4745 -3944 -4056 -3175 -4445 -3611 -5291 -4403 -5970 -3991 -5679 -3772 -6841 -3299 -3366 -4676 -3140 -4571 -3991 -4386 -6019 -5363 -5369 -4750 -4076 -2947 -4873 -3820 -5433 -4494 -4425 -3681 -3748 -3793 -4215 -4333 -4048 -4063 -4182 -4926 -4353 -3805 -3070 -6598 -3052 -3347 -4219 -4732 -4079 -4681 -4102 -3996 -3992 -4030 -4288 -4520 -5019 -3973 -2978 -5091 -4305 -4108 -3408 -6353 -3481 -3989 -4281 -4060 -2662 -3626 -5826 -3850 -4311 -3791 -3773 -3291 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/random.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k10/trained_ddqn/best.pt deleted file mode 100644 index 025748aee61248b2147fb25e8df48ceb4b7d3e58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14871 zcmbt*30O_t+jsLk389e&QY2-nv+s36A`KFm%Ge-N9F?gum!W~AL^RMODWS;O_u8dM zN`{JzNz!bnP=xRJKmYgr9?yHd?{$6ex4KsQoVC~QKEJi@wf4T(TKDbZASop#CMPHM zUy_=by4cFip1y0gc#rd18L-l9)4KI`(^SNk{E>D`czSMJzuwz3V9iE9e}y@ly}UPj zd)cn>3{Vh=jdm4?8!u82iT3dvZ?@HY&1&BOfrMwkMv+*v<$(cf*83|g-|W3AaLszJ zZFj6axfGt^(ynznl7-&Z;#l{RJw% zqTlkB^8HKJc!8>~tb;{>KLT` z2oM;$3XJ|u!}339jQm5w1i>f~jUMp;f$?t<3JxL~qyM5|@|PIX0Kphn!PtM(u>6aL z*&jkC3dV_OC;3t#0LK{e8-vFO&jo!!7CccBy|p7JjIC&fBr)_ zxwwS4Ph5rXwl{~19x#!AtokFUP(N}?t&H1pJWd!eKA0{}(4*4>G{|_BGMbeWPky;w zCYNMPISp+!D!3{`M%-9NwvISVx5}&Y-z?%t(>YUq#Dt+xtT390_Z_1b!++w|tukcD zk(qql6pGWsmAIK+Uueo9b=vtqkLa*5pK99z7;d*oV16Mr8<rc~JH;2#&^W`+l!h^c6&4P0qC5vt!Rpk~aPo`sz71FQ% zcWBYe3DocY2g)ut<7|fN(u|H`oMvJJ(@rLmhAA)UoeT1u;Kozfr2h-!+=kG?>o)w* zji-el$Jp`phE1oYIk(9Ads*DT$`aCk0RVQ^DiyrkVd&1^@B1`mbN^G6#v~w-A!$_mUjD zP(oe@kKp$|dO#wC55a$g1LD&2Q;)fp?Ek=IF>{o>|f9S{`~;GGIuV>OdG?+1(Z^wz5_IQo+(LM7C
+5DCl_4LB~@pSxvRI1&j!tq=u@xwjj=%^o2xa`v+{>F(Zn00s!b$MsV z&&%?rlO6Z)cZBJX$$6j1$^LWHch_tByWi{=-Y&Q!nsmSO|I}~HpZ#WGH*L!QbHDvZ zPkK37<6yxla`4NHqH*?@dHWosNsihX)Jn?5RXz&D`9vW-ot4BsZHgn8jAxK$VGN9H z5t3681ZTAkCKHxQ(wk1E(2~G_#(8CqxnW0$cLoWaeVy)<$idBiHK6bH5%%7?0;9@R znI8w&!sec5pl4mp3V%LigKa1=xYZ1ydq1LG&va-@wjyB-nned?BFKmmmau&$__la3 z|FmTmk?R;n%8pr6r=js&iyVdS$Mx{(v^QhZ-UAn9C^4NbLx$QvCO1AMkZ*0hT$`pi z7}~7{dxM+2ZDAM5ag)h#b@F8LdF5!5=X0JU`g0JmIz%KRpNPYExL4NCs2pCwq>VP_ z9}Q0@c8gZx)>~a9v?4^PTPK7){?RaO^m{tI_$L<2yWyy?40spJFxyAw!cyKe=HxtE zHppf#>Z&G_37&gMjE*aP_0oWB->`}V>?$Jn&r$9?a~}>IEg>l{y2uwP!sid~#J5pp zWN-9wc%>c+)lr$GC{-IS;XATMRWwgGG;t{|=W$c744Pl|fH|W3whd}zQ2RiVT@_1e zJ@$~RITC0eQi+-F>U@KVNAdK+2+$dJ5N`J9@*4+d66e-IWSg57-$GT5+V9v63*RK+ zpa*?)xQQ}#+H!~o8N=Y_f^L+SF(#k3kB3_amB=jDDwL?9#QobrQlHVvR{K4LVyW?j zkrEPLDB%iaEXaH17bL3m9?9Vw@i(3O#z>V0k{6osxCi~P^qx3#Ib9E{1qs4W@3i38 zpk$%Wv3l686~R>J9%4GKSFvX*55VR8Y-}qjL@ARHCf+9tn-$ub4zXO6ud2bNhZ;eD zXbmJkkHoX#VK{hXE95D(L(qs*;K)eR*35AB*_Tc*Yv==iFCDPk*NFi<4x9Urz|GdX z7;h^}n{EmLgTJxA5=SyM;pwpOW-<>1Ec#AagPE}*=t-`D>}n4T`lZOw`F?wG!?Ao!`Dg{nK|XkXQXM?q)B(pml>nAFGV7&78J zc3(e;pZ#UY)@#r4$M$tNbYm2+K3tj>pB&8eC9Bf(C7Vz@YzHK7SK#&~P2#lD+xS9( z2{-%89Gv;12Pfrxz(uy=L_*SmFLO8sdK4u&=db=;QAR%vd3Tat89WvxZY`p@)dkGy z*^1O_Z#JX2&w(H2k|Qe9pc<`a{KLyP;?-?_u!z5$>G2%N@7-Jnvzcqi2Dw0$Q4;Qa zB263A$B^9zR$@%sNsKOeOn(e8r4t@L<8Qz1!o`J5Cn?*$ku^=?M4{J)i*ycWrfxh) zKCCFFMfh?+ffe#_w|tCRknm2`a-6$FUeb1v7*Nc520L6h-Wz;Hr;R< zU;ai2JlDTN`j_OA+EwL%6{Ke>7?8LV-9l}34y4gRj*;g}>do5B6qh^X;3OadC<& z-F$Ttou*rcYrhT!YxNCa%~ceBo$?)$$9;kLud>8UV=d$V={Yvcy6d@?oV%90(p#Kneo=Ss{T8cEKte^Q#-!x+zq=1Z$tH}d$26J3+3h?MuVS^Q9`{I6mH5TkjUf%_ z>2ntBlfAJx;x=xRcp;n>e*o4^9u7wmwnMhhX?9KhA*Mim6700iMsc4om@r0@dMuJ8 z4g*V(nW_Ua-_J4n_0nu>{0r3NU&l+n*D+hG3)H(N;jtN2I3ex;z7mWFtNEd9oRTtb zP-ua!fIgV^FcKf^>&Lfyt}-2w&(Sq%AIx5+$+&DD2VTZ9Xyhx)Dpl`6sIbMv{@pO! z>MjIcTLR~b8o+$ueuyo|gL#(XRI7dfxFxBPCl?=qx>PgzcYI-=_Fslc*%^iQUrVsr zK*;-`_YwKFd{(3G6-2)9MWsC}!COz9-mN{zi?s?ykLPn4$HnnrEB6#XU%3uv#wW8m zc4dtF=YE_wWhtAwA^}||h!Mk2PjG{h1TJ}S4E_3|@$vF<)LwC(ZJIq8UcNj9uh<}F zp-qIa`}_bXHJ(l!Ukd&+9GE@{bvC8j5vrDPc+31Qs8vhR#=g7QI&TYXoghvf2fxDP z_~(r3_0zCNTMTdLY+#n3$;YEU;$+yl1K^SW2o=1HU`}>E?)dBv4NVI8*-a7$=0(BT zd;WNR+b+x)5Qn^5*J0bh7a*uV2=^l)8;eY+0zBmHaA?Tz4Kd<_ZAvujOK`R{_Dm-v0PGh}C z--OK2&=;_^RnWosA?|MV5-be9W#HqB?O);h7f z?bNBM4U3l)FJfzMA$BB6kh}@k$f(&m$WysSiZ9+GkKd^kC9ct-GrxITt8cepts->z z7kACX;K}~PbnQh_sA)?cuh>WTVMPZd{Eiu_o~(ufhcSdvVnn|`uKV%1>9 z3O$-+8NuY04y6$uv9KdZiJpwDV-K6XVj3FdaE4bM+_h04jgdNF?`(oyOVy#q{07^V<{jVEi^4Y>($TQ&(F?vuo?-n$ux3rX;9 zBOjv2oA3;cI^ngYCe12Ugo71+a9rvcJ2zb(pB+ge(>ygve%%Kmr&&ev%Lf!i?s$o3 z95P`>crXN2Y4V54F0nQ}e+`;E(ulL&YBK!QXfk`^4SaT@mRz}AkBMS^kTISU*)5Cs zRcCXFmwF7b8#9~#oIQo*cUhRNn}=xMOXszo=D8Q%hFIQB7!oT--a0k23_pz+ZN3G8 zIRn|&Sp}rhK#aevWEDM8K7(XOPb44qYw*LS*K&r_t`X~---&C59zW|U;on~ohHf$6 zNl+Hz;$$^);@LfRg?=8omPO;jQ&Etb^#ao;m|)YbO0<8O0MUVlRC0I_UJ}n_-n>qP zqi?T5M5-3k<{(e}AjI{6-h1u|!G z@{mlJ**1_m%vgvqG5XkESIH#2+yqaC#^7xkJ-D~}3+DfjCEQ~r^7UIc*j(y{gpsPG zV#H_ckB}s1dRw6XB7+tmkAYo{EgL?`2Toh%;eefQaY*YyXgSf&p3ELhv&3i8uj_r7 z=F(m?^q)ur>^pdhS5m5W$5HIvi2G}_?Fl&!1 z;7kb?+#4S=I=e=*%?f4E@^%Tfbbmu<)!W!xEl&5dl0<6wJw`!yKAdS@#Ed_F0(;u8 zGm9`3j`d!_6h=JAegftXx`N=&!nc>07^KPaz ze)L?5_S_0=ww9r~`>XJaiWIH7Ax3*-yg)bmDH}Lng=SyNW;LID!~6$rOsaSnR3#in zdu?el+WH)L9g%^c;V0RIf@Lr=O$U1q72(X_mB@Sg3@(`sg`q_u?7S8+^w;6QmQ+IC zBM*FPUnBf<^8z#AO+SVuN8*{4R+u+EgB-rJmvnuvBaF;b@ z+FAoXwg_68DkPx(9#krwhICtby2yMsPFIvimx6HNxAh7zULzV*AFxchybLv~@IeQc zi@4vd{RW+)1xqijLSA7KP7N30Be7EUAsC_OrhQC(yD@Y>v0y^_itzrA1<+}10NZNQ znJfF=V^wN3x>hygENMBiaHTo@yi<%0x!oqbTBnFN#uR~b^(8b7xdz6e(%4BjyjfZV zcSjAvq!a4&ljI9Ht4cvGHyYkLOcsXamk1ftXwf>O79)=pLEZ%)bkW=gUOS6f%e{fT z4VMlHTU&<1xw{K-60ZjmE-az##oKYo%px}HyByQ@atGTRql9lax8R(Z!=M{%14}CJ z;_8JnF=>t%E&Kw^l?wkofi#4eKO3FU&E`zMr3n<-Q16F6RGIoM2lw9fv=`(yq z_U|`nl2T>lvfi-)x=Qr9X%q(4&B4JL3UJcnBk0e3g!1pJF#PUeURT8r{F?n89aUS{ zU#Xo!nWK_aa4?t|)tQS0Ipv_MkN~b*rAT|hBmCyK1}+wh(~EI&5IHmnXB1b$;6=k| zT(lcF`c8wM2`{iE;wD5Yc|y?GUxODn97(A;EABy%LgkBDeviULVv55yn_C3Yu$_N+~ zFbq~n@nGjjccxmbmN(36qc!ySqQPxhYUw%v9ZN0<#|J3Wc{@IX#BM2SI{GE1+?AsJ z3)(=*aWizxEQV1U1=#d!J#jrdl)krUgD09JLG}C(u64^5I2*JEqtuf@?@l5awD<&S zIIqJNBUj??JcgJ^gitMEJUV7yg_p9LFeg+Qx12Cwb&L)9jrj}6_E$PgUvnB6G?fK| zf-d;Bt;)mRHsPBDEJO8>@UWUIeRgy;TA}0i4h;W(_oW) z7~CZ#sOFj@AV07TwSI`xAiq|o_~=_qm=X(*e`G;VPy)WFd=1|lq)G9tYv5f?K+&ZP z$89)*CC*Rb@-S68a>xeg4ME)UAs*w|2dsT<3r-&V9xI={#Zu98`EuDc(3=&__>12_ z+2kR(?r|>4>QvzQ00DEoMV`2-)}Xs=6JYVh0K$Q}3=Rf1- z842u)VjdO@bYkcFtC9K%=6HUg2cGs%LzQ*P*lRZ(1JzPkBeVNBQEr5W1wb-||8s8qi4CZE6aoZIk#NFq?ui4Xu(W?_7vRn;oqL+|$ zkJE_pdqL5Bg}3b5w#DSjN-Zi;uS}J7PQsO-Y&z|M2kVS=T|Ds zB4;0Kk~q5zD7lx)b(P4ejUVuaUt05c63mtvnPIHng(?f1H6xXB%dVVFkQZ7K5Q)`8ZK^5I9<#g9WQQnR9a^i&Cve z5`~pPY>r5mvE7YmBEAVMYn+N44)rl#o0pS~GHPV>({T8uu1ORO!_Zni7Tga$$3we5 zz}9YQd~M{)xn~Rqqv~{GQr}DUc{xnW&X3HE{cY@y2h~hXgvch1mZJ{qo`SL7IJhWy z!YqB`PsZPz3@<*XL4;c?yc-_`j+f7Hvy2sqwc;_N<-35_R`HFD@LEnH4i}=r2PGQ( zMYniHlmtCt)XT;vda-HoH{kf$^Dy{jA#?G=5qj^?1&BE`0rxB3#6t%!Fiwi&;r#bb zJSi9hDH5mgnsy)@oKA#M?F-?xhbnn8-V^e2tWZzy1V(>W!OaHpbRW${HOx2!qP z;&%#E_MU^bvuZ@zQxY7~l(Ek>5&EXjf~JBzcDLCL&}!*|<>#fzO1p5dzkVG1TfcyM z!XRjOislXPTgTwU%S<4*2Rk~BVa+`yYIsr(xB3pEXX3?ZeRK?S_gp6q($(fINy&if z%B8I1i9qztVK8&G8@4p2fmE)KFse?9xMn0{#;XOOA!$Snc*Xd-=q1LkssvB|I{4gj z0Zm@sV!s*I;J3||sIQ#O^t>C4{J;R%as2|L=Di=4=gGs!uXDkBNGa~o*Abnoox(?P z6R4Uz55;=;B0KU1?l$a#82v=(zIPidQ;$N4R~2jtGQ;PA55dvzBPK~?@}?(jXBMpU zV!}P8nM)-sPIT5sb<>Nu#Pm3Pmi~ZZg1P8vvzPI`mj!0GKjEj@WiY=}4NeCu(gyJ~ zyj5Vr3{Ed1({~On@(ofTi&{cR?r}M)e(DPh3K|AGA0DHMFOGvH4~b0uR-)fHmpD7_ zC;b;DQtv4ZFkEnkb*c+uUY`}GI}AS1Kwk%3bgF=a`)SfE-O6;XfgC9@+5-t)Rb)$< zJcd530j^tyj+l3Y^)u9^7kUPf0h^>@$$8PU_u52a=Bh<3B5S$F_J_gzx(6|-IRU8+ zlKiChS|}Ou5TXvcL&2~`T&>Iv=$4<37nYp{T}@@8$KMU_nT)kkfGbTB9{ zfppp7qP^UMa6r)pKP{A`S_`kUu{jcSc~CzbzdIb4-O`4wMmJFGun*J>P(tUNB4`=f z$M}4{gG=90c-9fh@SJ|)f+{((j?3i9UCkF3jSFN>IM0K*OR6A7s}-s~&jaf>GjQfh zHSF*n0;_EESfA$oxP#ZrbSo9Gq*McC1FD$i2WNur1SvX8;sYkV+sx#zRuFDJv|X66 zGlMZ1)&yNAW-z7&+2|!|dre*+O8I?+ro3kG=xBs-s}!i8mjfI*G!`P+1+aI-Nha&z zQ+WMFh`MhxA);)e^=E|uT+x^bqh#wqZ4i&Q)L09g4nD+ZsS0G%uOFy#BA)4pk-?mv zEZ(=ID`1!u3gcDP!OH3+RMs`Yu$E8=E90^EjXN=B>_qT?c^Ah-$G~M>0W^QjWm4{C z<1;oA^@E0>;o4Rl>3p8Kc=|aG8+iz|O~t|UOa)%se~T@*-Hu1D-Nm}z0U$N?0j!I> zfsUQ`;b!1B7!$P^=1S@^5!#Yu>}>@me&uO4CN~Aegr}ifVhN<}IuH6^W?)mZ9k1!o zVpc^u4R^HpVY&JtoDtTHS}JwS*IVb=5H}~hd*G<`S*H?QFhm}&x++tlnISCxQV04; zb<9hf$Lu+&1E8_96195wi1wytV47${c~o1oCltpC=cyV{IU1s zb9}RRKQFnZo=s}|i3w}Q2o1drffrqZy`f`qYtJV5`E@wDo!f_2KU8?Gu6d}@+lA#8 zKUlxZ#cbk|I&5h;hATcw(P^?L*qZ|+sE=4Ld%`pwVzT>rlLnUK^FbL{-8>ZExJ2Pl zD+{>X9*J>fOJM}#f*Lcgz*vVp_$F;MWV+?T^y_($@I{`!T|JqVwHk`|ljZ2*b|1X| z>kxX55hKT^?t+6g=UMkp$&giG3pvbUtc_`ari~3?@tMK+u?l3Ury5N>!SS}7s(}2e z2Glvf7!t#C&~M=~46`@^r=RbEDOSti?vc6J$O+jY9Y9{7U1)ErCS+xqZo+vlOoGhdvw{{)N~noghDdXV*- z7LyfF%s|P2=4{OyH#oMaNtR@Mmq-F9m|W7FM+;Ot*laRD`)4#z|c!8zR%OdpS!YPlczE~i5bTmKW`i)O~1)|d`APO-oJ^PZ!Bijcm84}o|x0i3%5Yv zLJJx%FAhiZS3{z(k2S2jgJGAh@;)BZfYnzIfYVq7dbZt^>QuPEfmeNCA$=QUcFU6t zy=S~<-cQ)Kt2e>od1>f)><;*132Ps*3*Y4SoI#HG7|QVUV@9m&)}hcAGkJ|53znJP}c4P6Z4V~NxM*@qYjf!f5pKEM&grHIdtuL zhO1-zVPLZq^%9+*8b&&z$;>P0XLTIsibXPm=E~6Zv7)`^`(I#AuQ>I&as)nJ&H!h} z0-StVfchDdM0Gtv>Dfg5RmlVS_y*yjoUwH9c`MPGgd&YPL;V?eCPLg*r!J z!OHchQnCUYt_5HTN)Tfv1=jCbfDNZucI|FCDwke_F-Hw~_m}BGjN@7?-l0yHtC`RN zANJw|%>#H(q;OH5NhgaQ&*b}eN@4+XMJTHd$uTkKS z>{aCF?ds<4mOO=~*dw@6vrx( zcHcA>pH+i~%vyfvz6KJSKZYbO-OTq^k;f%Jir`6(I}TW-&ees^ohqS*VnG$!98~y_GyfpZdQ9nsrZ5s5iZy;OKcaqQ#rhMHwjhxNa)5NG}1iv#$ zo(AexA|y#&l6>*uxy;ccB~5f z0X3yE#6+@@H|9kI_~{wJ+r27O)m;p#TxUW){{;kp+7GE?4npB`Il5-Y9=5%@4K=@1 zz$4EjXz6_f?*|0qw=ZL;QcM!t)tw27?gyYSHxJ4#1VZ39Ga9_T+e%&E8g7oei1xl2 z`1F1vItdoyfRzhy6qf-}*Df*b5$bflxCYhlD#5V3*6gZm0eBS*r7bI6aL(1aqPZLf zwH58?R3L`3W0j~u!+mJBN&w<10Vmz-z%x{w=D>WsUc4DLbbrC47t@(@7Z*cvun^=9 zZDKNqzl28t*32l!WB4S-0v=pH45X%%?HQ~``;N3?$~rGlNexDwv{W3Jp9p9C5^!as z7gVG=z-8!wZ!dJPyEB0e$lMM7Yc$cxUJ_JiYtsIxbkOo@2KOO9(Cm{oPOCWx8&=9< zfVU$g)efiEuH6Eg`f?0DT7x6AcB6xZXe}3)#Qd6DhTb{}aBzVX@V02+TE`yd`h!N4 zvMwwnX`PJuZ z%NM+0&C5&SvdC^f<#r1eemjT#8qy?6kjS3M7Nd&i3sG0^5Gqw3W)fRAL6Kw)yLzP^ z>oH~@cz=pUZR35o)B7$Smr7w*h-`u3kDAcmycQNmU&G496s<(>oVau)d{JHn8zvov ziV4*uc+m)0bGU&7&pt(L*QgY^AKQv+ZLi_YnUB~PY1Vx2?ohn#BP8Q$`bkopBwto% z2MPJy!(RNjfUjWDf%{!U;YgOk}bMi#` zI#`*Uns%MNtt3w#hbqvZ4+UV;(I?v1c)}J6M5*ld8 zKfAM+YyWhH%)e#GH#^!%G<970>yEua?Voad8m+~wcRmfj{qW3|Dwn8@5)=EK|0h4Z zfA}w2{%`yj1InkutMm({hAwwHuGlc7Z}2Vi(wA*c>Kj329> zU|k47g|s^Igc#w0FC}D-bvTUlm%(iv>)5;>GW5aZCZbiIjfELAsrh$}8(Y*FXg$Xf zR@@1L_dLYbZAWqD@L%N9s%OxX(1_7Jvef-_H4s}p(3-7geQRYK_D8+NFMJIgSNRCF z)~v!;=7qQ{T7_Qg*JGT2&-VhsI|j`H)f@Q79?817Nw z=C8blw?+=*hDwjZcL&0tZOshEK;9cvWJYuIwoJnZswddm1((=0JMG|^7Sb=hmtgsz zZgzfoJ2?|Sid*$ynrD=7lNVs_fZ?Y_{ziOF6kG{lgGK8c`-DW$I;lj@ z9h2Z!wM4Ol-GB1F&i9A>2PRxwtO`9kuo-S8?i1>KAJ2`P`jRZ4D#5)@QRYl1gh9VR zl6F^=6TRKTIOB1b7~Z5)@Ipx(H@cajrAHhVy?Mr}zEk8rMaSdv#Gf>^pb8uxD9|R% z26!L`8AMs zxd`RTg>=#SqtN$6^j_|1CiUybacQfnu#MHWakIY29+@<|kef0V#2qh^Pj`6O=C~g< z$M6{LgA`HRFNuS{i}7cr-(}v*)ZrYh(P*<&n%gMFLQ6m^JYSg&onNiE>v!77tIrQ; zXHhftv`vP?!>^!j!9!xT&y2hJ)DGsqK7u3p@~jx9!Ex;cY|rgCV45m?xH44id(O@c(c@05RDrR=GHBkj0$ySns1!b-kLN#TyzD%1Y%CZX&sZU&p;Tn9#HDX|+OLv1EL$H>P$?2=a%u;SDmHuTJQa-tMKQbP{! zu_7QbP$Ej;+)P7CGKjXIb`k^+1P3iNNTAWM>}K~ zrPuFqcSV$?n+LLv7RWF_U*xN)OHY~cBxrVVxh?$a2tjj6lV(+d1=@_(;Yq<*U&K@m0-N{ zJFJ{9#1TvggXcGvtLEBB_WAHR~-jqraHn7 z1tmPuWz1cw%wdSe3-*Y#Dhz38gjShKx>)QB&%ksm1dM4VQri?c136Q6NVATOy_Fbf zn-2uhXrbTyatQ5+;|Yw#$sSS;C-o!X$)@$}%3 zHf(_QmmA=;u^9ieZ#UL1+y+&l-$CQ?NG@=+44s)%fP=S8fLSiqoY$-dGG&zpXOupI z)2ZAJZo^WrUi=>E9b?Xw98#v|s5E^9^^9#?4gPS>$E)W1aLcBFoY?#lI2_kYT~x2I zJ1*1%z~Cb)x>OK{Rt>J(BnNaq zT*O)YXfRj%i5XeRFf-B@7?S~G-V)=j(CY$CtNX&}AFbap6}tFdErJ1TA`;tztP`yQ5=MKF9(uWz?|-F2<^Dq*hyUPPkFBR z=@RbUwfFyu&-gX3OVU^roAEpU_ql!a zcXn|Q|9$z-n7+SVdvBgMM?q-iA0Qc5pnb1CJ<||Zim0uW-5zrXA!k=maem)RmjI|zmNI9bh&e*ub;p~e0X-ke*aRKKnFh5ejo7sTZ^F&z2ArVdyA3J z?EO9#|7zLcx87i}ourfmHGA7O5h0=9b@6{|z6wIBf0*yI>GS3c`-kxgEO~+cN&0|s z8OLk;Nsf2b5YNtTqQCYasa{lz*ISy2?(HJ_jN3|-Sl2@gwt9f3`ch``#&`~eU76`- zR@~ZfdG6*GVdl`#HtwQPHWMJem3hZvnkxMt2!KNXOk_ie)PQW0YzTBML3PT3A``8?bv+aI*DLh zmI5U^Cje5*{KOC8pp?G*>a^14&D$pzT{+nN~|puHm{eJ1g0n zto_(dq=P@w%9C8^Z@t+EwF>lWF|El0WW~=}DWvqS)TuhPSIM0OznM5bFjZTWwXO@S* zgPR}9$T^itvUcYSx~h8@U9)i-Qg;g+E;N(vlyq)W=FKcn{eCg(?rQGmmVF}ODi5<#i(nu*xtQ^p67NBdwv;k>8mGT z^Kw4f?=J}f`$u#8ABl45W^9tnkuVMsUGi^DIKFvhlW4kOztMEmb>p-*knWgJ3k$n+hSobkG6 z^rTgyWJh>D?RQF!NQW;&>#i$AHm8S@_#{n+V#S$q&msOO%Rw~r*np=ym%{WB!=P`` zHk$ENB)+DL!7t|vJ;aQqzpb~ROt+{p#=mCKg^uqbtYHog3=GjubHkXx+9VV&5MdO@ z)WNEv5$L2nmY$c|jz^Aa7CqS8!n5LJ$ZTo_9hY&7zF=4m4<%wjzxgBNF8B%A-<$b* ziFY8^RhWd>ZpMT8DXe`q0m)G#NtwzG2wJ=r)-T)x@q4a;ZjmW^^CtkA*be*HE8x@; zg)672qSqK5GI>r7Fp1*u#5kp}e`X8*`1uK9>$|AWiU;}6?ZoJCjXLC?XW11opJCcE ze-yqb&n|nS$Bud)3L9@mP>*$z;kHpUOv&)aOY3{7BJ-cHS7Z^=R0E{TR^p_c2-fp5 zQ6jh=W2O@T%SagfaEO)M*bf&!hQj^UZtT7G0&X?F!PG7b>=ar+osiXq1DpNL8udcq z#pMn-fScLf!*qE==TymJKP6%~;UVxuSgS^opn$&u&iToYDVJKdE4GeqpaQn&EaCZE4te29d_kWZj)Ypk{sUQcx z)n3FV{T|em76I>hSI~u%rH#hUftn3MbVbcs95+XX=q{C`-3MNxtCbXyT7Mf;m2ZQh zt{Z5qw8A7gVNfwjW%caZL6yK?{gED8Zja|x1`?SyBo zo>FtvW`lPK3+=}(sGbX2czCZf2;CfH7e>>VMsrXXz{e@YQnZY{FwmD5K<196 zV^nxQsI*^W^Pd|c*Sv*Y$YoN~h6~Xl{A(B{)DIR%AHe=2G0^8*ja7+#lwO)>#q#UspnEleiP+ypKoUD+)oX7HR-5-`(U475*np?rx1X_=sb zI47!Am_v#CmoU^{ap&es>C)s~1*lBe#&or@+^_j7ULSo97w!nMqk zyc9@yxC<;_riA)#a&)}Za;nPzCa@J-*k!sFY(&5yKAgS-*(EYKn^eH^7$qV+VFo^& zd4d(bJA`|tZv+qS2^KX~U?Fs(?(%P7{rkDWA|$bOh+S4xhk^Pk@Ga^y_1>Zd9;6<` z*DB{Q-|`HM+BX#0X~tFNKvummi-nvXM;!hz1bimOgl!nT6rD6%{ho-_;LhyV$a zdBPEOGv|V1_-JTa(t|`@3-4+VzYWz_)w5<-coE$ji1%WKT z{0)`bD?~d;rqPLQV&tl?2lGivj(J(0!1|pLVJf&f`g2q{S#azg9%qCYMt%~!y^=|H z^1oB>bcdiVV-)FxFdkj7hd|{P~`@kC(>o^ zCy|7qmSc)$+gsr+I80@%eZ#tF2GZ}nkHeHGH$0H>3SKR_1}%<4Bx&ke^gKI@3W*cU zW&IoBU}FKy?aqVaxfiI7_YPt2$}V{Ae;;h;cYx6LYpCP24D0Ox4NmqhoR0PCb}g6o%f>kKt=&GCoQaqE9VQBqKX>FwI+mHqem3{cplxpz8#0 zQJ4uAqxlKn$%~O!x2EwYuOM`1RVzC62QjnlofvYR=BEyBr5oF|nfdC+NL6hJ*Q2D! z*nQT5tcVx%#r3tUM-B@^NlxTQaSn=Uf5e1VG3HZQ0cEW(N33_fg730dfR~#It%Wgk z_Jfl+e;@-h6<*Mbg^cK4S0xhDqQ~e)&Ze(F&!NWDm*8G~2_{nBim^rH$&4&jVZ5VF0Rc-z(8dD~o0;<@I};2t<1 z7alHva3@`GEr|iWk+N94_Zj;wtd4JPCrxziF5|agC7iT03-~UJcvbT%sLKkX^nQLK zY*oAsvkY=^#q^EbY&sO*QE?F99*T+=jOlqU^0-lT4>KfY!n7nFhrPzH=~bnQ%sa0O zq$Ndz`_LxId?;~buk@kiPtdS%T5oY`KACBug?FT_hJ-=z{{$&fDI%z8$zobSYN zyXNszqen5PKFiXKu_&35=tR#rcnYPAh8KBF)x~_(NZwpweRz`FP3t8UAU*p9HA*TK zrdjpFr&+yNW|L_4W~n@6m|kZ0`AZTn{ZrJ)n^CCN?t>2|mEn}WY8W&9GpKsRqvH*Z z3j7d<3g)-Hi6zF0*GMJVF~cPY}i_$mxmijZ>`mQc4fnhh`E84gF^K8bCqB^KO20neuKr9GjOy|5bEDv$m)2X z7x+Gx@I>nnPG*jyv%M5q8sd)0+Z`$W#4dEOT+2UnGl(5}=)^yeoQ|hs9KhxJ9%=z^ zfQt2OfkiPca2{(wNohChs6GRZmmY??4-zo#+zp(-JHRe|{0>(4sA9qPQW)>tgC;ZU z5guD(mVplX=T^hK8^ds7$qd{X`W!2b3c$ji8eK1pCYtNwHLkQ?sV!Wl5nc9{d(&1>zIWKubZ~oK) zRpOUv_ZNkbaWxAg$0iYYnU3#z?t;(+6=v6@LjGP0HCSXd5nqi6f}pWlpg5_Nu6b|F z-_xW)C4Q4+?lsSZ7axv8{IE}S(zpxo;{18AF})7!x3tmAm%1<#7A_bUZpQeoETgId ze!^M{2U_izJBofCT~vCu1N`605eN0DV0XEk{x$s^^gRs%m)>-A+Yk>{%8~fdOp>ru zeZj3~3#IREgMs6Z!TYgsI9xIqS9wZNUrwJ#_wAe5PwkE%CwmlEPRd8zM8n>MQvRZ2 z2XXauBQR;P=JlDzzyZ_8xTSqQEc+rtZ+@7EKd2N?SChdammkzweG<_)r%va~|n(#HOw#>kw>GLUxlA7`T zD66qA57&HMhHA&ZAmw-zZ!g>jac-ZmI`e5~+bJ?58GfY5kl<&* z*m291r+VZxCfpCiET=S#HmHXO-k&gc{bQ6^_zt6A(O8%}ipXW$1G(IKinX|n(#2|I zq4ZSf4}8LYeC-IHF|Dj#j|s%bS5T7{tC2~kk5K)K{c(PXCzh{X3wHuTK=z6x{UUEW zJP%N$C3jteaH%!yii8X}Yq%d9MVishwg>}v&%twPHspZzGdLst3I`W0ho?PC9nG(- z(%BDGG#$$OeDFH!G(!v6hD+!i>40iqOELVwL%5%L5wENeBJaP&;TWAw*fk)7(WhRr z+O=}@O!;qU-f*4GF-pKq@s*Gnbr?hEXkbs}b$EVTf)-tKkbPwm1|{0UWWQn>n!fpk zc8A2sqe->wC9Csr$yJseu}Y4Xp85&3&##2sPutnxkQD03z(+Rwb0Ho-s*YnGk7L~q zOooVYAD~wD9-4M2ZAlFZIGgSgM~>~ObHt^hU2LRO=6Qh z7;xP35=E1*!B+jd=q_^uJ1%Il)uaUDyU##P^F4lTQUc@}gi@QUKB2Sn6DlN76Kcl} z@R$6Y0!k&aWd2-r)+%TZ+;4C*-62Fqde5bLgU@5HMGbYLXEwaazk!aj z%}_P<6z^x(dZ1)vh_GNTzMc|+J=gPa-tsQI{O}knEqW0iT|0!&xM+UH&@y{`^k@k{W_1Xqao6%0Eb&&NCLe0<=cg}tf0 zAno!R`m3hk{$tTR>y?hMeZ@ISd3!J4?&VG}R~^JfRu-^7`UYS~5MJ~@#$FvgizV)K>0p9}rj^*KwoGkw1{AM=Y?*j0>^5E`|Um#r*K*^mrhuOtH;8Wfe{?+%= zB@x#-mVfa$|9$q>#4411;fn8re zv-2f6P`|SR3g$LK$Z}m0FVhUC{Ro&BOhv<7d#L%E2BD9;QDjFg+?J4~e=SlcC;1ZO z@<%K7#PBkV+;$5#nN7k*9aUI8-W_V{5SXoZ;El%TLWR8^2*2crJ*bf)(Xn_+)*p-C ze!;wtZD^pfm%7+E3tLkp=}l@Gus=YU>{=PlHQGPtecdZXGz>>UxmXk%Henfj+vU!T z2pq*^{TfH#&mGTVSTzjmjiq>#W zdOVw8vFJFI<^$=W*Xhk~RENM8|$pTiG>u-+%Ey2;_bh0Un0 zatJNoe5I%yF?!{o7rR@t4@a+4Bcnd|K#jF7G2fa5p~H{kBllOgx6RI>Z0BFc-4i-+ zqf0p)H7TZ!oeJa2RHwpD<}SA6sew0JE0{C2D2<~f@GSQ*+_X)E{%RR=`(Yq%Gl+!P zNxMvOzPKxI$qYu59}VpZu8o(U!eEH6z*QSORbxt0K=O;L0{i^ z=-%0j;ny!hK&Untrt#tDr#N0yat0D!6;281#)c&^FlSRalpWSUd#8`^u-=IDP8S95 zn1k3lZw90-7iO234N&FMo~)bJcf6~M{#9wq1bC&FMAxPNMEZvVGn`UnE*Zx1+cQ)d z_c>~eTv{CYc>NZ++?znRN}nsNE!jeg@NV;KU)STAXk~JBQ6?)|)W+uXG#Pqx2OfIx z2JZB!(%&Y(hXrjC^d7rXI^wGYY0NT#voqh*#+}#AorBuo=r^QS=ojN!eQUgMItRUW z)X;8krZYTEe;g&Hz(}4;X0w;6;oIO~cy;y})JKde8nW63`}*gCjP4ikd`;+6ZOs_9 zMu}cflTB4tucn@O7O`_1Md97BbXZw?1Q!fGz~VV4QLF4DHTM2p*5cX>?`q73 z+i?aYV7&{Ro*av1KV&eY?FlYv$%MSk<|MR9hIU@J4_@62h4pJ)VW<8X*dqBDLwcp@ zyV}OA`>iW5!Pxo{IcrCXtI_5kiT-2ggwo>F>oO0>e`2JE+K#Qc0fsc-V+^u^84 ztp1GpIYeDaiRE0&WjH;6{%;4$COSg|(@; zAnY>A~#ketC`&W|YU4oai;-PHui$#Ze4 zjxHQ+IK&H_S;8|>nSz6pKJwHhvOq`68$7-5!q=X|$P<=gL*@ySFZHst)(kz~lN zPJaZe-p-!wLIN>aQHCn7>ZT?tKBmnJKjE6)yE#_v4q15V3ePOZk29{=36FPA$NI82 zSW#CBwYiVcb6q^WR}{7|_v#AlSg(g@sUb(dd$a?7?n}UBp_g$`{Ru53)eN!jLWC!z!rZ=D z0`e+Da3#H$4oi+>M=yShtD5o((A|fA8W?!T3UhuBht}tgaaM7&s*ALtJAN3XdPSp$Mg}_4ENs`(0gW%Q zc*JTtp~m~Ls;`6D$@L$26Y|7~>fQNp|I72-eakTA?smmVTvw z0eRMYY8h!|#>8(J0r4w}PpbFU%I~}e2!$5t}Bb@y6DAwhtQ30;~Ff`Q^9?Lv~ z)kp0hT(IxivgHaM?Kp!H;~v0gQ)6OYwVn!>^rc!w@8ElKlk%1y3-7ark*jMS;aYiJ zc1D2`cG(S48~;zA`)wK0V9HhhLo11;D+I}iHm7hrU8K3ESbz~xWB;LA)6N=$n* z4D{}#O70$k&zm3M}=RrzcKF;yG%im%igq@TO>8=$cIwsHX+pRhrv1cN7 z%uFOA4vP?cPQO1s2*MSy7 zpLy~&<&bQ3pAGI&gbmtH*_l6kVdTo`uuJ6@@H=ElL~B^#ky8%ev4XIx}FvR#C%R$aE2hkLW@MzE(^IXL=#MJK%>3p8da^E% z66M=OYtB>JaN-tt<(&q1qOxJwIw`9BO)?pyEU=>_MO@odPaAeBLA9Pd$p#CuZDE;t z@ZEg&rIb3Lg$LMK`Qz5cXu42sISvT+r6R`OrN8Rf5SL}md^?{j(C#pY{+T#~d1d_r zE(}O8pISKEe~TSUnslPI)z-G>*Or3sbQ2d5QQ zQu2}W@kW*_blnrDb+mG!L;n%#O@7QCES!m~s|vbo%f-MYFR3$M&tc7%6QK55f~v5U zA*uZmB;`a2YjSM~EAQKkrkk7bxOFUCP8*2>-5-(N6ai0Oh5=pHDA+@d2lJOHVDjr1 zZhV^#_qvlHq2>UhO(agtT!^#WreIpcMR49S8r_PDU~ru!Hpn&Mndj{|f3rVE+Z@EG zVsk1Y{ulgg8pWTbW66J;l1?oj{soxn6kAjD4!2|=fPo6O+;^rv`NhMGFA8MM{CI3% zVv2PaqcD0w1YbYx3GU(P5#8iSd^u3XH#N)$iO0owV0IKM7py|3eMm&bf=alko&j4k zros6~a@gh}Mh1h=vDSx+;KfE!VpL*^PYW`rl;PGGz@9>4Z-g$5sr(vJ$L8BLAY(rf zI*yn@!>b^er*i@&HOqis+Yae!i}=kV38=bsH)y5216pqeEK42@b3F!OL)QmbzTO2# zKC^-aAL3z=nIU}7ZKE7b#!`u@;as=uc?>^Mfcq`)gPV^CS>)3LKGA{n?wwims3r%z z@+gT{=y(P~)8`dcOSX|wlMHCiW|v@p`3L(`DjK7F4`H-}G&dCbK;TbRLu%J}dUOop zH2q9|rTAV_dZ-+9YNK!ge-NKr8lYRf2-$e31;+i@L1OxI`O{p-pz^szq{-hEbblN~ zNu+t1l?=MBW^vE)T4*TG!RpMNXhx7k)ZD^_P6I_HPZCk>LMJ3#bR~BpMTp`1#guz> zD}*>KhF&{)67Q0T?Fv;?VUPrEBRGpaOV-25ED9FKMW8}LDeG%>lzJ+E3ijzFv-^kg zQQbtE&W;V?o2ukO-!UQj@lZMnP1uSP_6kA3!y1gOxqzztv#f*PNw6Q3reD^H(uuNy zy=~q1?Ba?kXw=AOt?eIDx0<9d@^v32dv7clPZK2{WU?S?m@Z{*S&PT)Ujm0B^wZI; zz}6Mw^F^<~&h{f#nv0NH!#U`*^#NPc_YFAzUr^KZ5FH1kDBsKF7vwA48EwKdM|zM)@bBasHNY463_G?b+HT zSUZ?0w&oey@-O3rq#^KX^TutzB0z++@()*?fe2MaGHJtE)Nvb6a_R{- z?C-&}vG;D9*cai#(Uq(Yp2y-ZKCvq13%&12w}8b^BIyQ<>`>X4`B7CnyO#Al@jb2QPg-@>Zi2=-5K4C zS!D;Q`w_iVZT%7GYP*M`-|euDNyYt|hv9MiG3t_WBsQr@5S9rr%jE)XGMIEV8pbxbkfyo!&;j;YG(4g=h4J3MD<&Idi7LG^JY&B}Z z;v0~R3S{C!A($~y9h$wHAWf?q4J^a>vU1n4uJ<~|MVA62dmQhjHDSZHM5tW6kX`0} z0d?QiQ&yg9_~l(axbuP{F$??(DqpR@X`2LnXnQ@ih3mtUk#1mCkcuOZm*8=aeXz_< zgs#(lj<2@(bDKm@Vnfs@HoYMRN|{Ua+E8myEIq;)Kha?hcwfPg!85e^vPSy+lFMYI z{1onvJx8zqH~~M4zoMg5-ovGKDf;LSTU1eT#_sA~e)e?*rh#gqwsb87*ThwHp=2@E zTsRDe-rb?k3(h~ZMZ?(B!zCHVvF3RCc@&O)ti&V@c0-4uFv*WlqEASuG5O{jnAzJW z(#Frt7|w&m?4IZB#P;=cm-jQUy`f&THB$rg^vfYe_8RPZBh6e~*^dQdFT>tdBJA0& zGk8W@3^I$`(9Ulk7|eKxHSdIZ6V4k^mcrun_AO=*7W*BeXH5kW`UF*Y=q(jy;tQ%X z&w-L=5>`Lc0vAg|+~)fpcb$5K_e*S{47(uX>?OSB(1K$e1lwbMR(R~RC8!oPqSr1L zoa$SQ9a857XWU1rCDqR$xVjsRdc;VEjT<#*=>R5ePT-&Ld4j7}CWB{kKk5qhI9j#% z7;s9AZnS6sgVZTtKFk8vZhMDrqK_cmz#dI>tJ&;e8x%@Ag$)vyAmZUDvSND-nmvxj ztGeqjP7r@0yzwoiX1NincRS$8as^Tz(Fc7wBBVrS7?o>bgn6R_A!nr~yj=W(s=l`# zuGAF5d!yGd;+-PB?BZo8vMQ!T@9crf<-4g37xm%u5XB~x`k}eNKTDml9(LE918XrF zZwZG|v3^UzHX$BXm{nlO)-6;3>_sgTQ?`1|K~%p!44j2evcug|pxjyt?p~Ay_bO?& z!C4e`*>=I*HxtRs+yRKtGsUK4#Bt4qK+TmU7jNl+n7jc=H#~wryuV@OK?$7eqXHjv z@4%+5wcxmUkT2t{NM0Y8q1mPi?9T0`T$Z}w>cKPA$~EscL18?W? z{5dYKQPV3LM(h`*NA6c7CtmmC{q%U0j1S}HmkDANwBF(A*e*D9Hh>ACuil=HZ=)FUdDxO?ZJ&e8|$ zC&%GT$Et2>cldC2*zS3FYTaEhmJGpM@o;+Ky2H@yU_!NyN~RAgy28zTIkfP)Lr;Ht z6BNP%S(%P$kh5Zt4)$|k-oHKpCoX6+(~Jc1LIxHfHT);6yz+uQYd4~(a$7Jpq$5w? zJba7)4TI^LTP?8Smnxc;$&kWj4b>+cKzx-r@mNQod3!uAsBePTrUu}fF2w}6%EOn-9aP*% zb0#{*4n9BVrR?H0$%lS5W_$24-pJFr*n4<3HT&*EtXCcc+1ujGz`SYb=;Y7lju*p2 zQ>W3#1o09(-s*wvv}E(6DQ^o#?^S0c=jX%n4W{NDNt4*(T0>^5=FNY_FB<9X@%UfF zFB<><#4nC0vf%a`%9G7;H;}q^lnq=n49)L}(wt!38D%WX9UPGZ9RSe(LqT&2rB+{WUtiw~hjYzv&Yo<`m45y6G&!kqTJ_c+ne5IiKZ*_MJ1 zaz;D={PK=dbq+%4|Eq=H+-<~BWm+tJONE34vcL;|k%W~&NTHzegVH|U26?%3{l3$t=xIH!3;P{3fiucqX z_LfYgq_(}M0}`E7PR7fP!$iR&9mqwmRJB(-lzP(gNnKDa@Vxsobi}EPkK% z35plG9M_HCkCvgoAof8Ip=VBm>%*;Zu4^=Ym+l}AuSMyTJL}mQTB3BT@Htj#EsuM8 zOqJ?c)CP?^mcWx)THJupHT>x)#;JK7qYj6ygc{ihG}?R{V!E`cvFSqO+c70hewe^s zBTTt*;Wxmx&yZX1`2hwcg$R2_m6Nv6g3GI`*sfDYz6^+$9n;>_$#w}2V*>67L!tj@Z6LD2;$fS&VdBKo7=6DNh=iI@zBt_bPWH5fud5EXZ z@u5>ml*q8MyhEY2+~l%&nn$HB&z6SxTFK)gRroZde)BO7`JWuly_b){ozHUFsrmQWMEhLqj4DN5+FN*XT`)f0w_?;mHSW8e4X)m7 zz*RCSn9vZ72j!bd0*6`4}j%;q6_&zGVi9!t@}!eNx{OqO?PZZE0%UIE)If54Ld z(VWAoPS|ByObzxXGk5g#xU-Yu&_6?jcxTlK*7_~1?lnc?RUysks2>5La#7-GxDv~{ z+R29t3efy50S4Tr;?tS-EN_7p_haQmn3eJY{IUTxHbjn2ca zOA+{EULu%zwG%tT7w|K03>*@%#OhV);6&?i)$+U8N~b2vB9 z>y19W<)D~1fc=Rh;EhxiIFI>)I#JqO)b^<`>&rwgy@f@)+YGmILr~PDdImAtnWsib7CdVD|3^M9zmBTac-S$9)@aZBc1gUb_a^m4c^KSxqUTQ z2CH*VBC>J0D~}Va>W7?fBHa7iQLs?s8SkNi8fO>r1@%puagNjns?DMRp1)1sMITgY3etaUw0%oD2Aa=aE>=jz+*TA!V+FXII7rQ}|!_wzRP_JhO zcg@P^U;bCuu7G3Jg8Z@H_5Z>DGWp;5U#k+=a_YIkT=8lbZsLPuoKXBaZhqtv?n%N( zu3o{EGn*REZ3uVge*1;{4Sz=K3UV`k*Z-cEqLAi)=4bpnX=>ga_5UtG!${`0cEZ0e|C!VG_jD85(F56(UNigXYmJLqdrVDH$V0hO^h+lnjYP z0}YZg7L_s-={x!C$AmuyAHZ8a&hu;(%SE_$9$;_-?`0U!_EwSCp)%n1#JucgQ zT=#nK^V)t;SArv`uD)56hw|oK>E!0h5&8=vVZLXdlh3-pPD*fuH}mtZ(dLM37UUgw z>_5N}wQ}*{h}l^2S?O8{1aZWz1g!XjI1*>ve>0Kv;YitXq&NS*)!%fScR6`;WZZe* zcwToC$y76?`~~wj8B@-;VBo+|I;5Bo*P6zwont zIBK?>Isc}i_a8Lo{vko1Gml5(8@~@n{kI4SD;|ycf6-X*mlzEn&O%#`=D%s^{Y69T z4O-bCLF_mjrJ1t z&AhXG9HSE) z1K!SBYpq1ZLFTA~G+zssy|u-KwvwC7xY-Yr z4xMM12L6dmkKzo5Q5>d|YJQOwP(!~Ybr^MODifz0N~-UWVh?tN(CNa>%{nTgL{Hrwko?|kjC~3{6GZV>N zzXeS1_leB#@~O=2180a;{vGt5gduuIff2hsX9l_Df)Hc$U2r_O$i4+S>{z;-bji}8V+WGxWP!Pig+n&&Kiiaj zQ|T2c9HPdg4Uf?d6Xn@D0?N$p3)<{#&Rk~a{Jr$4p80gdL4EezgiyM8>tgmt^CgVb z!R54=^eftGDZvh|G6CnCw(LM-DQ2;05A8bP2HT}Egl(rkgX#ViiI$6w(<%$9Xqo76 zcG$vf`uxZg=C^{$Fmsu6yl4A&|DP1B|EGd=%$I8aR|WquTm9F6%xdfC*DKFbYNrDU zU6XS1{k6+*>{S`vxh{)dwpN?$GA^biMAx$HtU}4tYZOWKj##qNw-~ISO0eCe_?Xkq zA-KNZjlEbwlWmiApI&%EmQ=W~mHkbol%7?Zj2qX~lEb5B?65P|B>zo@aF(;9H|&YW zn>KsM)kg%Frz5l2*(G{xOW8_#7BP<<`f)z{@~{>Ao?8Oyukt6~#`)88zl*Y&WlHRJ zw}<4B3$|o>>SE?c+hek`yOkb!VaND*@sYpB&0Y2EwQAl&_q+d3<3{{BZo1}6m;67E z+kcFt#lvJ`=d%IsirJ=k+^-fX(<}_#BTj$n>xBb8H>u;*OUa~UQJS@S5j?IUP;X-_ zc0Jkz3xr>i+kC@O(Ow)1eP+@{Z>-=)-DB{YzmRx%uN5b(_2kBezsB%W67&n#im7$Ya^c3?Zg~|gVc(Id8pzp4vKohFy^`*dumHD@+(p^HkrU#Ic36ZYdqH> z_B7l%_7I;HHsZ{A=Lj>Q$9TzBhQ^)waJHis6lPq)z$0<2I-zuoz%o#4O^-#2kbdt1SuJ*WW@TFOsHD~#uZx;(`%*KUoA!H!wvdiCM(3oE6+()8EZ6{pG5ft ziP92@x5+7vQlxP5XYyU!d6F_EoMv)$8=!x15xJyW z3AMCuL6Gz{=t;@IP?vOAedR0h=*}S3{O&2V*S|%B#tw)b_cSs{=c9EN$Kd+rNyw?q z!?wc(cxCt%#xwS)CT$FSClz6f!39F~{4lyXR)IrY2F_CO=8fwB5v98Zq}tD6T1h5G z66bMeTNWyAxC}0ZMWuO*8i{*0cDQs%f?S@n0ScOC(*8E_Sg)~!zM82*Q?ZY6w}vKN z|KvH^PObwwrW~}SWa%}jN_0Z@XSlT4iIq1=h_-8ghRa>Q!G-ccd?G1DuYV^&cbI0u zl4Tbu{Ni4YH(|)@FW%O@}69 zvB)9F(2$^Atn;|-Pv3#{CULsKdOJMucBPz7U4iG0Sy1^d8i!WyMh7ohng_=B#uV(! zt-#K%Z{R{zA=g5deeHY``ASug7An^)+g7mxkDneR-ye7f6Eupj+L4boT@(SI;3hd| z=rEJ)BtjnW{t3y|a_oA=Bj^|;PUk+I$M)G#M%wN3p)#iU;>ZqBy8m4VdCx%(9L4zA z{yw`%@vd8#{ez#qLtqLyzU@1?N8vVbvuEO)v|+Nb^1IPOOGUOTNU;+ZKZeG70k-O9 zVYbXwZAuRAlF~yG?9TKjbRsNazi68T4^p$37uQ~)(A;w3;_wu*b^mGD$$3K7`Y5o^ zitK_P7OG`^+Ct>bP-C{fS0!Bav!KiNi_($iBILwUSlT17PoPta>L?@xe{&gV16C>!}~4vFPO+amO6(_zH=C??UdOe)32a> ze=m9ILIIrJ+=3pY7~AD_I{Yk{#7^oJVhc#@0YB%*l1#iY})F53hH%>(LP1l5cxr#z7ZFT zTdhyPXw^el?I=KB6ceSbTWX-gE_iVIcA|7Vo0zuDoL(iA22FiM zII*{$(B*pumtGeTQIW+MR~HH)HP2a2O_!;80vd4L^D4Y+34^0{e$Y1OB6a#6i9d_A zn7AdujGp8+S}ouzyW&$XoRq%{79SE|+KYQ^sV~;}@niutviUPL>B&P#+`Nc>pj%=h z+oX=Is|L`IUyyN1J_ZX*Rq^rGOm^*rrObly`54$Rgr4ob#z#&sWzJ`}fT&9uyS@Ge z^l>za!mZ)-w0YqSD>a1451WNW7xmDYFM{d&R!3a-l4A=kyh&~#t++~~OX(|qg6#e@ zE;<`5VR~O5MiWYoY+3t)xNR6o7_E~gBh3b3rIs}DFd^Uf8Q($jmUP#dhsp*dt&-{i4A71cE&71x{!Cp@%)Ow#Z#Z>>8A8T*5A zH9NXYepwZq*VV$!tH<&56b9w>B-sLPtz_LJDKdWgjIu)RR-%i47W<1aAKjZTjCG%7 z$=2;<=&{?1TwWN+ENtW>e`-sUw+~CQZ%h)QpPvW=GPRma4!l7srXwymIv?AHBtK&hI+(8!A$M-EgoZXX9DNszM~L%KDk_A(4&H3bFsT0n5iyf<9Zb7MGeSz}VnKe5E=Yt*`gtw=`X#J^~~<=-{1le{AWwK~1vR zPUJuRYMlJ&3{3k_fuA*eSt2o$>CumTo z&bLsrE*Zo2iQ(wAv=8$4KL@wlXN?^QRTMRf1L<@j%(6|PjHYD~6NBHv>`M(;dC-)& zkt9T}t^bCj{h!DSqI<~!$#Kk)nOr6&wiPDlDX}G!0h2;4Ko1@f26N0{s!9dc(N|Dn+(c_$=^<9>k`-HKbPEE%Lg~K6G2~9PU>iphC~bkcG$j0d*_M+q=I( zud@`fdYu$oxS$@&zuYFzS9em%@&cryM+zZrQ%@NqRZUOY#U&Koim+_^19Eh9x zgT?Ld*wVWneC`I|yKOZvWX^!SxFjt(WgRq;Yru1p5GnIAy!bS44i5B=MztZN#+@H= z8%hR&aUvj2j1LEVeJF4Cb}YH~fK?X9MbjZ2*iv5)y2o5mw4@d9FHgqQj?Hq1%f|z+QgPY=Bh*TI1r-WnbmEOJs_=9dp)*q&9S2*mS8g4s zuC#}o-6U~w%W9AhZN=G*88ABGJUaMoMPIGksK!_mxsux`?d)6VzCQ!}nm%B!#d`ET zl0=y+3DJf5PYEaK0T_I{8Fe~D=pXs{@YN@qd!aHCpEJJTx#a*DG(}>r2ZyC2lZK9` zi}32yPMj+76V9!uB~~xHPaL$0;f~t}gJqNiDRU*1GQTHFQ~t_mW;%-BDoY8Y!y=_s z-K7{aFbu1jx8Q6}82Zc&X4y#c(YJ|!!TJA4l9hJ_26^Vo97GZink!}(rhT_{D31TtMIkkOH8P^z!f$7 zh7X4NU|#)C)L$C_=VUvf&@mKN+7yGOd7%yg5-~YaPUYV@HhR!sXgr_)j~y}82=u_OuiE{(te?I)@lfvUx5wzDTKoIXyV@P z`&8q;b}$=D$C&bNkPnt3KPt%4g3X(V&!R1$T%!T2Cf~*ry-hHFei~f$HOBlK{kV5& z0F`Y&0%B{%@yLSp9ginu3;a=FZa83S8=ltWqxRpt zN(JvLM&tX^q}<0ng%CCnM5ayC692d>Kk zIqe~;yUr-hwSA74?gWwNg`d*%$wss?>%zA)J4kQ$nb4$=$I`U9Md}xqlV|q6#$LMy zV*5rj=qV^Cy?OI)e9Q+h8`?zLq-Vg$?ptKl0%_D7sU+2|e#G_jkAaf=QBu-Lm`wiq z1|GzmAydf(@QHsCxon*cIct=UJWzX=+~bo;W_4E6@wqKz(OW@!wt+LFmZC+-ms`WQ zeh(pk^EFP4>wzBG4oYS4r?EnBFls1Nm7Wiu3&&1O!`wF((DKBWd-?fp+|=cQ3nqO9 z3G-2EzwjXFsPp{w7pw6n>jm5ve+mP)qT$Dbi|{t@Bytla@rq&~Dww9gj5&#zVR{-i zrYNJ6fHRTi+J&Xe5YZqiPFLkyV|^VTeO88|7WMJdcZjWA;Q|$E*dPf^WH;e{&nF;T z9M1Et?m|+2JQ~jWg!X=QFt^JM*BFQs>-G;58U`kK=!q<`a=R$KQ(1yM=oODyS~aNg zvkBLR6yc3ULKq$wg(e=_Sg|r0Y*__VyFdh_q`JTgjwDUKdw^#8g5)^uMC3G%;itDT zEETT`Xbej&)mR^mJEmqp_Lvl@^!+L7ny;in)OC?>?hW`bJLj}UMgv*crO8Eq~z$_lPQ=VwjEB&MMACZGD!I~ zMu@Jl01N$cnCZ5PoHww5UG-9&oxLU#uRU2(wo{=Mqq<2p&ItnP(p*+@z(d$mFpjP! zP2~7>Kj!XOAr{O&g^5zL*@tXD6G|hdAk21Tm&vKKFUKr`hs|BM{Ywda?q9^t2p(X` zL@BTxhKI<=dJpPTo)Eh#s}=Nr-6z8nKVZq35NLK0WUDBA2K8ryr1?@6ww>hzGdAH`HHEY4+f@L*VU zJ{Mb`*5cEh$@n%(jO;3nM6D?~n7m{b;c4neJ?Zjgk2^Y#KitVbcqq9XK~Ak+kPYPq*01?Til7_!^N;~ zqdoQWyS?#|70)odqz$a@$&d?wnnK~#8r+my10{v}xHrQKG%af>lliiA^oL6B@{vKP z2uVR@>1|LZZUBqrTfizKnffGp8=tpC0kJ0{p!piXgDlKNAaXcSc za5#dvcI*rxbe(`QV-8-eJIuWkq=WW1-s6i`{3PkBh}*JOQ!y1hKk#z|rhmRpjMeLM zt6S}1O#22*VAUfPz8kV$F&H~~3(`_#>B^K4bXVGeYczAPw|orpqAudMH$Mr|s~@MF zk|jePU58hnB2dEcKDHE&;ucCC=9*GmQEwKM5{*=dR2(;g-cC)ZIEt|)(zM{qB+OCk zB-;EWX^pCHM8Y{qEaQ&jv8rhpc`XX-lP=+V^Dr36=s@!8b>7+`1Q+%C6JGL0*!X!W z)vbnT7r@4j#*Zj9TbkS}SPter{rJVe7bDh-lD8#=>5wO(sByao+e;?m^m*fWwU0$j z>iGbs_rJoS&)-n3m>-Vc$t~qS%fjjuCtRE^KnIjeV2vC+g3*35q-${(k((t-CT{OT z@AN97=f!(!L$mF8|pAT-T|g>5vHfJzM|K=XsWIIJ$2`p z1R2VI8qE_ksE+W(kTN_Ef^_avC60Z>J=0XQz2XSV51T@o<9ABUMw-lgng*1I8ezOR z7ZRVfqnXK35K)VwHp$E43a{0`$zkBN<$c_$!$)=>KL>`J58;frgHXB4A8d=o>Fb$a zFuCMDUSBXmeEE8g`aJa|e!g=RCS@Y5`L-CvrFTNr25I{Bs0{AQC7z-`Cu}ek6gw3u9>ah z&~tJeA?z!M8`np{lP7Ap)kBaT^-`xyu4lvW$2RCNV?f&cE1qb%2>s6^F?eh@P6_14 zxSoYz^+lAf&4|SL`U)^H)sOOX^hW;D8)%$bf)9_aLf^ud)QtQk$Xr2uu5%L)OET1A zk%w5cMu46g7782he#W(rZ&0Ok3SfvcLToIY%q?~)#+`#1Xf*jMe1Fh^zEX>DqihM( zE!l{l%3@(m_#iy@c!}9^Ebj8MG&JnsLd<8LttO=6sAnoQq$^F^(PfbS{RUiq+D|p} zcf!NgD6H1yDXrHNzuTo?tFShe@O^-)Q)IJ7kb~=6$NJW6-+jA1c$*? zkZwGQ+fsFjGK)IwNYcgY{n@zd<4dZ&u7T>%kLA|Q6`+?TNzzk~3e!4PSCQzDDs}7W zg49DQ6zO#l%&I-8fbUcB@xj|D`1Ayvymt#PHl%|1WqvwoM=n8$iO_bw8wste{Ny#4 zXRHyW8cg@UPNi3e64BnWbk8Xvva3iO4^Fzm<#fsus>(4K^>q;D)F+|W9$yf%Urk-p zS1}C7ME|AJnHd zSCwPl@i55t*Z{rZ+hA|hDa`+p2ac_EsQW~O{?+F}iSG&mczhkd=MCebiec(dU>;mb zyALOVB}o4SG4f59I642`W&pT=`lah3pd=iW*RDXPyl{N({TV-{`4C5X3sC2QDA^)( z3kN5!L7C7CtZTC}KySMWJutDv*zHOTOq+NHocxUtY=(%Af-1C;%0QVzABgtwD{z++ zM!XNvhfn9MVa99~u41h`?PnoH_H7#khZH$<(1^$8%c|6yg;i9dk}z#&m_}_^7zeZN z2%<${9*&14L-I2nqC_PNubL0xn;Rb}+q*L4*pX;zyT&ri8T|oso+#mFy-v_Qe+P%& z(#Y+Vfz<1RxZYa`918?UcRUPpn;W?TJpyRo*o_EBof)p+vWXvC=Z#bMd<-drnK8I>rW~37q7WWs zO3>35t->_6BrWmG3~jP~A<2=08&~nsTV4W2)~Msp$GP}YQi6Q^Y7JT^??FqpDeJ&p zLlDsrqlP${uvVXdpbZ2q)FeggoIVJ<2ERkROFYclkO^PU=Ap+L4i-{2DB7D18zZj+ zatBfEiv|S?O0b{bl$L6UhU#SlaF*Hx@jEne`fxATw{Qgnov@}v1%|O?v<{mTq%b!$ z9pyegAnuj);m}u4R6bS%N4Bm5UbGOEw;ZE7a_2yo<}e<2dr3Ui&xFXEnV2^z5mR%N z>D?ZCuus;LDq&J_&cI=ad-o7Tq~&OB-uvI7@;Zvj9)ct761;g*2_MQdgNu2k@!qa1 zc#*yamfaixEy1hCrw%7j_OXvBHT^s&)apT9=PsP(ei4QaT*WM($0&DFA4M%4@n>=) z+Lq0vho@CidBiR1&7)>0yXB9$r8BUsJ_p zw~I6w3ugoK@e?QJrISH^qX=XnTKkG?|X^kD2V+)AB)^_6<6J{8hFRM1vD{d}15 zgIIW`4hj>bpl!V}>Q2qYUCz1Ckf)08TKe&ddk}u#W=)3_77^~JMIf9IqUrE@I8ob9 zi08`ETDO83r%XlCVjvia1r)Qc>p8d|?Lzl?HTcv-mF_S!Ch9%T;MgY-vV595zI;6! zyUv!NrSd}Jm`yjecouK{dQpN7Kcz@(^DEHzK8n*ZXZUD8%enM1`U5Vxk;L;m1nB)k zL#6i(Zo`ugT=={u0$-eVhI{efaj?3T(5mLm1=~O2hNg|wvf^fljcwsh(O5<#3m?L< zWq#DmIBU4)lm=R5T&yXr#r66Y7$>U$zvOwgtKmy*xK{&8-}y*gAwc@oTM!ggq38N+ zrQ9XjVXf*Mx-~PIetKV#-jE|lWw#2UYWD|>9p?FZo6eF+hBxsV@d#L_TH#yHbX+kd z8RZj$i1mlvaG7QUB|1|R)h>%b>1Z@opYVe&!zdhStEC)%)li|4ZWvnIi>EFG5kJx# zKxDrPcTZm`JoOtQ7|mpQgNi3TL6aY3eZ^p#wk{2y9iaAx896onIqYXzaq_q-oE4vq zMTx!GFro+3}ns`X5HW4ibmt*_|Pqzc+vBads0?}>|EgvE5zmD znB)!6Xz0d*;a|Kx=xnUv*)of$#-$>A@sy`D_WlZirkYRSxseYdZ5N~E^I{C{&IgUm zOi(+S3_pKN;nN4aH{W75IFfAcSm{Q;piV=v~D^T{c|a9iKu{2>+a&9gcwv` zLW=eJ4V38Gg5_u*9GtO>TJhvEx<_w=Z1obbIuwD&RF7iwd=YwHcPwOF6+`FXOOW&S z9tNoKleareU{o&vmfq9EZ~Y6vw3PS0x_=jQw-16;vm|UU9)?=4`JnOsG6u*7;3ZIi z_i38&aL60yGewZi$Ds_hy(rgvIh3=?WDHn(3%VX!qOHiAI_Gtw%66B7$G zZ*B{=;wKW!J`*RSk6^on1Z{7q0^c9+hsOD>*dX1AIiGCMJEVfrn@$?w5AQgHeSL;rJD$? z?(~S|ROVf8= zD#;p=ZnC%ICmcIDwajh*Mq*vgIsA=!aeY*gU6!)Hhy^_Z0-#LwDbkgzGkt^|(zQzbnjUfANDLlL_n} z-fg5(W+&}rwwTTOI!LvMgflToUf><~4X(Or(5Gki5!)8tr+QMB(RFi#$n1F&>4TTb zAgb*-ejnF?yDPRiWQg740@(!^)yp+`SrHkSxsuduk@V zZ(#+RR+Yj^%MzB&UR^q^a{|mJc0=ddAe^1}1E#yrU@6S_h^9p*bkO@&Xc*`t470Dn zEkj9qUeY-Tk23*Dp5Ld~*p2Hx-lR}30oz%5AY(EeKMpt&(Xt8LQtSu$&&!CUf;z&S z7d!VHoWV$4PG$~RNHcf0P;6zDcwF=J1tp>}8LtPIvX%Bd#-%f4=>hU9%89(-jy}() zL%q2s=ElBQ;M{=pT79M<@gcSAYy@5@jAx5WpJUEZS-f@OSNyfS7>ai8U~0aka?zoL zok%aio&5;wIp(y@g?7fdD2<6NPKKMZ@%VN|EOX?gBwgod#J;=WAlWoti^`%G>BcfX z_AyUGO6j#OleuOG_2B0)OgMKEE=3nnp0jQs#MnuI0=9XsG`aFBG?9_}eD5mp{c_$IZel zL4Nv*!B@P!<{~99xeYEZ=f!NYTu|G87OwQ(j;)~=;Z(aINy+pTYhIX7NE}P1lH9%$e;X8hMtCN)8ypfu>0qLRs(yQy+w(S%nBlk#+GBoD&9VJ3 z>xvA$<|EI?c7Mq=IXZ!M4ihD7#>ye(vJ}0jeimIhsf$>@Oqljuu?b!M6X8eBWcqW{ z7_p~t7i{6JId-_KLXh<(80wfymq*7#{SISjGbyB&pAE;3Y0s$~%N_VT4{t=#?x5T} zKEB`mf6BxANB*MT|0aLY1ukQ{{nnn z-ArtGOp?b&G$@tjOK73vo!~dFg3CVg;v7z*WbUFZ>>v7Kbmlz`rZKD^5<1oC-{V#r z*jVwu$Y0d||H)qz&eSJ-^MOkIpvq{w-^XW?tKquza%R?1U1oL3M-(VnUSMhc^)Ot^(f_Kf+%F-)M`9CB*&m84$wSz}Q3uQnLG2 z<3>wmN+3s&9QHd30gHu^+?Yw6csL!NzKBDwk^n63`3n1oyNNM{D!jPhEM!$_fa}NW zc+%w-@y+BJYy0bPwCe7H3r*|rK}-+KD^_BP#w=h#cr>gmD~7XAuYrI^D=Sa#3ZbU2 z&Di-xEK6 zvMpAxlW6K;0R;RCIArKqifV2I3$Zk?5kMfscU7i`ET$%t5dbc6{+#Kd`t}HWBcMI&| zLdYb=XnMl%6sBI+fDn?acndJ>I+Bit7`hJ1O$#UeU z5GO{*eo~31%T35nS`JZyO_YF7DP$iLq|*G|ISh&0=P?`cme3mOUOC2qTRY&(R9q)0uZl6HxWTJp8CG z$E*u=Kt(4__`K~f=3IQmiaGCr$A(3ilkY01PZ4QED*t>YMy!ZR3gpEzNIp_BD;djJ z`@t<#9elL!fyrfUa6Uv3J-!ZjR5ApO>&3}wN?WPvlsjJk`2&Tdt5GaSpSJP%MI`Hg z!&OuIAeugd83s0}{K9}a?lA>>t-av6atw@}6{ov7B$>148}7WL#u$u^V$hv(6jE1a zPB2DHSadiQy(WwteRGy3-|8`}rrFq$>xo}(NHKMz5Aps&&C*L#F2T>#2>j@3haS6> z8P~x+7GLB9uwQS&NdGE@s>g|7r0oyOd2!{_!;UB%{|=|z;Ridm8hniGBeFDZ0=5qF z@_T78wv@)jErPW9vNF7?d=7<0Qi)CrU+Ut(W_X^&<=(CB#|qgbc>2hY*?P4S>==E> z9$ybOJ*V)bfDqYnI~E#UXEKzYBt5}&GH(ynfGM9ljnO(J0k4L`$-LZ1`k?J}=JuKw zu(WVBkmah(;u$hX86YrsrOBDK_lzTbg>cg~K_+f@dMUqa0X00|mhtW4;;sQ*e7kgz zVj9|sqa&9n|N9;2>@Q3Y_?zKEm77$Ooe<5ET8xWdiIQk^5ZZ-R;ks=N+6_gakH#gU z#;$ za8CJStf(a!d3A!39JQl-S4WU8KhDyRTx1ySn^Vv|4*_CU9u1%^x;h7CFr zgnq0qrLyH0J-^ovceR9;{GhcM!?1Lia$SgiCp`?k3TG)TRv~iL2H=!;II%vg5K`xk zqLS$lKJYOHtMPZ#!-H4h@$(AI+#T=T*hz~*y9wpGvu-j z;dHc*A|sIboEH}#$JI-8m@nbSz~-zNxij1ftOCTzyp?S*|K|k8AuC3q4*D|JI zNEdD%-HQFDGG6Oc5VLnRJL;RW6rJ@`%&M2Ih7`esjuD6JA0*y2mQo2dqdyCuks z>)r5X0>OMzcZM6O2~>T{Os1sRm^p1R4%N27q?|(}9il#)sT8b)z!iMto5)Gb)+#Y> zR$?1WG?gXQo136|%209VS4n1|_#P&nJYA|DZqDo%$OY?zKVWjUIQjib916G{gQB(J zm?MyZA^n|jPmPyF7#J7G=vUeI=&!7QIH3B;CBsK_y4H2c}i z)b*Mu*&R%tU`5exyjqUZoHW=YC`S8xs4zD-^nzDcC`Nd^L&KcSgvhb}^^rnz_m zFF&*f71CBPOY&QAfo}>Zd5vO;Q#1eYXe)|zCtuOjF@ao5Y_x}g~Yw`ca|B|>b&1kQ`#SHM>XGX6bW>!?hG9yB#8P&<* z%mn8_x?k9zF&fDIS6$0ufp44Dd9@k8`+v_%mT$^`)@S^?Xv%!)r2no!Lr>!O9Y4P8 zwt-g-#rM0fwc`JM_|KZYzn4qN{r=#O_Rk8xf1>|hizD*~lHq;J-_eV-|B3y3J<6Zh z6kg5YA6T7#V*l<#|A}oD{s&g~pV+_qk$++xHUELt`zQAAw(}=8PU|07{eNQruHQeg zZ3h3qF8(L>?;4c-W1J5g{$K3B?P0Bzh{(c!Uo>5icTfLrV*fb4`&}T(YmGb+zZ(z7 gdnEYy3XOjM=HvVQ@meckk>7ud@qT_^|JSwu2jz{;f&c&j diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/dqn.txt deleted file mode 100644 index 90ef1ea40..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/dqn.txt +++ /dev/null @@ -1 +0,0 @@ -99999 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/optimal.txt deleted file mode 100644 index 1a3cffc82..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4181 -3360 -5349 -4572 -5868 -4643 -3721 -4332 -4296 -4253 -3899 -3251 -3128 -5218 -3607 -2288 -2624 -4896 -3321 -4115 -3703 -5033 -4855 -5301 -3826 -3442 -4354 -4815 -3612 -3112 -4283 -5599 -4111 -3709 -3177 -2670 -4081 -3519 -4684 -3521 -3700 -5279 -3494 -2824 -4296 -4343 -3603 -5116 -2914 -2802 -4266 -4631 -5112 -4042 -5253 -4192 -4075 -4816 -3533 -4473 -4707 -3740 -5483 -3106 -3180 -3267 -3517 -2871 -3610 -2818 -5219 -4513 -4681 -3650 -3811 -4623 -2978 -5074 -3328 -3623 -4226 -3229 -5058 -4504 -3738 -3670 -4668 -4620 -3522 -4540 -4584 -4617 -5132 -4647 -3443 -4143 -4885 -4290 -4385 -3254 -4200 -4736 -4274 -4956 -3993 -3170 -3539 -2940 -3089 -3780 -3618 -4957 -4380 -6035 -5659 -4347 -5214 -3340 -5318 -3535 -4673 -3783 -3556 -2442 -3155 -4505 -5504 -4349 -4052 -4689 -4176 -4553 -3325 -2994 -4910 -4725 -5112 -4006 -5423 -5259 -4614 -5157 -4259 -4115 -3453 -4974 -4667 -4898 -4514 -4452 -3806 -3817 -3429 -3630 -3858 -5347 -4603 -4637 -3548 -3985 -6016 -2221 -4315 -4311 -4339 -3720 -2719 -3199 -3640 -4974 -4701 -4149 -4467 -3516 -4041 -5534 -3550 -3411 -4174 -3451 -3105 -3296 -3393 -4380 -4450 -3759 -5412 -3962 -4122 -3391 -4075 -3529 -4284 -3019 -4184 -4521 -2349 -3258 -3018 -4023 -4683 -4033 -4886 -4409 -4017 -4408 -4328 -4994 -5092 -4566 -4533 -3375 -4170 -4421 -4428 -3345 -3206 -4261 -4490 -3242 -4284 -3528 -4380 -3364 -5595 -5083 -3298 -3412 -4038 -4506 -4034 -4346 -5719 -5266 -5026 -3799 -4001 -5678 -2806 -3903 -5534 -3315 -4436 -5021 -4940 -4671 -4336 -4869 -4520 -3671 -2577 -3496 -3741 -4589 -4916 -4493 -4424 -2716 -6667 -3462 -4237 -3253 -6654 -5024 -4099 -2946 -3800 -3530 -3778 -4803 -4928 -4839 -3139 -4836 -4058 -4514 -5625 -4945 -2967 -3379 -5140 -3473 -3435 -4216 -3444 -3863 -4120 -4685 -4227 -4631 -2726 -4224 -4342 -4816 -3319 -3169 -3557 -4062 -4370 -2531 -4398 -4603 -3295 -5017 -4161 -4652 -3199 -6054 -4689 -5254 -4946 -4057 -5202 -5042 -3905 -5797 -3949 -4098 -4755 -2711 -3310 -3494 -3696 -3641 -4261 -3812 -3687 -4015 -3996 -4273 -3725 -4339 -4851 -5399 -4257 -3526 -5615 -3758 -4096 -3751 -6295 -4374 -5169 -5006 -3859 -5255 -4669 -4505 -3669 -5862 -3504 -4834 -3756 -3536 -4149 -3534 -4984 -4704 -4882 -4034 -3984 -3603 -2857 -6358 -3169 -4637 -2679 -5051 -4457 -3609 -3221 -4190 -4186 -4075 -3692 -4049 -4232 -3418 -3687 -4554 -2519 -4953 -4395 -3690 -3607 -5252 -4030 -4961 -4317 -3500 -4277 -4946 -3992 -4368 -4112 -5211 -3240 -4739 -3750 -5064 -4649 -3954 -3744 -4637 -4141 -5027 -3715 -4991 -3367 -4681 -3213 -4527 -3124 -2584 -4396 -3970 -4323 -4455 -4018 -2994 -4401 -5182 -3518 -4415 -4026 -4992 -3198 -3888 -3459 -3899 -3397 -4690 -2930 -3661 -3686 -4975 -3771 -4991 -3884 -3515 -4950 -4961 -4659 -3327 -5193 -3249 -4259 -2862 -4048 -4018 -5345 -3594 -3126 -5013 -4908 -3228 -4503 -5266 -4716 -4019 -3596 -5702 -4195 -6458 -6019 -4186 -4053 -3704 -5229 -4786 -3107 -4084 -3314 -3405 -5165 -4764 -4464 -4942 -2880 -4227 -3406 -4205 -4805 -3691 -4707 -4245 -3301 -5315 -4576 -3572 -5467 -3690 -3599 -4439 -4128 -4805 -3835 -4049 -5035 -3129 -4030 -5717 -4056 -4762 -5345 -2517 -5230 -3703 -5094 -3411 -5547 -6349 -5111 -3730 -5858 -4573 -3935 -3367 -2873 -3931 -4437 -3828 -3163 -3849 -3794 -4040 -3667 -5904 -4752 -4036 -3718 -4540 -3946 -3434 -4643 -5192 -4465 -4588 -3451 -4157 -3486 -4289 -2965 -3805 -3533 -4111 -5276 -5294 -6766 -3755 -3701 -3542 -5072 -3627 -4046 -3910 -4360 -3204 -3694 -4526 -4071 -4605 -4061 -4672 -3612 -4822 -4846 -2792 -5241 -3616 -3731 -5257 -4845 -3260 -3075 -3823 -3891 -5467 -3799 -4543 -3892 -4390 -3941 -3991 -4299 -4876 -5560 -3876 -4330 -4866 -3322 -4052 -5002 -4167 -3659 -4297 -3700 -4221 -4223 -5148 -3003 -4619 -5582 -3287 -4905 -3304 -4859 -4609 -4884 -4591 -4945 -3365 -3901 -4372 -3773 -4112 -3699 -4005 -6513 -3839 -4524 -5542 -5118 -3748 -4021 -3887 -3577 -4165 -3762 -3961 -2167 -5948 -3936 -4024 -4815 -4257 -4280 -4271 -5089 -3694 -4771 -2969 -4809 -4379 -5738 -5532 -3137 -4347 -3959 -3564 -5246 -4786 -2665 -3640 -3499 -4092 -4062 -4731 -4042 -3217 -5020 -4003 -3891 -4087 -5254 -4411 -4352 -3808 -4915 -4718 -4033 -4431 -3766 -3668 -4285 -4702 -5088 -3456 -4345 -3436 -4250 -4301 -4078 -3742 -3599 -4698 -4321 -4923 -4712 -3530 -5159 -3942 -2956 -3632 -4662 -3498 -4612 -4161 -3620 -4306 -3579 -4150 -4609 -5305 -6663 -4617 -4313 -4036 -4565 -2584 -4893 -4890 -5125 -3771 -3099 -3169 -2548 -4101 -4654 -5291 -4015 -4569 -6009 -4363 -4513 -3714 -4427 -4137 -4872 -4451 -2850 -4921 -3850 -3755 -4406 -3653 -3112 -3969 -4633 -4238 -5594 -5599 -3220 -5499 -4749 -4524 -3847 -4644 -3670 -5607 -5241 -3660 -3261 -3840 -4578 -3576 -4575 -5814 -4639 -3260 -3831 -4239 -6512 -3194 -4197 -3656 -4867 -3765 -5065 -3070 -4232 -4079 -3576 -4788 -4461 -4874 -3870 -4062 -4038 -6598 -3570 -3441 -4959 -5814 -3489 -4115 -4762 -5703 -3972 -3461 -3789 -4304 -4763 -4936 -4028 -5134 -3837 -3834 -4668 -4008 -3433 -2839 -4717 -4746 -2997 -4624 -3898 -3617 -4352 -6028 -4934 -3701 -4497 -4636 -3671 -4270 -3896 -3432 -4655 -4521 -3920 -4027 -2639 -3964 -3058 -2538 -3499 -4627 -2776 -3152 -5667 -5717 -4071 -3965 -4185 -3387 -5283 -5165 -3060 -4599 -4917 -4274 -2770 -5225 -4866 -4376 -5984 -4129 -3902 -4028 -3320 -4158 -4457 -4087 -3910 -3104 -4691 -5178 -2623 -3184 -4565 -4314 -3255 -3215 -4524 -5345 -4456 -4846 -3986 -4756 -3827 -3955 -3706 -3968 -4638 -4987 -3614 -4437 -5777 -3679 -4972 -4588 -3110 -4635 -2670 -4128 -3934 -3992 -3559 -4236 -3553 -3616 -3776 -4892 -4642 -3837 -4948 -4012 -4120 -4649 -4484 -4378 -5655 -3712 -2986 -3610 -3360 -5631 -3431 -4209 -5265 -3498 -4197 -4128 -3559 -5627 -5424 -4162 -4206 -3471 -4211 -4188 -4162 -3736 -5197 -3246 -4399 -4578 -3731 -4024 -4311 -5417 -5191 -5730 -3726 -4245 -2764 -5091 -3456 -3983 -4228 -4169 -5131 -5265 -3674 -4495 -4351 -4964 -4658 -4495 -3642 -4040 -4375 -3483 -3989 -4853 -4367 -4692 -4299 -2983 -4853 -4187 -3190 -4016 -4548 -4771 -3498 -3665 -4453 -3927 -4112 -4777 -5171 -4455 -3295 -4695 -4895 -5149 -3633 -4292 -4065 -4254 -4088 -4221 -3618 -4261 -5421 -6244 -3843 -3948 -4796 -4186 -4333 -3207 -5825 -4184 -3428 -5014 -4755 -4107 -3600 -3889 -3337 -4310 -4036 -4515 -4029 -3918 -4619 -3343 -4000 -4169 -3077 -3285 -2256 -3292 -2752 -3892 -6018 -4727 -5516 -5427 -3279 -3630 -4191 -3678 -5030 -3669 -3791 -5737 -3431 -4480 -3685 -3638 -3598 -4748 -5419 -3679 -4893 -4626 -2742 -3687 -4527 -4268 -4192 -2846 -2788 -6365 -4725 -5740 -3245 -4909 -5298 -2257 -5360 -4757 -3170 -3974 -3591 -4414 -4793 -5988 -5175 -4023 -3372 -3338 -4197 -3925 -2850 -4829 -3213 -3857 -3353 -4192 -5773 -4675 -5649 -5041 -3748 -3121 -4116 -4592 -4219 -4387 -2510 -3454 -3545 -4498 -3657 -3748 -3352 -4714 -3749 -3590 -4513 -3032 -3537 -3973 -4898 -5064 -2942 -4591 -3914 -4671 -3890 -3141 -4293 -3632 -3050 -3965 -4976 -4433 -5115 -4754 -3712 -4239 -4243 -4160 -3763 -4389 -4156 -6323 -4879 -5544 -2660 -4261 -4017 -3204 -4895 -4443 -4035 -4751 -3789 -4567 -3166 -4712 -4295 -3872 -3866 -4170 -4585 -3825 -3603 -3933 -4503 -5281 -3083 -4296 -4454 -4657 -3953 -2368 -4494 -3374 -4727 -3257 -3864 -4285 -3619 -3182 -4078 -3200 -4522 -5016 -4651 -4843 -4858 -3685 -3476 -4293 -4710 -3511 -3021 -4904 -3266 -3747 -4933 -4117 -2667 -4000 -4041 -4445 -4394 -3279 -4323 -4380 -4882 -3295 -3572 -4376 -5241 -3415 -3554 -3171 -3412 -3851 -4774 -3464 -3817 -3519 -3339 -5030 -4808 -4471 -4613 -3810 -3559 -3795 -4546 -4330 -5898 -5603 -4437 -4673 -4224 -3898 -3008 -3437 -4063 -2268 -3932 -3531 -5239 -4355 -4271 -4488 -4363 -3574 -3919 -4660 -5337 -3688 -3100 -5601 -4113 -4490 -4257 -4674 -4054 -4349 -5442 -3327 -4873 -3070 -4831 -3978 -4466 -4779 -3884 -4395 -5252 -4190 -4043 -3530 -3465 -4682 -2664 -4648 -4241 -5142 -5199 -3995 -4303 -5490 -4113 -4424 -4884 -3442 -4039 -4104 -4249 -4042 -3745 -3847 -4027 -4659 -4528 -3939 -3384 -3236 -2977 -3579 -4465 -4546 -4497 -4476 -4267 -4343 -4584 -3646 -5810 -3946 -4288 -4647 -3562 -5806 -5315 -4702 -5755 -3913 -4319 -4668 -2896 -3537 -4917 -3901 -4318 -3653 -2662 -3755 -3099 -4929 -4398 -5112 -3421 -2828 -4593 -4071 -3651 -4418 -3118 -3875 -4328 -5317 -3954 -4006 -4698 -3338 -4345 -4028 -4305 -4579 -5188 -3070 -2885 -4548 -3883 -3786 -3885 -5775 -4657 -4689 -4420 -3893 -5300 -4393 -4424 -4442 -4298 -3796 -4991 -4142 -4699 -4154 -4374 -4420 -4502 -4228 -5623 -3831 -4396 -3425 -3508 -3882 -4347 -3788 -4389 -3436 -3621 -4227 -4611 -3976 -3615 -2830 -3724 -3674 -4251 -5543 -3149 -4736 -5698 -3206 -5183 -4722 -4041 -5215 -5769 -4978 -4636 -4400 -4491 -4436 -3222 -5856 -4495 -3359 -5205 -3466 -5416 -4368 -5109 -3682 -3496 -3740 -3631 -3694 -3660 -4832 -5274 -3955 -4406 -3949 -3690 -4846 -4481 -4164 -4300 -3118 -4813 -4744 -5098 -3733 -5400 -4515 -4877 -3680 -4090 -3971 -3576 -4889 -3536 -4519 -5060 -3536 -4580 -5621 -3398 -4388 -3873 -3386 -4483 -3224 -4990 -4769 -3844 -2874 -3883 -4113 -3817 -4788 -5206 -5201 -4568 -5504 -4042 -3966 -3704 -4746 -3815 -2995 -4440 -5438 -4279 -3858 -4483 -2638 -4286 -4231 -4868 -2796 -3379 -3954 -3597 -4400 -5065 -3223 -4565 -4269 -2747 -3873 -6425 -4870 -3550 -4157 -2996 -4618 -2378 -4127 -3001 -4226 -4435 -4456 -3733 -5168 -5229 -3488 -3152 -4811 -3573 -4184 -3803 -3342 -4545 -3902 -4701 -5101 -3896 -3493 -4025 -3966 -4732 -4378 -4401 -4673 -4626 -5105 -3655 -3862 -3686 -3756 -3754 -3635 -5522 -2890 -2803 -4433 -5298 -4635 -4001 -3811 -2787 -3900 -4075 -4431 -3211 -5746 -3485 -3781 -5451 -4617 -3179 -3275 -5009 -3397 -3351 -3835 -5043 -3371 -3296 -5895 -4303 -3668 -4926 -3581 -5285 -3831 -4238 -5641 -4872 -3759 -3376 -4251 -3249 -3797 -4747 -3760 -3331 -4576 -3053 -4009 -3949 -6529 -3890 -4186 -3611 -3061 -6122 -3608 -4182 -2721 -3056 -3056 -4189 -4299 -3455 -5107 -3666 -3365 -4165 -4321 -4420 -4492 -4702 -3196 -4384 -3848 -2437 -3729 -2712 -5247 -4357 -3709 -5176 -2667 -4450 -2718 -3911 -3202 -3575 -3080 -4599 -5504 -3585 -4170 -3779 -3417 -4025 -3633 -4725 -3957 -4060 -4334 -3524 -4907 -3719 -3587 -3103 -4335 -4292 -4803 -3252 -4078 -4632 -3837 -3749 -3903 -4407 -3766 -4405 -3704 -5804 -5220 -4111 -3855 -3754 -3198 -3872 -3630 -4893 -4619 -3750 -4703 -2773 -4471 -3714 -4722 -4822 -3268 -5367 -4319 -5378 -5091 -3426 -3533 -5863 -5395 -4759 -4801 -4890 -4336 -3911 -3376 -4745 -4571 -3469 -4885 -4902 -3320 -3486 -4088 -3838 -4084 -5441 -4992 -4003 -4858 -3871 -4153 -4687 -5146 -4455 -3681 -3389 -3180 -4152 -4306 -2771 -5030 -4336 -3304 -4427 -4561 -3777 -3060 -3978 -4555 -3610 -5252 -4369 -3218 -5294 -2971 -3773 -4384 -5864 -3394 -3177 -3056 -3997 -5398 -4228 -3972 -4225 -3951 -3890 -5293 -2931 -2867 -4430 -3825 -4721 -4702 -5169 -4368 -3235 -3729 -5859 -3849 -4389 -3463 -4114 -4635 -4827 -4241 -4439 -3867 -4726 -5169 -3593 -6237 -5140 -3822 -4008 -3825 -3559 -3894 -4039 -4166 -3386 -5939 -4462 -4255 -3832 -3692 -5154 -4643 -3884 -4604 -4725 -3923 -3884 -4238 -3702 -4968 -4362 -3447 -3513 -4073 -4662 -2759 -5222 -4452 -3916 -4045 -4470 -3877 -4814 -5133 -3799 -4353 -3603 -4186 -3779 -3628 -4351 -4332 -5263 -4594 -3804 -3485 -3725 -3882 -5022 -4515 -4537 -3635 -3896 -4784 -4564 -3891 -4813 -3927 -3424 -4440 -3535 -4193 -3951 -3616 -4973 -2900 -5270 -4651 -4991 -4359 -5191 -5232 -5811 -3551 -3907 -3650 -1758 -5026 -4520 -3399 -3617 -3292 -4267 -3489 -5707 -3737 -4187 -3489 -3720 -4695 -4655 -3915 -4130 -4231 -4276 -5414 -3855 -4415 -4741 -4396 -4380 -3930 -3043 -4117 -4091 -4882 -6390 -4387 -4067 -3885 -3626 -4135 -4777 -2628 -3641 -3456 -4153 -3962 -3445 -3741 -3903 -3266 -2971 -4061 -4149 -2020 -4195 -5199 -5196 -4363 -5279 -4275 -4851 -4431 -4491 -3221 -3328 -4532 -3270 -3995 -3591 -5112 -4351 -2641 -3820 -4221 -3531 -2554 -4163 -6093 -4609 -4152 -3996 -4140 -2976 -3737 -4127 -4696 -4332 -5102 -3349 -3632 -4845 -3580 -4743 -3539 -4891 -3126 -3553 -4068 -2960 -3049 -4166 -5045 -2937 -4228 -3428 -4177 -3279 -4284 -4277 -4074 -4990 -3863 -4860 -2522 -3489 -2709 -4083 -4519 -3531 -3222 -3465 -3461 -4080 -4111 -3777 -3846 -2603 -4231 -3200 -3824 -4216 -3609 -5103 -3140 -3498 -3569 -4319 -4852 -4499 -4336 -4564 -3691 -4440 -4662 -5339 -3410 -4219 -4504 -5534 -4542 -3584 -4251 -4729 -4074 -3841 -4170 -5174 -5589 -4581 -5160 -4233 -4228 -4145 -4925 -4292 -3595 -4550 -4803 -3799 -4103 -4449 -4160 -4839 -4084 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/random.txt deleted file mode 100644 index ed4ccc62a..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -49209 -62906 -45614 -63791 -41957 -41715 -54716 -46259 -50482 -51969 -43403 -44482 -47998 -44866 -59582 -67939 -42474 -54240 -29747 -60739 -49041 -56112 -43812 -62511 -51839 -42951 -50371 -53470 -45148 -43203 -47464 -34627 -33535 -47112 -60644 -59005 -78298 -48008 -58737 -47831 -66052 -47194 -75622 -64746 -42416 -42499 -59148 -36658 -44829 -41739 -47748 -37973 -53413 -45063 -44557 -45680 -64361 -62553 -57125 -63143 -33427 -57750 -55207 -61277 -34734 -52955 -47930 -45209 -54624 -61261 -50908 -64302 -49848 -52239 -36400 -56453 -38692 -52021 -44664 -49040 -35539 -59438 -58511 -30159 -24921 -42761 -54071 -38130 -51471 -48157 -46441 -44859 -60573 -57763 -46918 -49479 -44962 -63791 -33856 -42376 -49346 -45188 -52101 -45745 -63117 -41287 -57980 -55180 -47926 -42418 -46816 -47288 -44568 -64276 -76161 -68279 -46932 -46422 -45976 -40755 -58048 -42651 -38320 -58125 -43813 -57871 -61762 -44114 -54783 -53654 -37877 -49124 -49686 -49184 -42843 -58439 -59349 -50858 -66740 -51291 -44284 -39254 -43905 -53456 -49185 -54249 -65830 -47914 -48470 -47733 -50221 -35186 -56863 -60767 -56234 -53742 -46032 -63452 -54226 -63444 -52223 -43308 -45046 -46368 -48558 -49168 -53629 -29452 -41685 -45337 -49209 -48187 -42989 -47374 -47968 -47613 -42721 -43757 -43749 -47840 -54529 -60460 -55991 -43842 -51341 -61835 -36077 -51093 -46319 -47567 -47337 -49230 -53642 -52591 -49168 -41018 -41086 -58947 -57475 -67595 -52175 -70094 -53197 -31523 -54059 -44514 -52062 -61822 -37167 -55022 -55016 -48845 -51950 -64972 -72759 -47130 -64759 -71934 -69622 -68459 -59222 -48299 -28863 -54045 -51355 -46372 -50561 -74948 -49555 -43167 -56280 -75110 -47909 -52457 -64302 -61830 -55161 -51631 -50917 -51982 -54139 -48344 -42789 -41770 -45010 -41422 -78941 -54918 -45105 -53627 -53887 -52876 -46507 -58813 -64622 -40658 -35529 -64576 -60479 -36493 -66189 -60302 -52434 -70664 -59388 -36892 -42193 -68437 -47835 -58256 -57930 -30523 -70817 -38410 -70500 -42339 -55670 -41513 -59053 -44231 -49023 -40337 -42802 -50403 -54161 -43426 -42480 -54340 -47675 -34546 -54285 -55566 -40443 -51845 -30012 -44362 -58167 -37936 -53848 -47818 -33212 -72602 -62737 -42893 -52987 -61823 -79566 -47091 -49409 -49173 -53076 -52734 -47861 -48792 -45971 -55145 -71807 -45773 -49993 -46889 -42825 -32631 -49761 -51139 -58402 -64642 -50297 -42705 -39366 -42151 -47830 -59285 -43856 -55065 -75534 -49182 -69862 -56959 -47921 -60249 -46293 -55086 -54791 -51398 -61431 -53513 -58546 -60215 -42797 -41111 -64321 -37711 -62121 -60347 -55972 -53944 -51306 -44672 -41900 -44487 -26856 -46685 -29459 -66953 -47106 -61482 -40165 -52318 -44121 -56114 -57512 -50525 -70031 -55178 -47195 -86498 -54751 -62441 -48386 -52596 -48986 -60222 -66977 -55973 -47181 -55617 -44292 -62541 -45939 -57194 -51005 -58131 -54394 -41515 -58683 -56183 -49264 -44786 -63592 -34529 -44669 -47954 -61676 -58008 -43170 -61588 -59513 -38529 -47737 -52474 -45393 -47984 -35840 -40182 -55018 -36036 -49962 -50863 -39873 -56764 -54940 -55319 -45854 -46111 -64698 -71129 -47503 -36671 -53256 -44581 -63717 -44235 -45271 -42984 -43524 -56402 -35568 -53091 -69277 -48608 -72794 -58438 -50582 -58318 -49761 -33389 -55004 -67684 -38345 -47156 -70994 -36716 -44218 -76682 -41951 -52682 -61834 -52750 -61409 -54760 -54948 -60149 -35004 -56286 -34489 -66938 -47139 -60688 -67460 -44740 -53766 -53851 -39293 -42304 -49028 -40070 -39731 -58770 -50900 -43025 -53454 -54135 -75868 -70018 -47950 -45063 -48078 -45174 -62096 -58645 -53824 -59335 -69592 -59819 -49484 -65546 -55856 -67524 -75799 -60294 -61521 -75374 -62245 -63909 -35405 -58284 -48910 -44256 -38950 -47536 -49097 -40084 -50087 -44146 -63914 -47877 -59902 -58620 -49145 -53152 -66238 -57550 -62932 -49856 -42674 -48843 -51309 -45041 -53505 -57172 -50358 -55331 -53011 -33431 -44036 -39837 -57355 -65815 -50488 -71123 -51818 -50706 -47922 -53860 -58920 -49820 -47430 -39271 -50084 -53482 -51752 -46483 -81015 -60157 -29247 -56037 -40742 -46685 -47518 -41712 -68897 -65413 -57360 -65846 -63376 -51028 -51103 -56715 -57690 -58217 -46779 -38625 -47333 -44924 -39359 -60174 -56333 -67102 -35239 -63139 -69499 -43969 -69393 -46699 -39866 -49299 -52197 -56089 -42256 -36216 -49439 -67331 -71486 -32198 -34410 -52436 -33846 -38386 -34225 -49134 -44244 -52267 -48183 -44281 -39397 -63987 -60365 -68215 -33999 -56778 -61388 -38118 -41949 -67636 -47417 -41518 -56335 -85925 -52258 -41537 -44016 -51099 -64516 -46865 -76924 -48896 -68669 -63128 -45446 -42910 -49905 -67687 -41904 -47171 -66872 -43554 -42333 -50270 -41898 -57696 -33857 -71201 -51442 -62528 -32786 -48436 -51968 -53545 -47911 -66180 -56706 -52756 -52182 -49654 -58622 -40409 -54733 -36698 -65069 -68247 -54066 -75877 -42224 -55603 -62148 -51732 -56543 -52763 -38076 -53222 -39490 -63653 -36457 -56587 -47778 -59028 -47309 -69326 -45638 -48812 -72399 -50351 -63120 -57374 -53490 -73923 -64297 -57155 -31385 -79050 -69445 -50121 -56641 -56801 -51125 -58971 -38033 -64412 -51004 -57875 -62045 -42197 -57783 -54246 -46714 -44333 -72875 -61791 -74567 -46687 -55120 -44014 -42929 -35301 -60691 -61870 -79392 -37497 -57300 -51069 -73742 -43128 -61000 -40802 -44614 -42892 -46548 -52194 -43281 -55318 -48735 -38467 -47641 -55307 -79201 -47132 -59760 -52960 -36951 -53163 -64906 -59157 -57012 -56195 -55640 -64117 -53976 -68341 -56922 -58067 -51664 -50877 -41370 -38726 -70095 -53467 -47868 -45849 -77016 -39696 -54086 -58565 -36395 -38741 -44671 -59209 -48734 -63948 -59614 -51747 -36523 -50160 -59477 -73171 -54317 -38797 -55927 -55400 -54787 -64427 -39049 -54894 -53462 -42670 -51931 -30371 -62058 -64079 -46616 -56452 -50037 -76112 -44317 -43230 -56941 -40436 -36412 -44345 -65218 -36274 -54185 -53622 -47766 -51059 -61590 -54869 -68812 -30181 -55035 -54514 -54834 -55359 -68663 -51862 -48135 -62750 -45421 -50750 -53685 -66974 -53138 -54477 -49906 -46913 -41159 -39594 -67996 -62010 -58247 -49258 -61721 -33030 -44553 -72891 -52840 -56091 -52266 -71780 -69019 -47250 -32107 -47283 -40486 -74040 -41013 -56423 -58424 -52502 -51696 -60529 -61699 -38015 -69454 -61618 -46248 -51729 -70810 -66574 -48603 -47465 -65757 -35290 -36895 -65972 -42532 -73625 -41106 -58804 -67982 -49623 -60283 -47783 -47362 -45886 -57123 -48084 -49546 -58639 -35823 -63334 -58927 -47799 -39302 -41841 -46617 -42165 -55208 -65427 -44032 -69115 -53204 -49520 -30513 -38834 -57594 -39726 -48937 -40624 -51143 -42344 -50810 -58523 -49459 -48441 -70271 -44429 -62426 -47860 -55102 -52189 -58831 -41270 -45690 -50011 -47372 -45324 -39539 -71696 -56437 -59582 -43543 -64116 -50260 -59266 -41877 -55254 -51889 -62552 -51213 -78916 -40251 -58430 -51696 -73121 -47603 -61406 -52690 -50328 -51850 -55737 -44258 -51262 -38657 -38871 -45332 -40261 -57245 -41812 -53997 -31335 -38658 -57079 -54680 -38034 -41562 -44479 -52992 -55482 -64164 -50271 -47279 -77781 -77897 -43189 -62450 -57569 -50790 -49061 -50269 -49722 -58651 -42638 -64473 -35416 -54272 -45769 -72245 -42541 -42116 -72182 -42983 -47560 -58961 -43352 -50531 -49403 -49559 -49844 -70460 -39041 -43010 -57343 -54443 -34755 -41767 -54351 -64231 -22796 -51547 -52707 -78588 -54265 -61238 -43787 -25750 -48513 -50061 -63961 -57603 -45434 -50958 -63281 -51150 -47346 -52113 -51918 -55058 -45595 -40059 -65785 -48987 -67173 -56640 -37321 -54724 -59197 -76575 -48228 -59404 -55060 -31724 -40951 -40911 -45807 -72512 -55947 -54084 -44482 -44980 -51116 -47906 -53264 -32573 -62708 -48423 -54210 -86595 -43916 -51080 -59212 -68549 -55236 -29969 -53977 -34169 -61196 -53650 -61696 -60245 -46299 -72236 -53037 -58943 -64329 -49926 -63392 -50092 -72059 -56110 -60996 -81374 -55423 -51756 -46477 -52650 -46899 -62447 -62308 -37762 -44321 -49218 -36503 -36752 -51957 -54756 -45928 -44885 -38448 -38845 -42441 -46296 -61679 -35862 -42720 -57135 -53259 -56982 -55073 -63285 -45607 -59611 -34135 -52720 -48707 -47945 -65089 -59733 -65203 -62560 -64238 -38414 -41334 -51345 -61379 -57771 -65628 -44431 -55973 -52529 -45172 -61893 -67357 -65596 -49883 -41324 -63399 -41344 -57317 -67603 -49214 -35520 -48727 -67611 -47767 -65589 -42318 -51307 -60239 -50943 -77641 -38845 -31913 -69677 -49915 -38811 -45261 -53388 -59814 -33479 -55977 -62542 -46841 -43934 -56786 -40748 -73193 -50850 -45999 -31831 -53996 -56477 -53678 -51487 -76202 -47795 -41739 -49393 -42437 -77850 -49932 -49124 -54470 -62839 -61514 -66590 -56576 -52022 -59220 -48645 -60713 -46424 -57924 -49285 -48450 -61189 -56576 -58929 -46262 -51925 -53289 -42913 -51703 -54070 -62233 -61297 -67856 -64176 -58551 -62910 -56573 -37487 -49040 -61399 -66628 -44377 -40186 -49109 -46910 -32850 -50042 -55811 -53575 -44768 -47128 -44015 -62182 -45301 -36141 -54879 -54525 -43700 -45195 -57666 -32909 -33497 -41342 -32710 -73266 -52580 -55593 -48427 -43038 -65719 -54078 -31383 -55918 -49258 -61348 -51325 -58433 -61675 -72803 -72985 -63997 -59935 -51689 -35112 -56994 -57797 -33794 -48072 -42500 -46970 -59704 -55527 -66618 -43364 -42786 -51355 -66934 -67792 -60284 -48420 -27799 -52039 -43039 -50839 -52879 -50306 -48653 -64400 -42921 -58107 -49017 -41388 -40603 -47916 -42961 -53950 -40635 -55110 -52106 -54954 -54876 -50351 -48879 -50993 -53106 -68821 -43276 -41793 -47575 -61306 -50308 -47029 -52668 -53282 -55796 -41323 -43859 -37528 -57270 -55375 -57181 -47493 -49762 -45962 -49380 -44365 -54472 -58495 -47634 -60709 -50445 -56708 -60552 -57602 -29555 -52917 -69745 -51239 -60902 -57646 -48661 -53818 -45075 -77472 -64275 -44358 -53330 -42693 -49626 -56038 -20886 -51175 -64936 -36106 -63586 -50671 -50463 -55204 -51947 -46808 -48495 -46396 -44804 -60819 -49678 -69415 -55972 -37712 -53059 -51316 -53721 -39214 -57042 -74518 -61034 -56149 -50683 -61603 -43804 -59999 -46975 -40582 -48122 -66786 -61691 -43378 -56460 -55288 -40339 -74480 -44443 -44333 -45981 -55631 -68100 -47493 -39173 -46083 -50721 -53044 -54368 -55568 -50173 -80071 -57869 -58224 -40881 -44361 -42335 -55099 -50731 -48606 -49989 -42729 -55436 -43686 -38450 -40915 -29935 -62758 -44271 -67039 -60396 -67059 -62592 -53840 -53489 -41008 -60419 -39989 -58321 -48355 -42914 -48062 -42707 -51418 -53602 -39559 -66159 -46112 -59996 -54810 -57032 -50433 -60499 -50234 -46880 -49526 -60179 -43420 -65775 -51074 -42037 -38769 -34106 -65414 -45753 -61187 -38817 -54303 -43949 -44208 -52844 -69206 -60185 -44537 -52483 -62943 -46471 -40833 -53598 -43970 -63880 -54051 -47265 -55022 -43280 -38364 -58246 -69456 -56013 -66781 -62472 -60907 -53414 -66945 -50324 -50346 -56693 -41312 -51650 -45473 -47915 -44204 -26206 -57488 -49385 -63531 -39907 -54250 -55431 -48279 -62453 -37961 -49308 -47505 -48098 -29048 -37267 -27635 -52803 -47929 -55532 -48020 -57911 -66381 -59698 -47534 -63430 -51718 -45384 -57628 -55758 -69780 -43341 -48357 -44433 -67473 -60024 -48585 -56440 -57597 -59595 -64081 -52628 -79710 -60777 -37791 -46573 -63519 -54018 -57071 -59646 -46497 -36176 -69652 -45675 -45249 -68226 -60737 -39391 -79226 -44837 -40582 -43897 -42016 -41233 -63962 -61871 -50871 -50418 -81610 -50716 -52415 -60005 -63400 -34821 -47511 -54471 -52992 -73597 -51508 -52733 -55971 -39118 -45004 -54621 -51033 -54204 -60056 -43880 -36147 -67191 -70281 -54265 -59955 -32382 -56003 -55160 -46006 -64258 -38122 -72630 -43787 -59732 -62308 -54408 -46981 -46021 -41846 -63346 -60777 -53087 -44581 -74720 -39068 -40338 -46940 -62782 -52360 -47940 -40880 -49227 -50351 -52508 -50358 -33704 -61778 -63201 -58337 -53031 -50004 -42323 -74495 -54788 -52423 -45941 -54277 -36498 -68434 -49866 -77188 -57555 -71548 -48834 -58265 -41973 -57014 -61262 -58368 -58269 -31700 -57144 -56691 -45438 -59207 -39782 -44565 -39896 -61184 -39671 -50099 -30138 -54386 -46818 -50973 -49375 -36476 -60171 -60885 -49618 -61297 -47858 -61765 -42187 -46701 -32996 -76331 -59864 -61059 -40446 -45743 -49787 -46958 -57028 -61273 -67514 -43619 -41708 -49691 -50993 -56674 -42950 -42105 -37719 -53281 -61745 -62022 -57882 -57907 -36836 -48444 -48660 -69792 -64653 -47703 -63940 -45042 -79751 -60349 -39410 -49281 -56119 -41180 -50362 -69847 -60279 -61156 -42000 -57980 -72292 -60746 -61575 -57247 -41285 -77526 -59315 -51651 -54279 -53283 -53544 -51960 -61539 -56822 -63535 -63656 -48386 -31944 -47402 -35878 -40415 -49804 -64183 -41138 -35580 -40751 -60007 -55187 -41872 -73986 -54017 -68606 -45716 -48149 -54541 -37083 -72467 -63700 -51908 -60581 -43958 -65733 -47176 -37680 -48815 -60414 -55034 -66353 -50722 -40001 -58952 -50545 -55183 -56589 -51485 -43386 -49290 -66188 -58108 -33841 -49612 -45163 -63102 -51260 -68666 -55140 -44368 -42942 -54914 -49688 -53528 -36986 -70675 -40486 -34190 -68231 -58780 -46915 -47770 -66253 -65043 -38321 -56115 -57533 -45721 -62268 -38514 -65469 -44100 -52598 -60900 -56529 -48587 -36737 -55113 -72600 -40540 -51421 -51237 -53276 -58061 -56100 -51695 -38674 -46795 -44391 -61290 -39949 -64619 -55129 -42867 -57459 -56744 -52028 -55747 -58026 -60966 -41194 -59922 -56205 -75946 -48179 -49877 -57310 -58074 -46731 -42390 -70644 -52399 -44582 -60375 -54925 -64305 -56048 -44878 -63546 -51435 -61341 -79322 -54278 -64768 -40764 -37791 -47376 -39801 -42315 -45644 -63853 -60961 -40630 -51255 -51010 -46215 -62207 -49595 -43337 -69995 -71638 -49615 -46489 -53518 -49237 -67580 -56536 -51018 -42200 -69072 -44168 -66102 -45977 -41585 -48493 -77490 -52173 -53403 -54761 -48685 -62637 -38934 -66569 -57014 -51074 -45027 -44047 -47616 -42491 -55427 -71810 -51536 -44193 -35272 -48708 -64606 -48159 -51522 -43686 -39051 -55901 -61829 -53330 -39147 -39222 -36938 -57349 -40692 -40953 -47509 -61290 -49399 -49104 -42943 -74045 -64679 -61570 -67287 -46788 -67683 -65573 -61375 -57900 -62281 -36615 -53050 -33246 -41554 -44179 -60097 -66027 -52814 -60001 -46669 -75647 -41115 -44515 -53557 -58123 -40330 -67059 -50403 -32672 -58277 -41264 -58924 -43196 -48851 -62493 -43320 -44267 -56619 -73170 -43840 -55710 -54820 -55890 -60576 -66310 -56497 -30271 -38777 -45227 -43651 -63576 -50642 -51389 -31795 -57510 -40349 -77050 -45264 -43051 -69226 -64902 -45661 -54828 -50886 -66639 -52072 -70967 -65119 -56339 -53520 -48755 -49954 -55448 -51793 -47127 -50746 -39921 -41290 -46714 -48262 -43907 -52550 -47111 -47842 -71181 -44013 -42602 -55726 -49669 -61846 -63479 -54953 -64519 -55542 -50251 -62270 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best.pt deleted file mode 100644 index f3e9b434e0407547f03bfa6c66facb28b1ddd3b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15831 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 Uc#A0y@9)3)*+0ME|LfiV2LcFLkpKVy diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_1.pt deleted file mode 100644 index cd47ca1240b87f3a436bf037460952c4b4cdb87e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15831 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 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k15/trained_ddqn/best_seed_2.pt deleted file mode 100644 index f258810b8d34f2200abe00223f5a7f0e24e15251..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15831 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 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k20/trained_ddqn/best_seed_1.pt deleted file mode 100644 index 550b4e69524ad5fcde1f3c34ef84230efdfd13eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16919 zcmbun2|QKZ`!{T!r;{rf-f@4o+^_y2s}=UqO_W}o%F&UX!auf4wOy0*C~zW@)9hzQSr zOENsud8}M)>>b=~S01r)vs&SN+|k%bif7;7k~g1?jgzCJt&N+5(@9q`GnXT_F1AP3 zIoP;~v3OLrvv`;75#yRZYNNU0w5@}ky&H?q#?6UqcEzDnZVryFVuxI8txq{P9y#P@ zd(zd(<&e9U7>j?|vOU6Flq(wM_W}S)!(Vro4eHu}k)Un25WvB(}38_x!2qA3D|!R<0~5d+vAH z3)ufO?;TO5F z7H?-Q`8N&i|Dv(f2e%|4l>tFB&WU zW<-~@l1pQT8%yI~HUe0he`sj^h1Ygt>1=1|p7LVp?Gfd+=%Ev~ZdQMW32W8AT3dhF z9`0El)@m=7!N2;_-PXmGJ49FvQ(o79br`n~ScDe~?EmA87K`*^G5_<7Hp|e9wdP-E zPPtmIFgFzz>2vwUbmHUT`IF86Ux%+0kKEse?@A40qiO#byxftz(prNoRdg<2r?;Hx zG*(Az{j_81_~ejJ3W~{tqW4K`yHAT`exkQ8-M}0+pU=7dX(!!2X-IA=n8_R_pMq1m z8fSI$3%0oQYw|*qF)5zI$JC;oI9sRRrMH@^a*9#{=>ApWhSr)3n7oEDbo;g-X2|+L z@_1<;T|Os{?1~*DCx>l0$A-k1_qDt^6$V|j#Gxwk_sQFI1wNtO*t0pgGk?*Fx|f*Y zC!BDW_d%u+Uk4ao=VQJ*B!n}h{g~nd=Q*lvrKtAuA>GgMVm8an<{T-iWv3lXr6=Qd z)6eupIkOJUmA_!C$^hGCD4F448%qLCilL>|hd763M-`|K$IvgLVGi!J5WK8vnh6|8}?f@Bip_Z6GVN zy-2ob88s+n&3x@VkMp+IocY@38ePX1L`IyS$C=~*3QAUG(IM_4w8ZC=qV|a$x;CGCfC~ey3PXCL3wfs^v}ey)NaJz+fB>Z zNdNzHyZu*7YWD45miHMFs{)K@p9Efx&t+rKoqLk(>}tl5zFy2-7)d2GX3>hvTSz72 zET{-HDqo-d3RSL((k3yout2wyT%Wy)*_qx$I3It7v#Lk&Qh+r5;dnAKd;;;z?w92L z318TFz?5`s{DRAJ_(>?13tQ;>la^nnUkJb54O8cZ>>zmQ0I^B6zm zNYU=%9L%{h2+Qte!iix8`X~Qk13iW?x#FTKQEqV*q|W%k;Jj*JINhVpb?MR#EH8*z zvk0%dD`2wP2;nK831V^_G)Zaz=}2XIW`D2na7np<}${o7=Y_=jcA%uTwELpm|& z)<2tg5UomAop=mPuWQ&FC`Q&^t0g}Fz5*)SdWoBjv+09-)?y7Q#(u5r#8@#c5Y_qC z(LYiJNki*=`1EWIrnt|eb9ypSX62j6yz{kH>v-!RU4* zoN!tXotx}nSExIx&27YGGaR8bJ{2R5Ud0`eLUiDPc*^=y4MzNE2BXf0>?c1dO8Gqx zX)7@U{CoxJisNg+yX_ckeg7203%|g(AO<>j>O)-qCycSYPWhB>0%7lEVCXxOacAlq z79aje6#C~6uey^spD0hfczzomh)BVfrEhVfyMz!@jAs-*nMr3R-@slC z5wd6jK`9;RMbRtL42LyWiPoCe#NE3ogx%tU5chf`&u{UvWOYS9&p%B=?Tcj?fWKLfh-BD8lV!RPM0J`V>h?dG9sNIM-n0N(t^9axbhj{3u0zd8?I)sHgJHb*@4|fTqu*H|Q z;XPdvrn8!GJJmgXckG&sF%fB^cND&n0%7^disiH~4012esse00$q6Fef}Xcrn0;;H;c536C#frF2JeVG$x7NK*w!!;QVoC!dPK8vvSE@ zP|25KHv7(}?;SZpq^_x@uRgm%p3IFWUFYwHj6fO}b_9~^HSbc1&zF<37S<3vz8!DW zWPnjzChADpm6HdAN%q=xq|WySYJ8y^DSnoR*#S?np!p--Au>SaS0y>ATSjK3ZYSsG zD=>|kWATx76*<2<2fT~>@ZzfdC@<&;Veb}TB4*Hc)~1l_UWn5zS8Gu?T8?}jyX1kx zvPI;N=SbbXH&gY=$eu9xlJ^*} z!3~uUgrI|cG?nV_j4ox@;i5qX2yaTox{_d+k)lW&hA)ASO~o)0d58;m?!);_ zUN~2o1Gjb?;O6sEw8HBJM7L=(m}}JI^8GPbl3ha(1A=%}@HZt?xEOsG9Y*G+2t4vW z7jnh~2}=Gm9@8GfrRVIRc=-&7ree|E)E#<YYUVs5F}$#7Dz!vz?5)D|W!8mNQU%!W8wcm4lgcEE?9lrM8``q#}Cqp|I5f za|I({ja(K!Pq+?meZ$d2emXVHsRuMhR+LCSod&+K+%dL;59D?(g~V4kAZG6_+`K@F zme{XNUoN`{UvxLn^V%CR;be4?6?^v9eaNd+ zTqd+OAKK&}qHabsyqIW*#Oqloe|s8H>23;V*NM@*v%=6y{xtIcj-;;JEu^~=2f!;K z4<5ONV{(rrhRL=tBpjB|gHF9=-6m&ozZe59dPSn&J0EnjRRfQGNNsp8LC(B$2X^uB z5pC|-Fc7*FD#FsisiYk8UYDs(H zMsf9fe5lum@%*~<+x>PJsYO#)PK}{+w-T)stZ{ z;F(`d|ciSGnc^ijfJqUaSpl+NYmya)v!n}9M86z@A*=o= zfP6VSWwki0+AKw$)A@jcLL(?ptpccV8IuKBFtltxoJ_7N%Zz?XER{%w_VW}R%(zG_ z%l$-!kGz4N%InZ9?*Yeh!Z1bq7JG4nAJx2DfIKW$gzs&(g5iBBQY-Zij(qJS%+(#B z#AXQM&#xn<4iDq%(hj7|GoUR?kbXa5g_nM&Vzv8CaF{Dbi$}N<-E~74xFQIOZ3>0BR<|lg#+#Q zCYlKg_q-w;-tNX%rLWK`BM1*AaQiAopKef;p?4HS;Gz~ae5m?>x?nJXYd0=H$C55Y zi#TYt5~C+ev(U!tH#mR!g(u}1bb?ej$R;{Nrv)$MiFskhvTR10>v52=IDl7fH)9?> z2KO_o!Q+!4nWQgHFDtWvZ;vm+g2Fs}BO?u0_Ksj?GGU+}+=KN4y|7xPonlHxp-|jC zj4cbrVE0g9>PM-F$c%K_Mwlb23~!{!SW$6RVcQAX!9ZYK&$7o6ut&(@bE3YQD>3kEo91#wi4y}Y6 zjNj03PllBA@+T~$8(?SL1dMv5f*WrRNWHaY$Bo1gKA+`q#V7Bbs0E=k7VQuv`XQZ_mep?bq;X{Sj(kuO+tRXrR>Q zLbl0mKb&+`!>RXCU>qz+#~OZvy&q;_!JSwbI3z@ukB!5}^i3aC6O5IA^(ykXjTE(UDVNnIcWz%&j6`Saia!QzEo)y*CQYd4(+V zA@KNJ4bc@J7;_SnAieq<%2j*fT9;6e8jV9S>kRlg^%5Ho{-SKJKPO!3yHUq}AvRtK z!cR)M(2>GJmVFW?iBRP3 zXNY`|qZ$RJ;Q9M_wD1U_{4ejtZ&Eeveuc%b#`H4Pm+}d%)|A3@cW>PDSe|yXmch$+ zgW4DDkW;SR~SkeJ&7h9;J%-6w%|dnb|DZ$_97rcv+Gqha#v6Fhyt2ix?b(D0xX zUA%TWz4I3bWmo$UsvfnNA}B-8Iaq`V#@6@+)xkig6-GMx;AA?D{O?8R{K=p2o3n_> zoV5vO8W=;vUe5{W%{x>JzWS6T=m+Ocpf zrVxH-zCpImN647l3C0z?q}#M0ob%x;9^AebBF?X*#aT{p&}%c!v0g@x1y17G1J_~I z8e#Hb@ffN^gy7uHn~?Bw7s2)tq`Qn$i0TjlGRy5g$h=ded8T|&)Zhh{%#x&s-WQ=~ z;Z0clN|25=v%nVLC(z-WhG=+`Q1whf-py<9nc8x?&y9~Z?dXL2W3%yatP^lboWVdp z6GLa*Vqg9p57P}^qiAv#997#wl`j;h15MJY?j?_4S+Wo2kP+0&Lw6~=gejD|>Bu;- zvrYI`6r6aL% z3zpk>p&I)bH5rhNo8?7lVud(uGuIRzAKAuurTrc6TsMWhlS80yJ%-1hNYWBH-K~BItKXjHkXOL_E(O7@cf@M^4?i z-E$2QY3dJ8M$1r7-GW%B2Oz%r4N3=(LB-ew>JfL{uqbOLeTzqkzSW`z-Bky`UR#o^ zx_t}X-w2UD>x*$q({b3+_8G0~`S65UDK;9Yp>UlB5g#UjPX~BN8x{|(?ePp3jtY^l zdkSFPF%wG0uo8aI){rI)afI3KcG}39%D4ek;lgk?5b2DAuG5vy=Vezd1dHA`2}>l z#0ZX@bp*CqGRVFdH&Fg2NEdGX&R}C8Wz+5hsoMwf6aPM9`MX7Qc5oCyAz9Q_6 zO$#t3X%y`h`BAQeO$h8BXYX1y9YmIMK=RryD49A@cI|`#hhk}l+9 zTGMhYIU`0-6n%m31NU*8urW1v!FMFzh|rZ8XOSVqfvUtTvR~@~DYcZJlmRBnE9}Ld zy?jiik`_wqK_*qTYZ8X59PyXx5@uIqJ2ig&VY!f$EqT{il?>r)#Dlnnxhv)(It zu`x=F6zw|#%LYtHsSFeH&9OCPkfS8?R;eV}l@LVsO__sOwE%l($q?DE@*2;)@WHNy z6Qq`E2=3nc6rb=&lXp}{V8e{B<(a9MpyEg#jCS+D_61ka;t*npnG~7lm;t?_FGxw= z1kAry2bZF=L3(2zjh!>;mXaLO{;d!ddfJrUS?L68mYa}@w>HADY)6VxZ>9JK0?=a7 z0;YXMA3hD{spyqC1HF%q5}iK~u1xG=@?Q;L?%U{seIY*7;&T$DpQJ3gvqzCyJ-QGj zlYWs38WT|b?Jz0n_!zaB-yv1=CX6@sQ1?$fCIl6E$W#?wv@jK=E#rUS$ipgPp5d~J zb*DMR1+fN5Q}s(;S@rd z8i$GrI|Aj^57^4BRi(PaOjvE2jsu(?!m^+cuf?^)h)E?erX);z%SD6SQV0C_{05Q> zE>iv@#W1h&7FO%l!Ku^Tz-tf!Q8p&HZ*>>G>Yl_cDW7q_>;nk;`~cSVs{+37UdNAn0trQjD&*}f!|EP!@{`vpbjWpvsIEXPtThAo zY98`))_Kaq-vXZQm;hPPAe>C>ge0r0)I;}KRI&Jb>{>5E3(l%FSo8KRp`4e2S@(tL zoelw1o=PQrQ5B=_PQC`2yAP3l?-ag^uSKi#&*4HyHMQEN4LTpRqV&3xaGZZW_&%IX zMIO5Xzgu+a7|A>E@W%=`_qi44uMb6C*Fuyyuz+yUivf;-65SDAMA@Y$5S?D<+0EA& z*qE&V@A{EyJy#5bkRA+e4Z!AVdtBMa4?0Ej=%no>&`@_9BupbU*ClPN(HVtc@0P>#I-%lCz#dPE`0ZIvSTmv#b(%qI7Q zN`Rxmcf9%RcG;^FvoXSP)k0RcocaDTsOLcfbuC2d9xS8-H#G_S^B8L$OR3l zkFe4B3a0C{z;)YPsPzwkODriG_Z zh92D|%0gu5B7;L%7@>qZ#b>eF{v9J@Q4nquu_lx+*kWR|Fx~is4Z$+O#KW9uOl~kk zkyH-w4z3^=H3rnWJIkmP-wIfAqY_qjq+r=5T{Nlcz}xyG#H!bOseNZ$;et{tp;|IZ z)ry&6Qv1c#Puq_XAu~hYs8=Q9;p- zzJ%f2YglO=1MV(z6!VJ;Y*b%{v#TCq#g1_xEBQ&!i?Yz*Rf$qV>Qw9dRT#WUiTb8d zUlzDZn(khH86_lnh^;2KQA|*rq-3fop|8(i{`|4B+=XnMDfpIJpVZCXs?bMyG-p6N zx9uK8%mZULeY~)ZpDvd+1DWt3Xc&>jJE_tbpuHZ?nTo@P@A~L!&!OsWwSwUA2E1^h z4f`+Gg6NOM@SP`*=u4kX&yek0eP($sSgn<&`$uw7(Keb0P|<_A?T?9{3A6F)1_kiA zlt|U;&Y%Jw*rD565wK(V)dKQ78=4(pVI4ZGI7fi9qwkEu}^aCZwecqBx zUq+Abe!|x3^e2w}8U&8`19;qc2mEG+Qf?dxXxB0Wma{BA)Vo zgAP7oXz%(O_2e=k^{yqZ=AFXUybtj6*g7~kJeN@R6UDMDReWdJ53l1dg0fX7y7};t zr&bHH)y}O3kEZ<)dY*%~=Jio~1?HmvRv*~2SCU@BCkSj^4>)n?G)%||P~?^fxG7FU zc)l=x5j|n77}E2-7WBY-HVKm3ur}~#k6x+3st}MI^nzL8DT48hP$TSf%#c& z;OXFtRbQ6Em4Vp^$BXdFpbB0&WC!|Dkr>c*5cF$kDuQbuHp)xR8tj%^!ho?6b!*jq_S=dHj5p6jAI>4@dZ$KD){PSrqbmuoo$VNVSDW5` zC>HDdZ-MZ+R$Lt$h#xQYqN0ivnVz`7D$kS2YIM==J$OZ#-Qo&u6EQ&u#?l>;Pw9OJH`D=NB+S7%h z0~|8@?LG3rS39!s@(Z$o)rlg~Ld?g)woq<40&JZKO7K|(`ehs8Dy=v=^(IM9%g-cS zUkQ+xu2hnb1fNxK9UsVP9xw32zDQW@B~Ew8OOju5hN-$o&0LLhn6zwBBh2~klB>l8 zNC6`ga$tG^t_g~POYNHYo2$(Z@-1XP40#5vgTmxT&94UH?HQoMSA!SAUn5UK3ACR1 zg8f=IaZ0)XO&v&R7INUO6ZXM_=qRXm#4e)-hK1v_+K$)Y>=y|3Sg9J;lj;7$) zOIr*s_y%28ytICv5Ph339D9yM5~jZ4M0MC8r7rVzCrm*gTtZ z@2n@pVj8LIg#zT_+Ip<<%;N5Gl!EX~KG@zB3tyP9u9|=hMBrrRj}!vuVBpUaC`}0nR+y1u28MFh3Nj&+U_tr!Pu>Ug!Y#bc681 z<6E%mQVSFWHskEvUs%R)hg7M@ltl$EHIyhpGtbPU#J`4s_JU|Ut(k^PeV1YEw+6~) zK!)y?TS|tDn8AFvH{h}-4Zl3?M%mYa=-DDfj*DjD!2~HXU~4aO&YD7VbOzKLEo+b)CSiGM{nRaY@?Y`AV?e z-2*DkQFv(YE%ve!Hn!j1hZ6I%vDI-UmFQaq1FSauy)=Z@ee~Syt zWzkdg9=ltz9j(`Wg(LkP$ex&iS8J!>s54i;xYCC6S^b!|stN3!y9h6*PArZ=oG)Qd zXdVfodU!+NXOIz|otjB3H(5`~!a8(3Ax;-L8{m$Go$w*>BPvvO;W`abTF9XopLbZ` zsvAR8y}v54#Pl_$OfSQ3{xG6?6&np|9q>al1^f9M@yBjOyed$N-pk^#M`$Z1*X^V> zKI_IZ0e_g@nS!romLjjRAT_o50ap{x0rf)yq{Y>K==CTe1_~}<^Nx6;S}y>jzl)I; z1xw*HSFgYP-Voc^BN#d;f^vG|v`o4cSf;b_i~ep*yFCTdv_l<&@|zC>t;a^qA5rl5 zS}xAyb1SPB6{b_+Ev~O|1fBpL@M%0s?D7+%eH{Q(BV#CPqZGL~ikEmMtB#&|N%(oQ zJXrh`q}4-u@KMiCur>)nA)Do3A;g{kj_6VLI_u!->l5&SyUxmA%S&dw35GhWQjB+G zfKd1+JTVfC9ur6LMG6hm(}uBS`XIPnFoW#7X)s94BDR@^;rP)ejQp?wZ(CZz4eq}G z`^@7+^Se$W%`1RX&-A8N@HG&!-?~9;AEzwX{dgvo`)uXh3|`Ei zAa~$CZulAq)LcP2ZAug6eDX13*Jae1XvafKV{priJY2WEf_D2?lZ->!C*9W{Gnn3^K+bHop27jIPhH@Qs+UlS%O)aR$`ko`OKH?>o zc(+0ZtC~AMM8KJI)94$05m0k}4aV=uCt!6rX1AsyotO@fg-_zth6o(sNya#T1=@C@ zE?x2F4JEWkl{$Ir8F;zH;yq^t;xe~=`8y-269@9~U~Ul+`PLAd`fYICRDPx!1T)JatJ#}@HI32gu0(~S3sddRuL8?-m z7F(*y9?p@#2lJ1@#X?8w$@+S&xnWByG$5nY4s?fY)$N0ABRWVL$Q>r^9OSz zNi&ZMV&?ib^kB4tPDd2lR#6~cJD(m?mc&~Zj3H(3bmSS^O0ga$;Fi$i)Scl%%vlo$ z_DbS#|BDad<10p=le5Q5Hq!Lx=wYgpX+(9F{h$`_7N%b>I8Ox&XJV;K5w^w7$46he zdW)O~6iW*cgR!@;VE8gjWUOaQvF1}X-f!8;zdVS;JyF;znawC&7YaQN#t?eR47UYn zfxqG{bS}LCMY+Mawdx0!K5GHa5gF3iy+p}S3pHSVi)zN@Cf-af7w&U!n;&zdLmVb;F<~x9v}C#zOVfPzk>v?Fhnc5Y z;mnG?6nkcI0Q1?l4NTXhz4+rsDLx@5x$Bx#W|*rl^KF75(>W@Ysd(lIJky9^@<;K~ zv|}A^H=V^45xoXORq>$cr^5{DJHc$&AIs=0l_qawdNWtOt|;HBZ_AA8DZuAtLZqHc zJ^Cjk;IzFHu)BUclVAG=Gc=KxKD{!Lxi`v@RH?9FN=WH2?2|nxjp}Y-u1iO?L9P$Q zrqfgm_j)tha)|1!uEVj*+W7hVFdknKfbEUp*d8EBU)+=eq^&7l4Ya{u9CfNwip82W5Zc*Ft=%|EG}W|0wY&~m_C1EU_ai9#`#Rxr zWD4(GHDNC?D~1xq#V}9$E902KO%OT3OPjRmqR?azgzf2ZJACe@$&IrOQ zpU0_au0LB{`U>_R|HVgYvz%p=d3gTh|H%*UAO4Hl|2O`N79TcaO@AA%w`5_*-nF#4 zVhh+Al!N%{Uu637Dw1_D32wWuM~#G=D3|nw_!VRUP6>;kTdh7RF4Q306u^NoxslQrbI~JD2T*^|pGrWQ>F91AV}+T~6^h z72$JZS=wOf4W^!WApU7L^Tq3e{xAF&b^ibOFY*ZZGA+;b0Y_pPyy~eWgq_CW$2%vs zO|Lbl=CK{;jNAZWb4~^WPsYN@s`aR;v4_%Y`+$l5B^cDKg$tXuLsjr0d=$}uX|5B5 zK6jr^sQ)s)GyjUXX9y>5PY_D;?g7tb7v|}FBWB&ndAOf{7^7517%>mtpyKBw#(2Uf zu(O#U#>}M2qpnZj=DILOpuZ0%PC}BN`E3`L+6tn-U>%06w7~~oMCk`AqeyOAPOYej z!7~rzIRO@m$m@5A=_7N3YVi9Bx;3jo)lwPyjEvyorz4zS4vw4^U)m^vwh@r`_J?VY ziom5tiqsSPPW4T{4)?Rdu;%+XB~v$>4D9%fE1$=s&Hh^qO)p6r+uwj^)k~1RFb_>? z{J46J3v-t!w;s1w;*0q-RN*x84bNQAO&r4q`wc-%4P9sipwaQm&-uUpNC+7xv z9B=BJ!PWjDXdBf*%sHqGFJAMLtDJwArAa@h?AO(zWotYqdY%b!WWN_vYNI606cV5f z8dqVmc{%1dHQ~~d;~f3%&YTegCGtRCFCkl5#qi%Qg>G%UWQao;E(m*uqX`+GOIm^ID-hjGleN*i=7) zkpo|B3g67U}1UwRF}7i1y3A|6*)WrFFr6DP8G3f?te$2~#qpmv#$o*D=w_P%^c zZ8Up~myb5XT4#dIDv9T)3KYSYN_(b5o(Rcj?Mwv*Hp7`UO?Z2)3@P7X!|^1JazZ`M zvb&Fok%0@;&`?Sl*A88SyY+=AV7~zt=Xb+xvX=<7?1AA|&!MC10rscg1M6jPVXuBZ zwcd;x^FlyA>8bmn17ilF{(SQruy=AIk;; z2{cD@u*!y)0k5Ea`A(o(>ajvB0yLHl zgKULAcy*=&xYuKEY&x9FoI}_he*mWp!!dz7KmAxV2K;*>VCP9;ddGVgrtnK6rl_nZ zmULn>d48GtG0PDaOHJVyuHIN{9tt1( ztT}ymj&s&dzQofCb5V810Bosw4;3?OF>K2R2v<>rIT_NVL2w2de#pXeLj~YhAVi+` zlcf#g%7|g1LqLvS#;G!%)f+;tf})2D^F-WQrfd0~vb9=Ga7kk`D2ARPgs}ya-#miL z3UfhrsSsJ?UxA@(TG8g)dCr;48jz9NM&)_O!0UZ#sM1-*-m1KwN`J{ueiqpY)(Ykz z!<)cSDZdAMXJ262q;s`>@-Ej8VUX+NRRwps-h~y0_kNSIQu&sN>YK-2jVEbRntg@O#w*gdvUye zs=yUKNz%Tjfav*bim7S7lhbH~-yc?Gby)s1<4lN7zs+zhr5 zH;ClpX9#wFGJuvfr}NMWj_!FMiujm^MT>vK*GzSCRa7qIjWCF|Uu&V}gfLm#z}*v+ zeuS3Kf1rGvJ$Eg=8YU2f%A zdN7;uEh&pS>|KPL6+EF>>?gvk7+m#f2_wY&JZGUt7TjO67!NLZ1M}Z$vTb)N5*NSg zf%{T99FkDM&DU~p$)|Wu>VX?n<7|88=F9g{I`tyhHw)19wR;FFBSCUj+5t}A!egA1 zo{wRls6VdVBS60jJ4ihFaTZkXzQUNfDbRS~E*4jPgj@Fn$fYA39E^K_k@pK3ailTuyb$}p7C29=c` z;nZk0@Sj{tMhE+IelL83sZQ^xkh-l<`qq_EoN54rKRQ;gxc7{@>92xD<hAAETzNU(~L`>0W&^k!kBUc zl~XUpj%m#R^+`nxwz`Bi%$p3K5f>tPiz2a8okX1rU#Ri>yyVDUd7#4EF#g#`Xu0po zRE%1~G`j1ELFYOdi&P{?I`}SC?sN@aOv?trnH@mBk%E+Mq3qIib$IsI2~G`HGqc?eQ;F%bfbypG>TjDvVj{JmIU7^eup}SGTK$N@27G$)Z zEQZUA1WBEMqnz)tj-0x8eJEx24)1CngS+$k*!Sv%z+C+z6mhQ=y8R5L$JHDM)cMGb z6NPv}It>rowBw+53-m2o$`B+TgPfr*xCpl5COKE;z$PQ6%RNhYF#Zx1Z)U=b4=T{W za}j5y?Szr~dZKy6gmU8gRS&N!gL!#pI0~}+p=4JP^}0$3we-iqcGV~Di4 zN{hcxVP;#P$x4EBa43bw`8F_p`2c(~lqDm+4iRbPHAo)b!1YCYhmXy;dl8PckUdpL zO*ffGS%sDY6u2<8Y>k-borl4%=@NuoX#;&972$V^q;fij9g%G zuBp7k_bSq)yT%o6tbivj(JX=T``1x(;VZbJBT74z6u|u1d?YzBg8q}usGgQbWj?8* zp5Ke78r-Mw`W6JYBO{>1U^FEqj30V2Hw=qH<;0JfwNYlh0zz4iE*I` zxNWUCc_H^6A@Xh>+TdY`tZPI*rI(oYKA!XKnjUJkm@^%ICga&oKDyw%97LF$1lMhX z_%hF)^Z3ze&eV%LFgU-IyGJXGN#!fSY6c&9@Jk$=ZvBXlzKyYW&(S6_Q>9Sup&FRH z8)Afhio_t>5Q^7M0fbxf&^^W;Y|G8T$Ig|xCfSG?ydkNqF(elr2bvP5%3*lZZVp;- z=d3u@o*<1ViyI8+@#3#aMnV9SeeIkwF2c;HLRGL_rEv?e7sf8~r#Y zYFBZ3egSCmJ%qB|vxrjWJTm@yeCe-B4j$ax1Sz_&h#RBvoZ#5ocs?S8`Ag;vGPit! z=N1S9o6?{r?<0({tU1!#j&nvYG-7t0I-YlXg09|9KnnyAHeB6t+Uf>EM=lIyJ@vR6 zUm4a0C>U^DYp~5A0or!VMcMn2ATK6PS4%uWr?{X>Nabmr2rRw%uU5wB3V?2?pR8AVXfA+Ds*{xdN+2Z8!tD$2k;8Vt;oy z7+E3qbSdKH5@opX{SNy<3mZOoUc;KgPJGLU)aGmVA$}why|dO4zLQ&Vt8*k&Yr0S> zKF4uReGVA2U6?m2jF@|cE1**g@L0$LV3$X;r_AS)JuY@^AKMHfc*kK}En$NOLet2H z1{XM8!sC#UdkQGGN>KewQqB*Zpx5syv8q~-)|H)Bh^0<173z#Ky%E68S-rnQ}bE^#QRwDV3p-sDz@F43!3vk|}ePSt3&?CBwDXLFO?- zQHe|;i6o@LbM?D_|L6VP_y6<$pU?Ze+hc;LruLTBXYE9EY|YGV&CRx2 zn%axlaIMg{;g&lj!V!JKR7v5Yx#dX$w@k4)Z^^ZEoEluofBrG`B zvf#7$OO}$2q=lgNT6-I*f5~vQk=EvRwVCo4UdG;Ls=m#%f8Wm9|GJ&&f0MA*W`>2} z?m}UEo0)&9vG$hDERHrDHD>=MW{$nhTz#8)|5jt|Uuw+%n~-%j3;t4L;lI^b^hb@w zf8m$d+bq?$S@v%=*8P_nvVW7X-ex&RjUHZm8@WFsrfPH4Sn-z{EB_L+%HBp^-)8l{ z)mZnJ8VY|CqHLqcQDdsT&6}aF@uQTWEjw|SD3krR*9agjE;o|y}b^l+xuLRe$zja^5HJV$b|Iv9lJ=sjV zo!M!1lac>v%tS>9=e7zwWL`bo%XG)gLDTw;%rU_!YHJKmGuyLoGN*5y1AzgvCRxPD>K8;}BZ+yj= zNB>~N_+K+CvsrZWlKHtkg|SSb+UndQRey&3nv=WuOE2?0erayeXHhlp_alt8Nf$~x zzF_PledtK*7Ft~=m#Ns*g41)#81>f+)V3)KFb>XU7^b``*E}?Y-uZ5ZTG!q8^nv-V z^h7>)?sU5cbZg&IwHWIrX2C5r=1HhIov3!0Jb8bQ;VOKA4X?8qZmS9SUbsA$UjLZZ zu$+@iiGD-*;#;ukD34m**X3&3SFX`tc5Y`pWW(vI0ewhIKf5;c)mCt?WafMcqTkGXfN$>^G8Wqv zF<0{oQ*Ts6`&flAqgq~YD)lkVTNHr?K_Rq*t*qLiW7$m8(lNrdQZYB%&KL4GCez;h z4YY=yH>x#QqW2pwCOeKRw_I9|o|U;=?c&%PwWgyfjErFgQ~6avZD_y9zv?YQTYO$A z=b`(P|EGGR{$6iuHMea1|6FhXRg+hO3!wT{B`WSsLRsx9oc!GiF?(-<_1b%EF%u!G zrv4+fP_Z6lza&x9GY!$y>^ob03mcjIXXxM228(u2MV$r8pipuP*UGozqKP0P{jC%} z_7B3;d+Bg^t2o25+z+pBufTbsnOLnmhD&yQfMN3>igm~tjStR*18V#X|3yd2@X11I zR?7&KH;uxq&JnQPYJ_SP!u0Ful61K4N9uEkAqGdxLKo{&xZ?8!yq~`Y?@jqA)YO9h z3mSl@FcsHqzK$ErlSzH9Fdb#Lkht=B!2DALJHHOWqW7*;lhO{5pU|dcFNx7d+iwtU zVJSLiun&5-e}*GlrD(T<2~fW!1CJNip|P_uUNNnvd?j1KVZSgVrzS&v;Ce`&zsQF0 zmO#iha)*Tp)i}&^jh*({7HxO;ax`%H%@CBLa0+hio@@ZaCS$hHMG zeHO&6r%G|bBTwp~{R@=s>jZPNA)r?50?|7&s4wYnA-J)KI+)InX~zWVRU69j<-BL$ zl{N&9ZD%lL%LIP3%7XmF&rmB1Xp^dmpBF_Sd%iDx{z#L_O}tEt@-?zjPnOlyR0m#? z39vBz8hD?OppOoYVvvR>7tp9Jd?znmdE_z|HAmbCyH;7Xd>JnzcOn$DceWvKqz_)b$xr06uEWis2aqlkOg5%{qq;o8 z;kgTgV(%l#j|Brn=TITO&+>#2w?61QTMsXtM=^2rZpf43r=K3`1!uV`cA>^)YN=Z? zmX0|Q9i#oQDV)=m;7%o`1mXCjUYOh1i5quM$JKk>arU;C;9ww1$qH@2{hL4J3@S-7 z8=q#v;G1Yr5g)?hHsi>=t7 z9j>9mV{Ovfkpy}_FJaubnRxtoF+`T|GK{`D-gk1tj?i>mI&2JEKMB(7jc z!>vPVV0K|MxRe!w>%--^N|5u+yC!3GT053_%vN={S^$paKd9cCY?8H)i|%-pgl|?i zqxv~dT&-is>hY*RzdfxWc$r1MaA%_Ws&shE?xH5+%Sigq8*qK15QaRG@O8E^c>S1< zdI8-;xjzrR1@_=J_c5$rc^4&ac!8IdC{wC(k8u6WgM^B=kkY;aQ%w`F?e#5a-t!7& zPc-AK#ek>zUEs`;k3@3*TWUJJ8*N(lLH3{k!~IDHWQ?-${!C%CO>csh9R;xWX9(I% z&fai7FZ?*e?mS@d+?ipn#)U^}u)C zANsDsj4IVr3O|>+ybk999jLI-%r(?0no}EI><}KSPyo9dK@R2kuUd#TR5QKGj!7)o2M? z)FA=FxCL;|Q7+nPDi`f$`T}zx5d--w@g#RF`jx+?I#f5n;*$NaTTFy;7`=(D`@|Wy zeIw*#&H(w+R1FJa+d-iEDjE9h3kHb+P!bdmrN>0+xNRd)95EeEtXf38_Buj@G#hzp z%JBo$L^Ws@;D_Sbs@>w5xH0P-2{LF0{pT7Gq-_9&w;VvdWe@0$9mY)y_o7^{H)}zt zD6OQ^jk_dym<<&{5H;cjF(#?-?P5NPLCe3cMQ4c5Sd*hd@dh-F( z6QNL72)ITr9%)*V*`||^bLNXP*Oq5tZ&43!f5t^0dcOx+t|jAs4PIt;iXd$X@fc*S zgYlaJ;Fnwmrpr9TXt5!ZD_oHqg5;j82+fwhgb$J;pgZa@rfd=c`+hcx zjSS#x@pdXSUkhKSNRb~c=OFM67rkTaILywd+&CQg2{lTVz))o~URlmd2C_8p?nDzF zsIx|cVHZ_LuP9V{6NNf00G1WyxZ#ruz8CVuU2~&ZvKv;w_P9=X=~<3OrwVYO;1wL3 zA3)7rJxOIvDB~{uPPqM897HTiL2~na(t11^so$R=q__zk7lmNw{X#Taz7c=BjKY;W zf*_CUfSl%LCImAe;mjqtnNk6T9#6@ZX(HsfrvTk+>q9-h_6SSnlt2&G!QCZK&?ke^Tydd!4*JWBV@|v?C7yd zZy$lv+Uq&odAD$P)+D)eD+>n965&oH7bCt{j2?G+jNb;ng1cooj7{w#Cl4@aF!MLY zy%xg*4_YzrY8onV_2Q=&*xAJs{%3aS_Y}yi@4F*6QsrW;h=*rGW*A|wjvp(t_=g<--Q_NB}C8AYk-}6 zBd~U<0Ml+<3gHeBxOkcvOoLD`Tyux~D8GZI2Sn(|oIuvSXfgsteGkcSO@YnDQGe<`{ug<+sUCCH2igRCVNeY-ZE z-7Viw*8LV^-bF7W**@3d_mgl)>|BP9uLU5U)6b6OvC$Q#LYZFt`Uo6OYC{=;q9X5*RUB_3~D#>I` zC0yKgGVEq#HkJ5~$G?(j)UP_Y!e4&TJo*$;_CvM(&2H38rDheJtgNDDO@PUtV*ka?3w)Zau;hVVaE)%%UCfQKDU4Zhig<} zP61p(&YF004nUwN`|fr@y7_}WtZ_UB8y3A|M?~~fLYiNYHC2Ru7b8XYb;n`S7g<<6 zzlvOU6r;F4eusB^9>9@nHIP)*M%AyX#w_JX)LR}5{ax4C>CeBCzDq86?Qc_o!)rF@f}<;EM~dN-lO)P-ww65 z9h3l%55@o84O)5%Vf}$8)XE#u)P%GE9-7??MfKZYp?(i2omfU_s7C!g2Z8m|6Nq6T z>KezuE4PEBG<_DR&XpkpZ*pO7>>#z)<1w&#dFf1>S5K>I;w@Z;(GPRaB0^P zDDGE=t8Huy3w?^&W-Ul*g=1O0E=>Qz#So!Uj8iS55~gLL?|D;r!f?|C4YnwIUYJ>D zqC^f~;HC5P{ebtwMv&UD1_d=fL12bA>@OIGqcc5OIctNcJpti3TK}1v8|6u6Jz+>W z6NEn&eF5cL-4JoT606?71wGS?pl`v&EQ_6mN2^@$?hPK=VdV{Mx^)-EPn-kco=vd% zGA}qjO$AHt`7q^<6s;UK8-#EIeXY~Ul5ipBUcVnMTCo!o?heB0na{z0Bn1Wbi@>$5 zyl~z~6b#$P@#f4xvcjPj0xjL4RY)23U0nb+YH?Js-A~jI{>47=P!g?HpMfVzF&GeE zM=j1;0OlK_p>m9$nehIF(`1DqV%8EE4dJ1Aws6x*ro!~^8(fUHdM=EL+yd7L0R(YP zxN*FZvjz~QXY1Av+>EN#o~>u*~5x)|`$b+kL`FbN@c{GKtSQeI%3RrK65xGU5zx?kjlL zR7z5F1?U{zD$EF+hE>l*>8xAl$QX|}bFr`vCYTn;<85QDCJ`W0EQEur6F@j!g8sR$ z6Vg9?fq}F9=*(3EO_W>sqNun+Ebb;tL3MgkgmhKmEuh4*Dv}N!bQ9+`3APlCq71pppla;UF*L*|L@d zmT9rBrzlYN=Zet9Lzo$mHUsr7($uP=ZP4BAN^B|m%3*KyYRBpQ!fYkIw{Wkb5TtIo!AsR)nDw*=0t$HPvgu!`vY*}{ zNjJiXpfN5h4?(fHp6qRvdFXn9ht_A>Az!qEl~ch@KDPy+`sG{j-TWcz=81Z&lNiKb zhrY1=jA%F+d7ZkabQzvG3DeEL@-d)T2k%^+3I}sGK}y;*Qc`~tez+VVqEZzYdrXop zX&fTTGo_F@Uj$61JSJW`W?1M`RU~2VcvZ(67D}9=*}T^!t+3!h8W-vA-5=@4CQPk0GX+Eyd|-GU&eM z7mRPnhhOH)v90M8xo>L3SsM%zy=Ui}H_vguq*uYWIEmE6Ul-!m!4 z0s&@sQz|CJH{$i5>d?FK0j_*>9ZXku;FZ@RjPJw-FqI!uO*Xm+yU7xmIIcs@uV{da zK`(IVyc`t2OD5|Zu7lGa$xXsJ=sbg#}Pc-xF8m%fZ`{UI=QqOU+UjVj4$mSU7fV86|CiP9L?|*R=u{77Ha!=2}l+zB$Rtt2fEfE|D7^CUCYMXJ@3Ia;Un&T<4@MTjKQ5|Wn}5KOdR%BVyB#6 zONA(pp^n52FnQrltqvZ67%~E3S!-dpUmfP&zDa~ z-KiW7?tBb63*CTx&V}(?Z{Vh017%rU&WezK4LTJA(7*EngvlQTzfKXRW{D$g^l3+d zp%Au0@;#g(cN5>6L=x%CA1Kc~ob~#L8{n;hxRfQpjIHLTitl`+&bW-S7Fr}jM&u_V zA%}Q%N)>|gR-2y@SQ)&run3jo- zS>~@j48h=gInD z5|*R(^9{uvKS5H{BPp3RnV>L7j4}Grg$k?kv2Tr!GWAD_fX%#vd1zTxaX7`bc@Nu%=iqiXgMEow7L419dv8xV_gAJu4-dmGud@ zosxuL(K(ovJPxmueR1t&eq>u0L!p5l_7D5P134#9nI%c*Pg5b3Sv#g5o(U6uU1)Go z7r2J&!T4AdJjm_Cstal0KIbqtJPCoFHBLC>Da=@2tEEi#iO`xk2dKb`Z`9G`28^Dr zLw5dhA%dLsPnUicr5o9fB92^i(ocY+RpNAv_$k=BhnMaQ97ARHBRo8j2hX~$!{#r( zB!SZg+nmx!-1#)PS@ay=WS_&;$rAMMg{ioxCWx|`Z4b7KB$-|%9=bPzV_UK2!`{|l zR8$vW?(ZJ}gOAxHg;RcVa|?B8FAJAAFNU3?-9UISf2G|@2>t)Hfv{jV8H0cCRhEpkj z2M_Ai3NHG7qb>Hjhrs;Bv1oYFjD22dJz2JCHQ3ZIqxOR^lbWpt8jl)rd6X$0`q_at z_OV#ts{}QTM{)7*AvpIe5&P7$Kt5msFUh}x=%yRkT(k_9E;|dE(R0A%suKDQSW?!8 zk?h`|(vWk%4{Mi|6`*BU#IqH4q0(?0zj0Q&|AwsyA@*YfwX+~>s`_XA6 zwP7l@Jo-xJ*on|;u}|4Q#7~j#pER7~eD}8V2EE_qpkS4OFoQEbSbt|nroU3ojraj9 z6E4)1X{WeU+#tid0zH&<@yfk?qFyuvsXn<_F`h{7IOmhT=a#rGb{AY6ZpHhBeGvb8 z3|q!VLC#kc=5KrlP3?{t(?3j|81KfN$3ii&PnbSmT7c7>-a|)DCmI;Mf~-T67!g*6 z$27X3eIx|0mdt*xI;h!(W!H;I zJfAqNP$UY=g*<_4Zz6o1my94rL%mxUrbrCowYpMhkW53%6*GtzPbgLNYXKPfj8VpU zPLxVYJzD#V(|0@^z-+vj?ND2U&HQRmFsBAJcYg*lW<>&acH=f(2D= zvA0%JC7ZW{z{7Hw6{SPY&LAwFgEKMHPZ!y@XOi#~gz}6%&{sA9_~9*FJt@xEnT#SC z;@G!u$l+#he>`sw?839lVB}O380$r1)e2|4vMdjusY=j(ZxJ(1M{v@Uo6*#|iYMeK zT<*+A*GtQhuv=VoT4D>9&kzB-mx9b;g+Xl7^@rY=KY&|R>sZGhHSThQtj4LUq+hWLADankjN`syLdqK0o1Ne@6;>o5{kU2gD*(QbXCbAXc zc0OmPIXc2kqcm1PZzOJ)*#?gcN0HUb&lEZxq?CeOV9lp7_NsHDET{Di_)G5#W;#XV znUQw%=1+mIC)dM~Nn4Du>m$|6#ThZvD$I7f3$^1ZaCk{D@C$mvt|C zym`hd^LmLo8w8j-$s6$W;ccka=h&ZXwMb^`C(3=*M-X3q4}E{X!%u8qd_OH8pG<#+ z)An`Y>Y*r-?LUsAov$E0hl`HAr$zO4RibcI8YU`UghiWIk&1Uk@OU;q6Q(~7()+$* z^h<80rR*a#e>;I(FOR`f%R1PlF&lpT-h#X;H=ymXAATDd#77T$anxiS%A7wzDJu*f z&dS2fTO#mKI){wy{ftJdXTrJ<4KO1c(IM~=skClmhsoE$sL@wo9wg&ueGPKlh7Zp2 zrQnUKU-0bfLl|?pjeg2YFxe*s{8%9v?3e*gkuQnSX=gN_I*n4zzYHz=2GK<2KF+D; zW0W>L1F<~{xMF<<1lxqp-g!1gxD_~Ky-f?AJ0-->Z<8?3q!Mw^7dFT7!J!OQ6s?_u zuU5&j?W|_Q*P1e77WISV_Y{EBwkEPg*bRgo^T2&vfEJ&|#js*MV4ChDV!Q4l@E&ZV z1YC>YYcOZO&O8CdM?r8+D3%JEQw}LZE@*2kMR(~4F*9Gs;ysO5oa?xO{KHX7r`!UR z*Yr^W!=G6{J6ZT%%K=ms-a?eq6x4HM6FF-aC|V)Kn06ELg)M|hMxkIWc?lYh7y;qo zX0AR9PS4+u zn-qm;)v1ECgAF&mHQ_eQ)eVH_)M1!;!3;g3qAB4M`S9`XJ?LFPi0xBDvcgOV1uU5xgffRu;)9upX<~aIv(6A#-xj22tnEOB@8j@NJPNf# zL}{so5tzsO4C+Y*+;$S9#m?p6_Yx}8$c{fjT`bLq<(zSQvCd<7+b9Sx)41uC>-ed+unJb4Tm-%-Ih2-D_EgXQ~E0Of3y znM_BsVQzX;yC*)Hxs&W+kHOQ$Md;Ba$!?Sq0_P{SRLa+Aykv9$6`rQzN~6UnYS2M( zDT~ve`=hX}MuhHHFv5t}SHQ$UgkzVMq&rI!!S=HZ%v^pK8@GR>-UDxCk&%!;WUeJ)Qmq2UiY6uu%Z!WNOmIMgdC3Vv!q70z9UOIWx-~a z9N3dxtli7qsHHi}iNx|A5Ypmha$MemduRiuHTxp$b%J#>EYM-Q4qV=>3u%+1FlA#G zEb0%2@5zfGe%&CX_-FI1`a!pPAEdJevb!kb1|i%tzK&77@Y>(4lfcx|)Hak4PUg>ITP(1-YRp+uhFLvOwE%oqK z>?ZYmTNwB}u|mzg0Z8gJQN+iP;_>+e+CBv1e524w8{xJr$6wbmj+aK(u z%nYu4|An@)PtkQpC`L1~WV4barb}-^nTwrB+B@-$k|!2=+`{2sj!>CDft|0s!Ko-8 z42F2M<_Y3s zdxT`oJUn*r6HNE-h7hlAShG42KbP)8xnNP0YMPFAk#*Giu0c%Z_@C>fR>RfS2s|J# zfT`3%l8}}M&}xq8B~GtY>4yV;EO59P4Z}|f@IAL<)qLxR>92!v_RshD`Aj$L;1;uzvHvUuQrq1dYfeOE>jINC^Q@Yf@+`iaZTnV>`Z^n z@nuzkrBndbnIK8KbzFgoU$x}COE?}`hD4sLegoTE0>qk5A$aoO-AZ2eD;Y^9*~mHP z!mbGzF^OSa+I*iiToFSATOuirO`V91#Y1$Z4N*JNjj@9l=6yWI3ZN*?R>iXQO4r$Ma=GlIy~!nDx+2@sx}1x@j8WdBGs{_^uj z`x%xHYMuj9DjZJI{u4MuPnZdNor>clBDDL19$esSLcLefr@GaAsVV%maBWX1tSa`z zy5v#l_Xvi_J}X#|x|iDjQVfT#rbBVA1zbxLrX_FRfO5V#YDdKlVkZ`fqWUkOhgnB$ z-#QE2^i$YbHxYXbFGJgU#M!dE^twY$S==Jx_;LSx*f%u?qMDpxd7uz2EAoglk6u6} z#+Rr#pC);B0my{*!J_D9B&L$6xhxa6TP(**Z%y#l^O<;(slvSJf1A7mWQA5DE0x1RW(qMXGaxt)(P%IiD=*6M$KB4 z3PpNfSQaU1)RUAwEUv~tG~XWx`Kx$o^V30iZ0-l@#XfHEf7ee^8a2RNN05@^?9F*Q z3C4sx#PetTA^Yke99%sPXA+*n$o>{$V$Dap2obEa3Wvjy63p99XWUl&iM{lc1f#e0 zE}S^DFvoUtB@{QsW8{unEPD8u9A%|onj#k?DLgmA= z&DaHEX!ax>q$+$#wO0yz(V|M6s&E}w9BhYul^M`!QH^#+LaN{He4)(bP2tB1E0Asf zN_|ea4m>yf@D9iK9+GeqEm97Ht=9;sUr7g9kx|&)@{qkf=tRzO=t5O~NoJ_r8TCHI z!?7nP;aZ6oPTMH}DPnhsD9*+c+-0!!D>rkTy%h}&FM{Ne1kT>*3-J9YCVT2+z(%hR zG@{zTXweH0m0ykTi&Chm6-|)&fR`~$DbD}iI5im*|s1ud@?qT80G80IO1+peplg>nOxZ}<_pPWytQKs>xK*^RAn zT~KDd2d5`?K<^59SokaruV(&4_hsc+V80S>_VUuk#Uq&f-3)`}?*l1r0F{w=aJVcE zL^ueh-IQVkb-M8Nj{6Ypkc&b|Ld*iKZ`4WtFRUXVMXxiM3ytQ5lo7{&bB7CY*R*B~ zu+7JPtUz4Ud5+S!Bm=Rn&meY_1B!A<;5_+iqU<2WNOSsL+39^S=b$7#EioSW7O6v1 z%NtBO!SSiw8y4r6%Zym?h)=NeakA3W29&;)Gw}&BnQj@yBbqe)zjtNMVpM`Zh zm0*#uBon`42&!}wk^jVVv^2Si67~lm`*ti}A`lvGBqiJZ<3!%P<+-b`a|Nln-#)&Wk+db|xXyCUc56P6H9va@cvgjyiU}p4^rh z!lP4NDN9Qo(AwZe7G%XxV?Sc>`X^I-Xc|ZH+&l;Yw+Au7H39UO1;D`_6F4a;#0W!xC)bWc){Uc3 zx09P@)rG*^ zc@UgU^MKDSpR#oKVXa@wN6VXgqRQesSgBVA=JVo6dU!Bv=F24*cK#0dIaGkc89rwH z%~_DTdX&RRo8W_lHh zDRcIiNg41;^&{zho`7>qCtwcm2o<+egDRHc`1;~MlPHDvxNuE6Udj%^1+%@-*hmYM zt)1X-Z##;=NPuM4Z-`s_6?AI5u--_LIyt)^eh7##izAM(HT`O_Cs7d&Ty3PTobjT1 zFGW+9+dDD;-3Z4gN5{^F-K}n+s%Sk(Gp16&*?#E$hvlZI=T&3jsZnE9yJ|ITR??UL&HoPwu20dJX zAaOAq4i=WeX|5np59jzGJg-u3&hXRP2YKkI%5r?Oy#lSP>#4v*6}&iQBZ$<0#vOx6 z>`jO6Qh76zvGSQWqqVw#^m`hF!AA30B! zNxy^Pkh^%GiNj|7rI@v#i%N9O z1Yumv+Vf753GO_J{&H$yaXJiA?!LyPnz?wne+UAX#KZS_yrBK+KDdO>z?CY(%!Mi4 zFju$)RtR%3YjSz$8Q0t(%H;tR9e#+hdQafWyFRSxt-}7bri9;JoPKX2gwwAybLK7y zT3}TL5-RD0NUDPNzWsW)a%etrAiXbK&+?qp0Jd4;9Cqv1c-Z z!?TDbaZiq6c;JcWgDGRB=1G0@UJ+uaSvb;-3j+t-yLcw~z!G6Dai_fZQE(VcO3y;Jvt=#g^F(tcC`p z*EPTgjaVEC5TI>m1mJZ=I}o_H0Ga;E&W$YYyKIiDV_;wOe8TUsQ^HhQL*`ab;#5)+BM!mZ9S$vOgRJx&txhq#a1*Im5F;L;RP3f9b0dl%T5nCkFF>jKh@VTKB*8{daJ*<`%{Oqr(3c zc=_++I*~s$R2zA6KPMWR>rd9z=Kgc|-!c9F87?jL=ZC+ge@6KK6aAmDxDtOu=5ns` zpJ>H3|HS@hJnG-E(VTY<{0*!0Pwao%(Eg5n!~YNL+J9pI(~k6a?6KAVz^?lz_CNdD z-?8@;{()WpPwaoT``@vT>3?9A|B3z27UXpE|47Hw{vYhW`-!f$fPnnJi_GWc+|$3) zpI00FN&j{1`167UPO9UG_>(xeKd)8b%25CF$;I{OXI*W6fj|EXasK|4|Eui(0)4l$ Ar~m)} diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/dqn.txt deleted file mode 100644 index 5fdf36ade..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -3673 -4838 -3639 -6374 -3831 -3684 -5078 -3514 -4551 -5658 -5687 -3984 -3814 -5648 -5257 -4307 -4591 -3947 -5202 -4489 -2689 -4799 -5565 -4748 -6226 -3738 -4047 -3818 -3959 -5044 -5015 -4408 -4836 -5579 -5778 -4084 -3605 -4044 -3625 -4910 -4632 -4809 -3944 -3786 -4453 -4438 -4912 -4696 -4625 -3813 -4982 -3831 -5231 -4980 -6363 -3453 -4560 -6685 -5038 -3402 -4454 -5911 -3310 -4713 -4619 -4567 -4263 -4206 -4378 -4875 -4433 -5564 -5262 -4106 -4129 -5157 -4882 -4535 -5475 -4811 -4377 -5425 -5540 -4792 -3911 -4225 -5740 -4761 -4801 -5142 -3745 -4502 -5696 -4795 -5032 -4768 -4550 -4628 -5307 -4123 -4188 -4748 -4645 -5659 -6471 -4865 -4708 -4637 -5600 -5509 -3480 -4503 -3832 -3737 -4409 -4319 -5725 -6515 -4053 -5446 -2965 -4941 -5770 -4599 -5092 -3997 -5947 -3598 -5446 -3288 -5101 -3586 -3859 -4518 -6418 -4140 -4933 -4662 -5052 -4521 -3410 -4028 -5887 -5271 -4671 -3737 -5439 -3979 -4350 -5053 -3773 -3949 -5926 -4498 -5685 -3441 -2716 -4834 -5043 -4203 -4589 -4484 -3905 -4340 -6450 -5635 -5163 -4296 -4307 -4889 -5634 -3946 -4357 -4209 -6334 -4914 -4584 -4739 -5644 -5107 -3699 -4364 -4879 -6549 -5208 -5011 -5096 -4338 -3557 -3474 -4344 -6090 -5533 -4168 -3258 -3735 -5127 -5884 -3048 -5141 -4231 -5224 -3882 -5509 -5440 -4016 -3237 -4593 -3523 -6214 -4878 -5478 -5166 -3741 -4435 -3564 -3794 -4308 -4780 -4145 -4728 -4388 -4801 -6023 -4652 -4751 -4593 -5272 -3727 -5220 -4982 -5265 -4520 -5439 -7399 -3884 -4579 -4043 -5800 -5452 -5448 -4426 -3373 -4976 -4781 -4676 -3874 -4736 -4075 -5261 -4084 -3750 -4506 -4067 -4033 -5282 -4188 -4955 -4032 -4542 -4821 -5110 -3868 -4656 -4392 -3436 -4422 -4627 -4727 -5297 -4477 -5707 -3228 -3951 -4526 -4639 -5074 -5099 -4035 -3982 -5132 -4707 -4996 -3402 -6289 -4975 -4421 -3857 -4268 -3881 -5474 -3715 -5720 -4749 -3274 -4795 -4776 -3101 -3718 -4333 -4267 -4138 -4781 -6304 -3272 -4228 -5880 -2709 -5154 -4099 -4489 -4734 -4034 -5311 -4959 -6025 -3916 -4616 -3800 -5223 -4545 -3762 -3955 -3748 -4209 -5254 -5392 -4628 -6101 -5615 -6643 -4085 -4775 -4073 -4681 -4375 -5117 -4563 -5540 -4245 -4808 -3597 -4280 -4162 -4476 -4568 -4321 -5012 -4966 -5655 -5724 -4389 -4249 -4377 -5251 -3332 -3096 -7792 -5312 -7102 -5052 -5055 -5766 -4748 -5331 -5349 -5392 -3821 -4741 -4718 -4778 -3911 -4586 -4345 -5200 -5029 -5712 -3668 -4909 -4867 -5028 -3936 -4739 -4657 -4869 -4680 -4685 -4093 -3869 -2704 -4720 -4537 -3583 -3487 -5604 -4776 -4402 -4068 -4291 -4553 -3661 -4742 -4641 -3118 -4297 -4372 -4273 -5508 -4892 -4570 -6109 -4063 -4430 -4241 -5021 -5052 -4810 -5884 -4751 -5799 -6069 -3631 -4845 -4522 -4700 -4924 -3612 -3959 -3752 -3683 -3712 -4505 -3699 -3848 -4279 -3786 -4341 -4542 -3117 -3633 -4136 -5136 -4229 -4164 -3413 -4401 -4444 -4662 -5449 -4768 -4396 -5271 -5292 -4971 -3884 -5196 -4975 -4854 -4085 -4435 -5876 -4030 -5524 -4921 -4073 -5444 -4383 -6672 -4176 -5497 -4675 -5792 -2922 -5853 -4682 -4741 -5807 -4749 -4471 -3790 -5072 -3775 -3682 -3372 -4303 -5848 -4753 -4473 -4809 -4949 -6554 -4848 -3554 -2837 -5917 -4575 -4776 -3027 -3078 -4768 -3595 -5996 -5002 -4106 -4492 -4890 -4325 -4164 -3528 -4379 -6490 -5341 -4544 -4261 -3020 -4208 -5551 -5245 -5447 -3503 -4939 -4628 -4921 -4564 -4298 -2651 -4654 -4504 -4030 -4928 -3389 -4655 -5692 -4794 -5379 -4259 -4933 -5221 -3536 -4593 -3910 -6620 -3520 -4187 -4331 -3713 -3812 -5264 -5114 -4748 -4629 -4925 -5173 -2990 -3346 -5329 -3070 -5088 -4413 -6886 -5352 -3680 -3908 -4506 -5192 -3205 -3225 -5533 -4045 -3611 -5787 -5574 -4449 -5028 -5411 -5100 -5056 -4807 -4717 -4875 -5610 -4732 -5070 -4555 -4781 -5598 -4943 -3706 -3847 -3113 -6998 -5562 -5176 -4744 -6094 -3109 -5494 -4389 -4541 -4381 -5907 -3408 -2916 -4870 -3813 -4986 -3457 -4974 -4443 -4840 -3331 -5838 -4182 -4165 -6718 -4530 -4048 -5232 -4950 -3672 -4167 -4954 -5092 -5526 -4374 -4965 -5527 -4458 -5568 -4711 -5186 -4094 -3581 -4472 -2985 -4934 -4410 -4918 -4054 -3932 -5200 -5678 -4953 -4551 -5118 -4404 -3189 -3554 -4312 -6218 -4557 -4458 -4421 -3590 -5086 -4259 -3929 -4865 -4564 -5354 -4430 -4381 -5030 -5670 -4186 -3343 -4903 -4004 -4919 -5414 -6727 -3095 -4647 -6198 -4123 -4028 -4456 -4207 -4010 -4013 -4400 -3740 -5461 -4874 -3552 -5099 -5117 -5494 -4723 -4017 -3415 -4976 -4977 -4421 -4989 -5399 -5882 -4403 -4380 -3196 -4592 -4522 -4311 -4551 -5841 -3194 -5389 -4488 -4625 -4632 -3766 -5315 -4983 -4676 -3940 -3797 -4209 -4032 -4924 -4653 -4883 -5742 -4739 -4833 -4830 -5243 -3979 -3212 -4364 -4841 -5227 -4088 -5225 -5333 -5648 -3431 -4291 -4942 -3680 -5327 -4652 -6262 -3789 -3730 -4584 -4768 -4251 -3822 -4906 -3449 -3344 -4538 -4268 -5373 -3758 -4572 -4825 -4111 -6319 -4766 -3887 -4233 -5950 -5246 -4581 -5545 -4522 -4489 -3583 -5025 -4150 -5473 -4067 -4704 -6397 -3004 -4438 -5469 -3960 -5530 -4223 -4656 -5786 -4685 -4434 -4215 -5453 -4946 -4246 -4728 -5306 -3390 -4575 -5668 -5228 -6452 -5828 -4312 -6159 -5948 -5107 -3333 -4038 -5110 -4721 -3478 -3897 -6104 -4766 -4898 -7471 -3911 -4007 -4156 -4079 -6001 -4306 -4676 -4482 -4499 -4124 -4151 -6472 -4498 -5514 -4401 -4811 -4029 -5812 -4033 -3391 -5185 -4381 -3749 -6105 -4035 -5867 -5371 -4848 -3440 -5668 -4713 -6354 -4914 -4775 -4604 -4025 -4935 -5608 -3812 -4770 -5343 -6120 -3346 -4784 -4219 -4795 -4647 -4141 -2731 -6531 -3957 -3468 -5813 -5973 -4225 -5050 -5213 -6564 -5951 -4721 -6105 -6067 -5426 -4625 -4205 -4642 -4233 -4057 -5032 -5352 -5634 -4106 -6428 -4981 -3007 -4132 -3663 -5732 -4522 -4329 -4761 -4708 -4584 -4139 -5926 -4212 -5134 -4990 -4336 -4016 -5152 -4042 -4037 -3740 -5509 -4502 -7864 -4467 -3969 -3628 -3558 -4779 -4917 -3282 -6353 -6205 -6099 -3427 -3761 -5286 -5415 -4684 -5788 -3724 -4570 -4851 -3872 -4669 -5502 -4375 -4376 -4376 -3541 -4738 -5896 -4386 -5369 -3989 -4216 -4151 -4589 -5137 -4353 -5066 -3715 -4900 -5874 -3695 -4505 -4010 -5847 -4100 -4855 -4925 -4412 -4517 -4768 -5684 -4765 -3536 -3591 -4407 -4826 -5624 -4785 -4384 -4005 -5436 -5186 -5786 -4182 -4469 -3782 -6151 -3385 -3839 -4515 -3860 -3268 -3729 -3969 -6050 -5299 -5621 -3755 -4005 -4029 -5195 -4004 -3599 -5007 -4959 -4195 -3339 -5093 -5612 -5215 -5880 -4811 -6285 -3373 -4311 -4807 -5422 -5052 -4382 -5984 -4800 -5622 -4610 -3763 -3291 -3766 -4661 -7150 -4814 -3653 -4879 -4830 -4618 -5206 -4022 -4741 -5187 -4272 -4398 -4441 -4225 -6681 -4985 -3777 -4171 -5580 -3239 -5062 -4914 -4740 -4863 -4789 -3302 -5590 -4136 -6094 -5357 -5546 -4926 -5320 -4126 -5656 -3892 -5545 -3069 -4937 -4779 -3986 -3620 -4499 -5252 -4567 -6930 -3869 -3183 -5352 -5280 -4731 -4980 -5295 -4772 -4767 -3674 -4758 -5088 -3918 -5108 -4847 -5406 -4558 -5213 -4724 -3886 -5698 -5038 -4736 -3327 -5511 -5515 -6043 -4127 -4413 -4956 -4114 -4624 -5855 -3736 -4232 -3468 -4556 -4730 -5296 -5262 -4685 -6613 -5853 -5368 -3793 -4664 -5206 -4660 -6256 -4619 -5442 -5434 -3812 -3379 -4216 -3944 -5332 -4914 -4558 -4776 -4860 -3867 -4407 -5373 -4072 -4394 -4354 -3536 -5498 -3611 -5094 -4993 -5513 -6898 -3823 -3499 -5270 -4254 -5344 -4495 -4457 -4044 -3730 -4362 -4479 -4539 -3246 -4668 -3432 -3001 -6001 -3756 -3806 -5484 -3873 -5684 -4441 -5735 -4447 -2974 -3296 -3947 -3897 -5593 -3596 -4574 -3239 -4262 -4347 -4435 -4968 -6182 -5965 -4562 -4739 -4295 -4851 -2760 -3750 -4326 -4652 -4133 -4254 -4901 -5033 -5555 -5073 -5295 -4595 -6011 -3607 -5708 -4802 -4576 -6403 -5590 -3565 -6225 -3989 -3967 -4182 -4453 -5178 -6391 -5301 -4050 -3584 -4130 -3911 -3758 -4099 -4552 -4689 -4413 -4652 -5038 -4571 -4707 -5176 -4894 -5091 -5643 -4013 -5599 -6255 -6120 -4516 -4186 -4505 -3743 -4680 -4687 -4605 -3393 -5986 -4791 -3752 -3601 -2883 -4858 -5759 -5004 -3891 -3899 -4909 -4967 -4736 -3943 -6094 -4557 -5154 -4147 -4911 -5822 -5817 -3598 -3644 -4695 -4113 -4199 -4078 -5731 -4876 -5001 -3706 -4374 -6820 -4232 -4758 -3975 -4546 -4100 -5591 -3673 -3681 -3441 -5463 -5070 -4301 -4174 -5480 -4233 -6953 -5076 -3967 -4374 -4957 -3890 -3677 -4165 -4881 -4355 -5048 -4122 -4998 -5522 -5716 -5784 -6394 -4403 -4513 -4687 -4431 -4809 -3624 -3686 -4883 -6790 -4819 -5173 -4845 -4667 -4642 -4720 -5959 -5504 -5530 -4274 -4356 -4420 -5937 -4633 -5327 -4078 -4623 -4749 -4932 -4723 -4147 -4644 -4415 -3492 -6779 -4293 -4493 -4906 -4092 -4971 -4888 -4045 -3332 -4842 -3364 -3849 -5664 -5078 -5442 -4347 -3695 -5025 -4662 -5014 -5425 -5580 -3999 -3430 -2720 -5705 -5173 -4219 -5291 -4319 -4810 -4721 -4157 -4604 -4513 -5353 -4668 -6339 -3243 -3099 -4519 -3285 -5138 -3263 -4924 -6630 -4834 -5573 -3590 -4191 -5906 -2765 -3911 -5155 -6023 -5147 -4017 -5038 -5723 -5575 -3757 -5184 -4871 -4008 -5326 -4674 -4534 -4353 -6389 -3992 -4039 -4368 -6517 -4522 -4016 -4715 -4515 -4875 -4708 -4746 -6059 -5561 -3579 -3408 -5881 -6214 -5467 -4504 -5545 -5508 -5628 -4102 -5600 -3367 -4575 -4877 -3717 -4238 -2602 -5102 -4026 -4512 -3096 -3963 -3892 -5057 -5198 -3800 -5187 -4377 -4442 -5255 -3916 -4998 -2534 -4174 -5012 -5419 -4212 -5211 -5898 -4223 -5144 -5256 -5144 -5395 -4671 -4099 -3926 -4679 -4192 -2884 -4955 -5712 -4390 -3558 -4671 -4912 -4035 -4432 -3753 -5506 -3480 -5343 -6062 -4678 -5163 -4734 -3884 -4158 -5228 -4360 -4851 -3442 -4302 -6567 -3967 -6087 -5224 -5303 -4835 -3184 -6299 -4306 -5184 -3814 -4676 -4759 -5817 -5192 -5015 -3566 -3720 -4321 -3579 -5985 -3608 -5227 -3584 -3954 -4902 -5043 -5417 -4188 -5922 -4083 -5458 -3128 -5623 -3317 -5313 -4059 -6148 -4303 -4300 -4491 -3686 -3971 -4140 -3797 -3988 -6142 -3750 -4678 -4754 -4437 -4595 -4412 -4085 -5647 -5072 -3501 -4511 -5906 -4114 -4308 -4627 -4334 -5677 -4431 -4464 -4789 -6011 -5481 -4840 -5921 -2795 -4237 -6419 -6277 -6766 -3114 -5319 -3072 -4476 -5639 -5472 -3413 -4143 -4139 -4445 -4770 -3157 -4439 -5169 -3955 -3249 -3607 -4783 -5427 -4107 -5522 -4351 -4801 -4117 -4356 -3541 -5496 -5222 -3936 -5185 -3911 -4753 -3795 -3978 -3382 -4392 -6289 -5826 -5785 -3824 -4555 -6084 -4034 -3444 -3649 -6124 -5530 -4929 -3710 -5908 -4075 -3508 -5286 -4504 -5037 -5583 -4167 -5829 -4417 -3541 -4016 -4593 -5880 -5212 -3282 -4874 -6751 -6372 -4371 -5442 -5813 -3760 -5880 -4473 -4014 -4248 -5977 -4170 -3399 -4028 -6329 -4159 -5081 -3936 -5013 -5788 -3905 -3797 -3959 -4740 -4981 -5663 -4375 -4759 -4154 -4169 -5043 -5005 -4216 -2794 -5407 -4178 -4575 -4156 -3480 -4007 -4119 -3415 -3673 -5582 -4110 -3045 -4926 -4669 -4279 -3787 -4145 -4889 -3078 -4910 -6480 -3951 -4835 -3510 -4603 -4578 -5251 -4579 -5025 -4809 -3536 -4152 -4882 -4161 -5001 -5092 -4342 -5034 -6110 -4617 -3126 -4592 -5020 -5573 -5134 -4842 -4303 -4999 -3561 -5229 -4953 -5700 -5246 -4381 -4471 -4368 -5695 -4864 -4794 -4398 -7550 -4921 -5817 -4450 -4828 -4104 -5346 -6182 -4725 -3926 -3944 -4504 -5300 -4377 -3609 -4861 -5907 -6161 -4530 -3165 -3468 -2710 -6651 -4338 -3767 -5409 -4394 -5996 -4253 -4641 -3901 -4008 -4498 -3669 -4637 -5709 -5239 -5523 -5882 -4090 -5276 -2948 -3276 -4949 -4054 -5032 -4122 -4728 -4497 -4460 -4834 -4443 -5381 -4673 -4475 -5288 -6136 -5215 -4683 -2991 -3948 -4374 -5026 -5341 -3749 -5137 -3838 -3710 -4722 -4006 -5282 -4048 -3947 -6300 -6528 -3495 -3749 -5347 -4940 -5560 -3532 -5783 -5306 -4842 -3825 -3274 -4290 -6119 -6115 -4457 -3776 -4015 -5526 -5986 -7455 -4588 -4369 -2924 -4029 -4492 -5271 -5632 -5849 -4885 -4663 -5596 -4779 -3126 -5016 -4110 -5223 -4303 -4373 -3777 -4449 -5093 -5890 -5014 -5511 -4242 -4686 -4213 -4240 -4720 -4332 -4135 -4583 -5059 -3594 -6667 -3416 -5114 -5198 -4259 -5436 -5360 -4482 -5516 -3421 -5672 -4710 -4603 -5462 -4106 -4502 -3545 -4582 -6360 -4512 -4783 -5422 -3792 -2972 -4596 -4729 -5617 -5088 -4729 -4403 -4768 -4701 -4200 -4083 -3309 -5614 -4114 -4094 -5443 -4481 -4960 -5668 -5324 -4758 -6068 -5329 -4601 -4701 -4671 -6002 -5018 -5524 -4701 -3620 -4863 -3665 -3472 -3966 -5972 -4913 -5347 -4662 -4762 -3931 -5038 -5311 -3713 -4656 -4627 -4240 -2996 -4211 -4466 -4987 -4321 -5006 -4987 -4041 -5199 -4831 -4321 -7083 -4012 -4509 -4246 -5731 -6028 -4466 -3584 -4864 -4458 -4689 -3688 -5041 -4802 -4645 -5660 -6151 -4579 -5096 -4744 -4920 -3096 -3523 -4702 -4291 -2502 -3970 -4076 -4822 -4233 -4580 -5241 -4983 -4977 -5365 -3971 -3254 -3721 -4764 -5991 -5253 -3536 -3915 -3575 -5051 -4537 -5224 -3723 -4507 -5235 -3639 -4905 -5209 -5096 -3741 -4422 -5712 -4326 -5269 -3533 -4542 -4899 -7071 -5317 -3921 -4034 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/optimal.txt deleted file mode 100644 index 4f720135a..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -2952 -4838 -4023 -3836 -4810 -7660 -5078 -3743 -3639 -5658 -5085 -3984 -4396 -3184 -5257 -6145 -4502 -4931 -3973 -6530 -4127 -4799 -4253 -4748 -6226 -3703 -3543 -3818 -3818 -3203 -5015 -6043 -5144 -4998 -5778 -4084 -3605 -4044 -3625 -4895 -5246 -4540 -3944 -5502 -5108 -4437 -4712 -4696 -4625 -3813 -3477 -3831 -5686 -4230 -6363 -3834 -4560 -6685 -4966 -4026 -4454 -5911 -3310 -4713 -4701 -4567 -3878 -3971 -4378 -4875 -3640 -4813 -4825 -5825 -4129 -5420 -4715 -4535 -4730 -4811 -4676 -5425 -4408 -4564 -4756 -3565 -5366 -5356 -4637 -5185 -5308 -3271 -5696 -2264 -5032 -4768 -4682 -4628 -5307 -5396 -4605 -4748 -4645 -4808 -3901 -4865 -4647 -4637 -5600 -5145 -5448 -4503 -3832 -3737 -4409 -5791 -5725 -6515 -4053 -5446 -2965 -4941 -4714 -4599 -4202 -3997 -5947 -3979 -5355 -3357 -4160 -3586 -5494 -4829 -5275 -4140 -6245 -4662 -4761 -4521 -4227 -4028 -5887 -5337 -4671 -4113 -4937 -3979 -4350 -5053 -4992 -5049 -5033 -4974 -5685 -3441 -3353 -4834 -5043 -4877 -4589 -3761 -5185 -4340 -4354 -4721 -4509 -4072 -4307 -4898 -5945 -4641 -4357 -4954 -6334 -5387 -4584 -4221 -4912 -4231 -3699 -4403 -4329 -5050 -5208 -5011 -5096 -5501 -3557 -3474 -4344 -6090 -5079 -3006 -4169 -3735 -5127 -4793 -3048 -5141 -4231 -5224 -3882 -5509 -3107 -4995 -6315 -4593 -4418 -4714 -4878 -5478 -5166 -3741 -4435 -4756 -4660 -4010 -3873 -4145 -4898 -4388 -4801 -6023 -4270 -3328 -4929 -5272 -6191 -4109 -5141 -5265 -4633 -5439 -7399 -4594 -5313 -5572 -5305 -4162 -4538 -4426 -4640 -4534 -5243 -5998 -5468 -4736 -4408 -6098 -4084 -3750 -4329 -4256 -4033 -5282 -4188 -5141 -3094 -4542 -3101 -5110 -5290 -4649 -4392 -4350 -4422 -4470 -5882 -4271 -3402 -4800 -3228 -3951 -5710 -4639 -3841 -5099 -4344 -2248 -5132 -4012 -4188 -3402 -6289 -5676 -4421 -4904 -4268 -4121 -5474 -3715 -5219 -4749 -3274 -4795 -4776 -3101 -3718 -3919 -4267 -4138 -4231 -6304 -5106 -4228 -5565 -5206 -4645 -6456 -4489 -4734 -4034 -5311 -4959 -4245 -3916 -4616 -3800 -5666 -4545 -3762 -3955 -5840 -4209 -5254 -5392 -4628 -6101 -4953 -2639 -4085 -4775 -4073 -3607 -4375 -5117 -4563 -5007 -4245 -4808 -4911 -3786 -4162 -4476 -4568 -5065 -3591 -4966 -4712 -5724 -4565 -4249 -4377 -4081 -3332 -3096 -5005 -4807 -7102 -3690 -4283 -4496 -4748 -4896 -5349 -5392 -4479 -3994 -3254 -4778 -3681 -3638 -3954 -3969 -5029 -5712 -4865 -3739 -5492 -4307 -5141 -4739 -4657 -4869 -5002 -4685 -4093 -3869 -2704 -5904 -4537 -4924 -4265 -5604 -4776 -3907 -5280 -4462 -5223 -4686 -4742 -6237 -3093 -4583 -4372 -4191 -5508 -4892 -4570 -6109 -4063 -4460 -4241 -4897 -5052 -6575 -5884 -3384 -3982 -4381 -3631 -4845 -6880 -4700 -4924 -3612 -3783 -3752 -3683 -3712 -3660 -5048 -3848 -4320 -5287 -4680 -4331 -4808 -3633 -4136 -4058 -4545 -4164 -5624 -4401 -4444 -4662 -5983 -5058 -4396 -4484 -5588 -5564 -3884 -2971 -4975 -4854 -4085 -4435 -5876 -4890 -4455 -5960 -4073 -5444 -3761 -6672 -4176 -5497 -5566 -5792 -2922 -5853 -4682 -4741 -5134 -3697 -4471 -3227 -5310 -5027 -3682 -3372 -4991 -4963 -4753 -4826 -4801 -5245 -3647 -4848 -5029 -6849 -4380 -4575 -4776 -3027 -3078 -3781 -6017 -4490 -5002 -4106 -3490 -4836 -5417 -6741 -4851 -5721 -6490 -4869 -4544 -3276 -6061 -4208 -5551 -4035 -5447 -6310 -4939 -4628 -4921 -4564 -4298 -4710 -3231 -4126 -4030 -4928 -3389 -6505 -4629 -3769 -5151 -4259 -5145 -5221 -3536 -4593 -3910 -6620 -4369 -6100 -4331 -3713 -3812 -5264 -5114 -4748 -3642 -4925 -5173 -5049 -4756 -5329 -3070 -3791 -4413 -6886 -5412 -3680 -3908 -4506 -5192 -3701 -3239 -5533 -6291 -3611 -5787 -3679 -3718 -4807 -5411 -5004 -5056 -4807 -5070 -4294 -5610 -4732 -3831 -4555 -4781 -5598 -4945 -5960 -3847 -3113 -3732 -5562 -5176 -4655 -3858 -5923 -6299 -3289 -4541 -5357 -5907 -3408 -2916 -4870 -3813 -4986 -5003 -4773 -4443 -4537 -3331 -4646 -4051 -4165 -4961 -5597 -4048 -5052 -4950 -3672 -4177 -4954 -5092 -3540 -4374 -4965 -5505 -4481 -5568 -6077 -5186 -4094 -3581 -4198 -2985 -4204 -4410 -4918 -4956 -5302 -6308 -4258 -4953 -5364 -3863 -4404 -3966 -3554 -4312 -3998 -5442 -5184 -6696 -3590 -5086 -4259 -3929 -4865 -4564 -4036 -4430 -4381 -5030 -5582 -4054 -5498 -4882 -4870 -4282 -4259 -6727 -3095 -5017 -5537 -5504 -4691 -4456 -4207 -3925 -5427 -3852 -5769 -5397 -4383 -3552 -4398 -3936 -4994 -4723 -4017 -3991 -4976 -3187 -4077 -6736 -5399 -5882 -5101 -6113 -3521 -4592 -4522 -4311 -4839 -4665 -3194 -5180 -4488 -4625 -4045 -3766 -5315 -4983 -4676 -5056 -3797 -4209 -4032 -4178 -5927 -3377 -5972 -4739 -5067 -4830 -5243 -3979 -3212 -6676 -4841 -4641 -4118 -5225 -4908 -5648 -3431 -4291 -4942 -5290 -4390 -4652 -4678 -3789 -4754 -5904 -4199 -5540 -3822 -3389 -3449 -4132 -4218 -4268 -5373 -3758 -4572 -4494 -4582 -4885 -4515 -3887 -4587 -5950 -4129 -4687 -5378 -4790 -4489 -5200 -4798 -4432 -4358 -4067 -6554 -4146 -5454 -4730 -3623 -4783 -5249 -4562 -4043 -5786 -4598 -4160 -4545 -5453 -3296 -3817 -3815 -5306 -3390 -4433 -4604 -3910 -4480 -5828 -5594 -6159 -5948 -5107 -3333 -4038 -4685 -4721 -3478 -3897 -4241 -5552 -4898 -7471 -3911 -3875 -4156 -4079 -4444 -4306 -4583 -5676 -5706 -4796 -4151 -5290 -4498 -3559 -4401 -3649 -4029 -5812 -4090 -3391 -5185 -4186 -3749 -4990 -5762 -5867 -5371 -4848 -6438 -5668 -5096 -6354 -5748 -4775 -4604 -4025 -4935 -5608 -3896 -4770 -5343 -6120 -3346 -4784 -4555 -4795 -4905 -4141 -2731 -4715 -3967 -3943 -4818 -4755 -4225 -4783 -5323 -6564 -5868 -4421 -6105 -5398 -5426 -5036 -4009 -4642 -6160 -5105 -5032 -3937 -5634 -4106 -5281 -4981 -3007 -3836 -3816 -3561 -4522 -4329 -5159 -5582 -3516 -4139 -5509 -4574 -5134 -4990 -5024 -4221 -4356 -4415 -5127 -5604 -3991 -3738 -7864 -4906 -3969 -5421 -5111 -4071 -4917 -5698 -4052 -4245 -5243 -5817 -3761 -3928 -5415 -5105 -2935 -5636 -4570 -2865 -3364 -4669 -5502 -4375 -5980 -4376 -5209 -3177 -4460 -5529 -2688 -3989 -4216 -4740 -4589 -5797 -3620 -5066 -3394 -7067 -5874 -3889 -4505 -3493 -5847 -5446 -4339 -4899 -4412 -4517 -4998 -5684 -4765 -3536 -3591 -4407 -4826 -5624 -5376 -4706 -4005 -5436 -5186 -5786 -4182 -4469 -3782 -4197 -4100 -3839 -4180 -3860 -6342 -3729 -3752 -4901 -5299 -5621 -4399 -4046 -4029 -5195 -4650 -3784 -4384 -4959 -4433 -5223 -5613 -3968 -4622 -4408 -5386 -6285 -3920 -4416 -4807 -4385 -5052 -3581 -5984 -4800 -3955 -4026 -3763 -3885 -3766 -4656 -5309 -3985 -3993 -4177 -4830 -3186 -5206 -6267 -4741 -4364 -3908 -4446 -4516 -5621 -6217 -4985 -7210 -4171 -6480 -5501 -5062 -4914 -4740 -4863 -5167 -3302 -5446 -5149 -3548 -5357 -6519 -4926 -5320 -2689 -4814 -3892 -5545 -4576 -4937 -4779 -3986 -4210 -4235 -4360 -5200 -6930 -4293 -5344 -5352 -2998 -4219 -4446 -5295 -4772 -4595 -3674 -5530 -5088 -3918 -4102 -4567 -5406 -3717 -5626 -4724 -5069 -5775 -4389 -4062 -3327 -5054 -4740 -6043 -4127 -4413 -4956 -5211 -7029 -3942 -5805 -4232 -4991 -4556 -3584 -5296 -5262 -4685 -6613 -5853 -3254 -3427 -4664 -4972 -4702 -4523 -4603 -4914 -5434 -5457 -3379 -4216 -3944 -2968 -4214 -3825 -5448 -4860 -5010 -4407 -3883 -4130 -4394 -4354 -5120 -4117 -5851 -5094 -4663 -3447 -4376 -3870 -3499 -4303 -4254 -5344 -5904 -4626 -4044 -3730 -4362 -4479 -4539 -3246 -4668 -4771 -3887 -5166 -3486 -3806 -5484 -3873 -5684 -4441 -3485 -4447 -2974 -3296 -4977 -4574 -5593 -4859 -4574 -3239 -4262 -5863 -5588 -4257 -5360 -5965 -4072 -5930 -4295 -3719 -2760 -3750 -4326 -5827 -4133 -4254 -4901 -3627 -5115 -5073 -5295 -4595 -4768 -3607 -5708 -4690 -5654 -4360 -4879 -3565 -4817 -6400 -5261 -3674 -4608 -5693 -4207 -5301 -4050 -6430 -5657 -3911 -3758 -4556 -4552 -4689 -4413 -4652 -5038 -4571 -4707 -4770 -4894 -5091 -5643 -4013 -5599 -6255 -6120 -3596 -3684 -4505 -3743 -4680 -4687 -4605 -4985 -5986 -3550 -4439 -4952 -4005 -4858 -6657 -5004 -3891 -3899 -3311 -3842 -4944 -2959 -6094 -4520 -4002 -5093 -4911 -4144 -3994 -3598 -3644 -4695 -4383 -3561 -5266 -5548 -4027 -5270 -3706 -4446 -4493 -3399 -4758 -3975 -4546 -4508 -5082 -3673 -3681 -4875 -5918 -5305 -4301 -3899 -5480 -4233 -5272 -5076 -3967 -4374 -4957 -3890 -3677 -5721 -4881 -4977 -5048 -4122 -4998 -4507 -5716 -5639 -6394 -4768 -4513 -4687 -4033 -3988 -3904 -4657 -4883 -3366 -3862 -5173 -5072 -4667 -4642 -4720 -5959 -2875 -4699 -4274 -4356 -4420 -5937 -4633 -5327 -4078 -5241 -4749 -4932 -4227 -4147 -4644 -4415 -3492 -6779 -4293 -6018 -4906 -4644 -4971 -6875 -4045 -3332 -4842 -3779 -3849 -5149 -5078 -5442 -4560 -4512 -5025 -4662 -5534 -5491 -4371 -3999 -7504 -2720 -5705 -4543 -4219 -4510 -4319 -4074 -4721 -4157 -4604 -3294 -3207 -3346 -4977 -5294 -4314 -4519 -3285 -5138 -3263 -4610 -6630 -4834 -5573 -3590 -4178 -5906 -3987 -3911 -4579 -7062 -5093 -4017 -5989 -5528 -5575 -3757 -5184 -4871 -4207 -3893 -4674 -6541 -4353 -4923 -3992 -6819 -4368 -6517 -5252 -4000 -4715 -4610 -4875 -4111 -3630 -6059 -5561 -3579 -3408 -5881 -5082 -5769 -4504 -5545 -5023 -5628 -4176 -5600 -5578 -4165 -5779 -5143 -4238 -2602 -5102 -4026 -4047 -3096 -3963 -3892 -5057 -4299 -3800 -5187 -4377 -4442 -3611 -3916 -5048 -2534 -4174 -5012 -5419 -4212 -5211 -4986 -4986 -3879 -5256 -5144 -4511 -4671 -5126 -4502 -4679 -4192 -2884 -4955 -5712 -3480 -6712 -4671 -4912 -4005 -3247 -6064 -5738 -3402 -6367 -3650 -4678 -4463 -4734 -4272 -5936 -5228 -6373 -6483 -3442 -4302 -6567 -3967 -6087 -5444 -4662 -5908 -3184 -3440 -4306 -4510 -3814 -4676 -4759 -5809 -5192 -5015 -4018 -5638 -4321 -4468 -5985 -3608 -4991 -3584 -6200 -4319 -5043 -5417 -4188 -4066 -4083 -5458 -3128 -5623 -4281 -5313 -3853 -6148 -4303 -4300 -4299 -5154 -3971 -4140 -3797 -3520 -4943 -4621 -4678 -4814 -4437 -3766 -4412 -4712 -5647 -5433 -3501 -4511 -3838 -4711 -3840 -4177 -3058 -4720 -4431 -4464 -4495 -4919 -5454 -4840 -5921 -2795 -4296 -6419 -6277 -4584 -3114 -5319 -3072 -4476 -5639 -3964 -4608 -4143 -4139 -3769 -3763 -3157 -4517 -5169 -5108 -3249 -3607 -4783 -4010 -3717 -4145 -4351 -4868 -3845 -4356 -3541 -5496 -5000 -3936 -4771 -5597 -5092 -3795 -3978 -4511 -4392 -6289 -5826 -5785 -5234 -4772 -6372 -5161 -3444 -3649 -6124 -5530 -4081 -3710 -5294 -4749 -5690 -5286 -4504 -3094 -5583 -4008 -5829 -2931 -5091 -4016 -4593 -5880 -4853 -3282 -5291 -4752 -6372 -4371 -5442 -5813 -4184 -5880 -4069 -4014 -4248 -5977 -4170 -3399 -2891 -6329 -5137 -5081 -3936 -5013 -3644 -3905 -3797 -5538 -4740 -5748 -5663 -4578 -5322 -4863 -5712 -5043 -5005 -4995 -5918 -5407 -4178 -4575 -4665 -5041 -4593 -4456 -4810 -4014 -6908 -5114 -3045 -4926 -4669 -4279 -5433 -3943 -4889 -5080 -6117 -6480 -5489 -5058 -5276 -4519 -5635 -5274 -5718 -3624 -4809 -3536 -4152 -4882 -4185 -5001 -4518 -4342 -4534 -6110 -4642 -3126 -4159 -5020 -4341 -5134 -5500 -5367 -4999 -3561 -5229 -5337 -5700 -3896 -4381 -4415 -4962 -5496 -4299 -4537 -4514 -5561 -4921 -5817 -4710 -4828 -4590 -5346 -4586 -2407 -3926 -3944 -6263 -5300 -4130 -5062 -4861 -5907 -6161 -4961 -4840 -3468 -2710 -6651 -4913 -3767 -5409 -4394 -3887 -4253 -4934 -3901 -4008 -3438 -3669 -4637 -5463 -5239 -5523 -5882 -5232 -3683 -2948 -3276 -3658 -4252 -3439 -5086 -4728 -4497 -4460 -4208 -4625 -5381 -5421 -5372 -4212 -2646 -5397 -3673 -3583 -4485 -4374 -4566 -5341 -3749 -5651 -3533 -3710 -4332 -6246 -5282 -3379 -4311 -6300 -3839 -5141 -5362 -4926 -4940 -5569 -4238 -3981 -5306 -4842 -6042 -4794 -4290 -4558 -3806 -4457 -3184 -4015 -4888 -3580 -4890 -4588 -4481 -2924 -4029 -4492 -5051 -5467 -4925 -4885 -5419 -5893 -4779 -4190 -5078 -3335 -5223 -4303 -4618 -4935 -4449 -5093 -5890 -5167 -4387 -3601 -4286 -4213 -4577 -5053 -4807 -4135 -4583 -5557 -3594 -6667 -3416 -4324 -3419 -4259 -5436 -5360 -4912 -5516 -6895 -5380 -4710 -4863 -4145 -4106 -3174 -3545 -4286 -2952 -3119 -3693 -5916 -5698 -2972 -4596 -3328 -5617 -5088 -4729 -2975 -3637 -4701 -3548 -4083 -4743 -5614 -4114 -4627 -3837 -4620 -4960 -4461 -4133 -3920 -3906 -5329 -4601 -6177 -4671 -5601 -5018 -5524 -3467 -3620 -3969 -3665 -3472 -5133 -5972 -5813 -3303 -4611 -5177 -4924 -3979 -5311 -3713 -4204 -4627 -3892 -2996 -6592 -4466 -4936 -4321 -4922 -4987 -4041 -4651 -4831 -3089 -7083 -4189 -4509 -4246 -6063 -6123 -7424 -4228 -4864 -4458 -5534 -5692 -5041 -4802 -4070 -5327 -6151 -4551 -3942 -6132 -4615 -4407 -3657 -4174 -5031 -4070 -3970 -4076 -4185 -4233 -4580 -4317 -3887 -4977 -5636 -3971 -3254 -5033 -5519 -5991 -4791 -3755 -4339 -5175 -4616 -4145 -3903 -3723 -4507 -5235 -3639 -4905 -3364 -5096 -4221 -5640 -4683 -4326 -5269 -3533 -4546 -5800 -4586 -4973 -4452 -4473 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/random.txt deleted file mode 100644 index 1c76693de..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -21137 -15552 -13904 -18530 -16191 -13113 -12574 -14945 -15069 -19961 -11187 -12967 -12462 -18281 -14363 -13712 -9893 -17177 -15840 -12005 -8937 -10424 -12875 -12667 -14504 -15020 -13159 -12240 -16620 -11289 -10490 -15815 -12523 -11102 -16186 -16557 -16810 -10658 -16872 -12987 -11744 -10512 -16251 -13419 -12051 -11234 -13512 -9436 -11057 -16278 -14618 -15601 -12287 -13479 -11595 -13989 -10761 -14564 -16343 -13161 -13842 -17841 -14123 -9810 -14573 -11367 -15039 -12992 -9797 -14557 -15721 -13619 -15817 -12182 -16199 -16761 -15258 -15352 -10462 -16282 -12096 -14179 -12604 -14941 -13928 -11657 -16140 -18857 -8948 -15302 -10642 -15940 -11632 -16322 -14352 -12530 -13572 -17129 -12344 -10926 -13419 -14709 -13747 -11668 -13143 -14827 -14783 -17550 -14076 -12088 -13065 -9210 -14564 -13015 -14591 -14306 -12032 -14814 -17632 -13827 -12881 -14532 -13766 -16847 -14713 -14567 -11679 -17920 -9628 -15322 -13643 -15740 -16022 -12795 -14890 -16629 -19216 -9768 -13938 -13711 -12351 -9587 -15192 -14419 -16242 -9544 -16734 -10848 -14029 -14464 -14388 -12459 -12805 -14514 -14596 -14878 -11236 -13078 -11705 -13487 -18732 -14952 -14107 -13498 -12209 -16955 -10469 -12911 -12090 -15491 -17471 -13285 -12039 -16461 -11230 -11591 -15528 -15844 -15923 -12763 -14106 -17122 -14359 -10344 -9528 -8742 -15492 -16131 -12258 -15616 -12245 -13617 -14440 -10875 -17843 -13774 -17067 -12877 -13708 -17030 -11946 -8278 -10155 -16707 -9630 -8926 -12336 -14137 -13543 -14112 -8370 -13664 -14230 -9487 -14655 -11154 -14562 -14574 -10623 -14785 -11902 -9106 -14127 -13252 -13598 -12306 -15008 -16186 -13133 -15752 -11481 -12059 -16847 -15443 -14382 -12548 -13235 -21368 -17632 -16890 -14304 -14525 -8876 -15030 -12829 -14382 -13166 -12984 -19755 -18558 -16393 -10722 -14487 -11556 -13643 -10597 -14165 -15868 -12134 -14188 -12541 -17546 -16488 -18541 -12425 -13125 -10807 -12824 -12104 -11430 -10953 -15716 -12237 -19871 -15113 -12735 -13793 -13947 -18141 -16487 -12996 -8777 -11836 -14455 -12292 -13253 -14407 -16712 -11426 -11122 -17731 -10983 -10684 -16608 -12808 -9173 -16493 -15566 -19859 -14352 -14140 -16923 -18997 -16577 -10376 -14161 -13164 -12415 -10900 -13409 -14836 -15139 -10950 -11836 -13864 -13095 -11645 -15490 -15193 -15196 -9965 -16869 -13743 -12543 -10578 -14501 -13977 -11012 -16939 -17228 -9926 -11267 -11907 -14131 -12628 -12116 -9712 -10472 -12763 -13037 -10129 -16507 -14665 -10992 -14725 -12752 -11129 -12933 -12362 -12103 -11248 -13895 -10698 -10406 -12753 -11841 -10188 -10589 -13256 -13300 -12981 -8107 -15523 -13742 -12325 -14676 -13152 -10552 -12454 -11931 -18224 -11700 -10931 -13162 -12152 -12121 -12538 -22303 -13498 -19479 -13555 -13675 -13729 -16152 -16560 -15268 -16152 -15783 -14619 -12916 -14324 -14302 -14985 -12332 -17326 -12024 -14621 -12495 -12839 -18141 -16340 -13648 -12412 -11728 -13917 -11712 -14633 -13024 -15275 -11725 -17622 -17407 -13173 -12383 -16570 -15442 -13671 -14276 -12483 -14333 -15349 -15545 -11923 -17276 -11512 -10769 -13724 -12170 -14031 -14590 -12720 -13534 -15242 -11713 -15557 -13945 -15239 -14763 -14366 -13176 -11870 -12619 -14828 -12721 -10842 -11714 -16928 -10026 -13163 -14858 -17230 -18435 -13730 -12695 -16924 -15221 -14374 -15395 -11966 -14348 -11571 -11792 -12757 -14336 -11237 -15536 -18937 -11691 -16325 -13982 -14702 -16097 -15268 -13119 -9283 -13507 -15648 -10236 -17986 -9606 -13479 -13419 -15021 -11060 -13345 -17517 -13256 -13681 -12581 -13453 -15192 -17092 -17811 -14365 -11480 -14113 -12024 -11934 -19783 -10778 -14415 -10752 -17718 -12798 -15474 -15510 -14132 -16004 -15922 -10586 -13747 -13601 -11930 -19614 -12353 -11657 -13670 -14048 -15806 -11369 -12983 -19095 -10677 -17514 -15131 -10756 -12233 -12692 -13867 -16032 -12492 -13704 -10845 -16029 -12846 -12728 -18055 -12746 -12686 -9034 -10261 -15533 -16305 -11170 -18822 -14422 -16070 -17646 -16241 -11835 -10342 -14513 -15922 -17423 -11440 -13342 -14960 -10609 -14483 -7879 -14221 -14194 -9112 -12274 -15358 -14840 -16653 -12898 -10364 -15646 -14926 -16628 -13972 -8825 -14811 -11029 -12495 -19488 -14220 -11265 -15695 -18912 -14874 -14475 -15524 -11704 -14503 -14188 -18944 -11378 -12499 -9882 -10239 -10842 -14660 -12682 -10970 -15696 -11579 -14854 -16818 -12324 -15677 -16682 -18409 -15402 -10163 -13401 -18290 -12287 -18115 -11019 -11775 -12877 -13484 -16234 -14243 -17136 -11409 -16375 -12298 -12737 -8766 -14811 -13768 -14813 -13288 -11916 -16913 -13353 -15414 -15185 -15219 -11618 -11178 -13017 -14122 -13974 -15351 -14184 -13276 -16188 -11810 -12035 -8012 -10370 -14276 -13808 -14044 -13005 -10515 -15834 -13569 -10687 -10465 -10607 -8472 -14503 -17659 -16110 -14921 -14563 -23834 -15512 -16755 -22448 -15709 -13253 -12810 -9816 -14419 -15290 -12430 -16753 -18159 -13672 -13300 -16632 -10767 -9135 -18567 -12632 -12857 -16405 -11023 -12449 -14849 -15311 -17354 -11437 -12319 -12441 -18665 -14277 -14822 -16562 -16562 -13909 -17595 -16140 -13640 -12787 -14739 -11938 -17339 -13479 -14374 -14406 -10943 -10346 -15419 -15029 -11147 -16316 -14572 -10343 -16802 -12676 -15890 -13539 -11922 -14206 -13332 -11261 -8984 -9368 -14184 -12883 -13438 -15093 -11461 -12893 -11326 -18604 -14019 -15877 -16230 -13133 -15361 -9585 -13308 -9293 -17693 -12077 -14485 -15679 -13678 -17263 -15032 -11223 -13113 -10551 -13401 -12721 -14614 -12369 -12998 -13188 -19328 -14748 -12711 -15108 -13770 -12155 -11359 -11330 -14112 -14115 -13752 -16676 -18087 -10761 -17775 -14234 -12463 -17860 -12216 -10470 -13281 -13852 -12196 -16798 -15800 -12630 -15431 -15652 -12054 -9042 -12453 -13107 -14716 -17768 -14960 -11458 -18247 -18400 -10852 -10685 -13019 -11592 -16242 -16466 -14489 -10675 -11101 -11967 -14387 -9698 -12167 -14425 -16466 -13851 -12066 -11420 -13569 -6669 -12500 -17178 -11070 -14153 -14943 -11813 -12804 -16240 -13882 -17628 -14567 -10585 -16326 -13660 -13501 -14739 -15124 -11056 -15924 -11432 -11500 -14202 -16932 -12945 -12223 -15112 -14784 -11163 -12450 -15595 -10968 -13644 -12111 -15600 -12290 -13003 -10016 -18125 -14454 -14181 -11375 -10749 -11571 -14041 -15837 -9285 -17601 -17013 -14575 -10776 -15442 -13000 -17178 -13271 -13427 -13125 -15956 -18021 -14893 -12539 -11410 -17076 -12896 -16493 -10018 -14660 -13033 -16457 -11064 -11451 -10838 -15471 -14283 -12836 -13154 -19944 -12912 -17612 -9991 -13326 -15769 -14033 -10187 -10770 -15674 -12250 -11168 -14525 -14929 -13557 -14977 -15355 -15662 -14181 -10997 -12937 -7907 -14430 -14165 -14377 -15323 -14465 -16690 -10440 -14274 -10002 -13086 -11510 -12301 -13193 -15559 -15722 -13535 -16872 -12773 -11877 -13157 -10817 -12117 -17433 -13727 -13991 -16135 -13636 -10853 -11129 -11387 -15694 -11930 -19322 -13318 -8923 -12144 -17100 -12643 -12545 -13263 -11006 -12050 -7533 -14258 -13631 -17379 -17967 -11963 -13923 -13026 -18283 -14648 -14976 -13219 -14896 -16520 -10830 -10079 -15711 -11416 -13815 -18750 -12414 -15598 -12485 -9934 -18058 -15361 -11462 -12276 -12233 -12916 -14425 -14586 -14211 -8917 -13719 -13606 -17170 -12453 -12187 -15405 -17313 -19491 -16274 -15398 -12755 -17259 -13334 -17023 -15113 -13087 -13270 -15532 -9048 -12848 -12855 -19171 -8662 -13592 -9814 -16878 -10854 -14983 -13307 -17397 -15720 -13143 -16870 -16735 -9125 -11655 -12166 -16975 -15054 -17981 -14789 -15754 -14448 -11740 -10784 -15086 -14141 -15123 -15616 -14956 -14569 -15212 -16777 -14211 -15776 -17157 -17894 -14360 -12701 -10387 -16485 -15121 -6566 -10927 -12402 -16572 -13098 -14606 -13066 -11205 -10733 -14418 -13392 -14064 -14035 -10190 -14772 -11203 -15008 -14320 -11358 -13245 -17118 -16185 -13330 -11652 -11581 -15636 -12642 -12212 -11288 -13669 -12737 -12274 -14237 -15669 -11288 -12381 -15181 -11905 -12975 -12697 -14411 -15807 -13749 -15406 -14398 -11547 -14776 -9386 -15224 -13924 -13026 -16388 -14034 -14115 -12503 -13390 -12176 -11206 -14390 -10891 -16899 -16829 -14820 -14055 -16251 -13422 -12079 -13463 -14496 -19156 -14661 -15979 -15475 -11976 -12629 -12442 -12612 -17834 -11908 -10122 -11164 -12888 -14581 -12320 -15304 -12977 -11728 -14880 -11713 -15218 -10945 -14322 -12295 -14521 -12843 -12630 -15376 -14761 -13335 -12046 -17804 -13288 -10447 -16222 -9098 -10444 -14289 -11709 -12819 -14262 -15077 -15356 -13135 -13455 -16596 -14054 -15608 -13217 -14530 -14777 -15943 -13926 -10874 -11993 -15996 -15373 -13878 -13826 -8611 -15909 -16274 -10315 -10251 -17200 -12060 -12207 -11253 -12558 -11407 -12150 -11329 -12307 -12332 -11980 -14086 -12184 -13133 -12166 -13927 -18053 -13173 -14290 -17155 -13099 -13870 -11949 -17048 -11814 -9966 -10981 -18669 -13999 -14144 -12884 -17197 -16083 -10895 -10459 -16895 -16139 -14046 -17767 -15678 -12806 -12958 -12388 -13824 -17989 -14787 -12034 -10026 -14227 -12608 -11091 -12102 -15165 -11320 -15476 -11634 -14961 -10812 -13666 -14177 -13857 -12077 -19059 -13146 -10706 -12777 -13674 -10625 -11291 -13053 -11358 -13851 -15160 -15070 -18016 -14840 -15542 -10586 -17025 -10604 -14087 -9864 -12729 -10862 -12008 -11928 -17017 -10171 -13984 -11808 -12199 -11606 -14472 -10258 -12648 -15093 -10387 -13375 -12683 -13759 -14449 -7748 -14632 -13039 -16639 -17764 -12928 -11480 -11041 -11763 -10313 -12244 -13861 -14233 -12255 -12808 -16304 -11596 -12059 -13562 -13350 -12090 -9818 -14247 -13277 -13795 -13680 -14474 -14870 -16638 -13278 -15677 -13929 -11880 -11840 -12903 -13394 -15039 -12371 -10345 -11557 -11161 -11922 -14202 -11148 -11076 -16667 -12324 -13086 -14500 -11717 -9613 -15880 -14853 -11704 -13800 -12654 -14198 -16489 -15051 -15135 -15527 -13741 -10081 -15878 -11634 -13123 -14755 -10945 -15984 -12642 -16030 -14489 -11218 -20500 -17546 -17609 -18485 -13198 -10540 -13235 -16190 -16943 -15319 -15117 -14872 -14341 -11816 -16318 -16254 -15267 -13552 -13711 -14550 -12033 -15203 -11528 -12746 -14488 -11035 -10178 -8843 -14077 -17992 -14813 -9751 -15072 -14874 -12959 -8407 -11938 -14900 -13840 -14096 -13387 -11359 -17126 -12688 -15691 -13334 -11692 -12633 -14762 -10185 -18056 -14481 -9705 -15633 -14204 -9176 -14399 -9361 -13222 -13503 -16805 -16248 -12689 -9735 -14434 -15047 -15009 -11779 -14656 -14837 -15694 -16823 -18868 -14713 -10361 -14136 -14825 -13071 -19259 -10612 -11309 -16245 -11943 -14215 -11903 -14481 -13878 -11356 -12826 -11991 -13148 -12192 -14902 -13483 -15428 -17652 -10370 -13875 -13887 -22743 -13669 -12404 -13739 -10361 -17004 -13668 -15389 -16315 -11014 -10798 -16533 -13811 -12714 -14059 -15001 -12417 -13200 -14008 -16562 -10060 -14881 -11374 -11649 -13725 -10965 -13652 -13802 -13060 -11870 -11596 -14629 -12819 -11205 -13535 -14550 -15263 -12513 -17996 -14399 -10336 -10529 -19215 -17055 -10790 -10690 -12572 -9337 -16783 -12357 -11525 -20065 -11500 -14162 -12990 -17364 -12944 -13458 -13794 -16297 -15198 -12759 -17369 -13129 -11959 -16322 -13547 -13975 -15874 -11517 -15301 -17007 -16481 -17087 -12036 -13116 -17710 -10439 -14936 -13596 -13359 -11614 -10669 -13595 -8800 -20246 -13200 -13595 -13698 -10342 -9992 -10832 -14567 -13617 -12987 -12557 -18632 -11073 -10971 -19350 -15164 -18987 -11440 -14455 -10170 -13125 -14941 -12892 -10136 -13397 -10001 -11724 -13154 -13418 -7333 -9873 -11734 -12396 -11779 -11308 -16812 -15386 -13688 -16158 -15469 -14912 -15476 -16352 -14271 -12386 -20049 -13575 -9623 -16055 -9421 -12599 -14187 -13273 -11313 -12662 -15923 -16060 -16439 -12001 -11932 -14033 -12022 -14938 -13298 -17078 -10093 -15443 -13144 -8990 -13745 -11762 -10307 -15085 -13861 -16175 -14001 -13496 -11392 -19810 -11513 -13922 -12304 -18442 -9659 -11147 -10425 -16171 -15293 -16767 -11468 -14662 -12585 -11222 -10368 -15853 -14890 -18520 -12423 -17407 -10997 -12504 -14961 -18128 -16770 -13670 -15006 -10037 -14024 -12520 -12210 -19691 -10991 -15899 -11122 -16190 -7359 -18274 -14485 -12188 -15219 -12793 -10692 -9932 -15844 -13451 -11059 -10674 -13708 -15008 -13500 -8721 -10510 -12108 -14127 -16674 -11393 -18172 -11378 -18503 -10975 -14705 -20529 -13145 -13498 -14961 -16819 -12478 -10880 -14892 -13219 -11673 -15778 -13189 -12099 -14951 -12540 -17175 -12693 -7954 -14549 -14915 -12948 -12060 -10193 -12275 -11078 -9867 -11143 -10357 -14269 -11470 -14552 -13799 -17141 -14535 -11066 -11453 -17739 -15614 -12508 -11551 -11476 -12061 -13319 -12700 -13137 -13354 -11968 -15296 -15066 -10578 -21712 -15675 -13720 -14468 -13163 -13665 -16322 -12701 -10242 -16024 -13970 -13132 -11293 -14277 -13195 -13709 -15473 -11588 -10466 -19237 -13574 -14762 -12205 -17829 -13250 -14055 -13932 -12103 -12919 -10225 -13014 -17936 -18052 -12425 -12720 -12637 -13692 -11956 -13119 -12018 -15036 -10067 -10742 -14793 -13116 -14310 -14999 -13428 -13922 -10520 -14832 -11952 -17876 -13764 -13797 -12786 -9768 -9357 -12345 -9450 -9389 -14757 -15783 -12291 -13084 -13602 -12624 -11974 -12646 -14834 -11473 -14929 -16765 -11252 -8358 -10310 -15512 -11032 -14251 -13421 -12506 -20497 -14896 -17043 -16445 -9215 -17893 -15875 -16428 -14269 -12655 -16196 -14641 -11497 -14211 -12406 -12146 -12756 -12041 -17119 -12203 -12600 -18806 -12352 -13796 -15152 -12914 -15685 -12290 -12446 -14579 -9342 -13861 -12547 -16107 -14298 -9357 -12209 -11095 -11652 -12151 -11755 -14001 -12464 -9094 -17224 -13962 -17397 -16847 -13859 -15541 -9701 -15198 -10177 -12716 -13876 -15747 -15363 -12325 -13439 -14126 -16284 -9625 -12219 -15436 -14059 -12457 -14932 -12842 -15620 -16225 -9149 -13780 -19306 -15621 -14593 -16772 -11654 -17695 -13174 -17152 -19603 -13333 -15547 -14797 -11487 -11882 -13732 -17050 -13091 -12035 -14131 -9907 -8639 -11053 -16738 -15703 -12762 -15435 -13245 -13079 -11670 -12921 -12175 -14198 -15618 -12744 -11231 -13736 -14260 -11845 -11150 -12950 -12210 -14498 -14662 -14900 -13676 -10274 -12613 -12643 -17501 -12425 -12430 -17059 -13652 -11245 -13423 -13723 -11724 -12352 -16007 -13665 -21340 -11563 -13755 -14905 -13991 -11345 -10426 -15654 -10949 -9727 -11407 -10763 -20773 -13101 -14579 -13054 -13075 -11723 -14674 -17114 -16536 -20539 -14288 -13644 -11671 -11428 -13451 -11601 -15177 -15390 -13169 -11815 -15371 -10206 -15411 -13085 -16711 -15508 -13191 -13540 -16427 -11287 -12605 -14539 -17199 -17652 -10564 -13799 -8546 -10118 -10341 -9411 -10457 -10045 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k3/trained_ddqn/best.pt deleted file mode 100644 index 027cf42ec69cee828eb6dbeac979e53c8a299229..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13463 zcmbt*30O^C`}b*{2QoAXg$$X>*xC2m2^lhG9+IRKDMy2u29*>|A}J*eDk>!E?0cO; zh9VRVlqMCG24f_?<9*)ue?6Y>`~KHAtaGhvU3;JPyVt$eeXnu<)-p>eX&z5rp7%cm zbzXm-?QT0qCr|r{TW#HKC+yncY+k`F z?A#RvyfIb+iP38n#iAYTCQsO7@3hU)T_9=a?kW~L!N$Yg$=OZOX1Dzo4=3lXHtzN= zZmzp+JdG6vQlm$&l@p`f#5rxZ*$brqf+$)zyV|<1`0J&jKxVCkIL{=3>{=;tYPZWn zAZNMNT_C^Ql4ogbDd{gzu#~iv@E0fsI{wx~$z7mqB~V%WyQ;s{+2UmDCQx-0m*pt! z_?N870yRfDOJjF|`oCoO3Hn(|_zC*|h1YNw46qUm{C9PX|5Keoe@HME40e=Td{@C; zp!t^?#{L2=u{L5gwEq&L<1Wy(5)Apb8peOAq4$Rn6T#5G)EM?}HHQCIL;o+lfxBRY zm0;w*)iC*w8l(P@FhyV}mT=l#F#5LyDNC^yWB$@&>|avGxeJV}1mpj$g~?x9O!z~_ zRKY~C3@LZPq<_iq6HNZCh4Ei_6L-NBE5THcLxO2*6~ql{v(w()_P3V^rvIz4XN+De ze#;ZgJR~svmnl8%ce{x_M8LO{aQm0N#3m3hhXmmGw>QQDa!A1b{f&vh?2usAzutJb zZJDslQcj+YD!Az)$>aTw%l^0CtI8YnhxbmLWMSU_AHMtBkq17W%f9_QR+Q8UY=-ns zQKhrIXgzy{O8PZWf6vpj+wLt6xH>>oablRL?13ix^Z0O4wVeX1vDu34C_5;+wPdVF zDO#Gfzq*iaIBh`MZ+NmPAHLD{okBXoAe9JGyGi5pVWJru%-Qx# zj@?H%zv=qEypY@8n@L;F4Np$`pfN!i5VqHQOX zL;-7n?f3Pt=+f3gx>P|;bf!#-P3cai%RGjNY>aBiu1mAo>6#L(LxuyZ?b4s#kPE@p z_5QHjHi1?xTu*%6zED!2Ad(MIVb2aaPu3^tiV`afMcFB{*tnCYpzZMrR1Y60vM}_W&NYs1yqm=hWBjPxFiAFajFD*hbuCufQAgw~xI#iN%W)BG22~KAX8Yc# z9sfHEPx;frlP%0A{Vy#1$8hyOJ?M`&Whc0frmN*tL@hJ? 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 H%KJY6I`!L3 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/dqn.txt deleted file mode 100644 index 430a3870c..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4815 -3025 -3900 -5927 -4655 -3341 -5181 -4556 -4609 -3522 -5037 -4874 -5262 -4306 -4924 -4085 -3915 -4575 -3602 -3671 -6932 -5646 -3721 -3611 -4078 -4414 -3896 -4603 -5233 -6437 -4363 -5034 -4544 -5454 -3348 -4815 -4271 -3429 -4915 -4370 -4483 -5632 -5361 -4131 -5479 -3501 -4608 -3850 -4669 -4175 -4603 -5506 -4087 -5415 -5258 -4088 -3815 -4953 -4349 -4023 -6483 -4990 -4841 -3740 -3883 -5970 -4540 -5268 -4009 -3228 -3805 -5181 -3486 -4585 -5185 -5644 -4902 -3326 -3883 -5939 -4353 -4928 -5908 -5359 -4794 -5347 -5180 -4623 -4971 -5049 -3719 -5410 -3971 -4256 -5593 -5714 -3636 -5218 -4116 -4526 -3985 -5786 -5503 -5741 -5539 -4743 -5309 -2517 -4437 -5953 -4918 -3368 -2984 -3829 -3608 -6068 -3820 -4223 -4611 -3602 -4328 -3847 -4072 -3528 -4162 -5652 -5055 -4834 -4911 -3289 -5386 -2900 -5310 -4734 -2467 -4262 -4805 -3836 -4587 -5269 -6691 -5311 -4028 -6062 -5483 -4567 -5694 -5024 -4219 -4063 -4594 -3462 -4787 -5156 -6036 -4757 -4920 -5165 -4048 -6056 -5268 -4659 -4543 -4180 -4974 -3907 -5487 -5068 -3446 -2186 -4407 -4891 -3177 -4585 -3707 -4004 -3051 -3788 -4066 -3733 -4829 -3101 -4251 -3022 -6377 -6256 -4150 -2709 -5279 -4675 -5804 -4159 -5135 -3027 -4896 -4763 -6020 -4879 -5267 -5292 -3799 -3298 -5835 -4639 -5385 -4323 -4675 -4466 -4653 -5121 -5624 -4627 -3550 -5384 -4283 -3466 -5366 -3288 -3595 -3247 -5104 -4697 -6023 -4858 -4663 -4692 -4190 -4277 -4704 -4205 -4882 -6137 -4062 -3355 -6953 -5847 -4439 -5554 -5310 -4559 -6114 -4065 -4517 -4656 -5234 -4539 -6870 -5000 -6180 -5191 -3367 -4725 -3968 -4120 -5226 -4124 -4089 -5069 -5218 -4505 -4557 -5571 -4319 -5940 -4016 -3428 -4048 -6408 -5068 -4190 -4430 -5074 -5990 -4784 -4564 -4769 -5489 -6239 -4337 -3347 -4831 -5660 -3991 -4765 -4872 -4291 -4855 -4274 -4524 -2973 -3593 -4383 -4370 -3794 -4997 -4941 -3910 -4530 -3647 -2757 -4699 -5292 -6001 -6449 -5790 -5492 -4759 -4651 -5217 -5127 -4070 -4056 -3995 -3937 -5030 -3807 -6029 -5113 -4948 -3584 -3874 -3984 -5300 -5792 -5289 -4705 -5555 -4143 -5708 -5933 -6479 -4337 -4890 -3822 -4054 -4244 -4001 -5441 -5317 -3630 -5168 -5592 -3752 -4777 -4538 -5191 -4938 -4474 -3690 -4088 -4997 -5225 -4200 -4933 -4691 -5484 -5092 -5860 -5097 -5600 -4038 -2573 -4358 -5767 -3628 -3462 -4465 -5228 -4834 -3481 -3427 -4706 -4474 -4973 -5717 -3815 -4921 -5095 -4734 -3957 -6238 -2838 -4382 -4684 -3305 -4394 -4217 -3743 -3408 -4676 -3779 -3663 -3919 -4140 -6731 -5672 -4324 -5437 -4480 -4635 -4314 -6421 -4275 -4648 -4975 -3535 -5203 -6272 -4699 -5019 -5620 -3632 -5170 -5069 -4682 -3603 -5096 -6244 -4845 -4101 -3876 -4343 -4135 -5031 -4996 -5798 -6857 -4160 -5014 -4744 -5817 -6206 -4219 -3362 -3548 -3938 -4920 -5073 -4749 -3293 -4549 -4557 -4410 -3824 -4934 -4083 -4508 -3463 -3662 -3639 -3465 -5582 -5602 -3692 -4057 -5060 -5076 -5332 -4493 -3415 -5355 -4524 -4121 -6847 -4823 -4229 -5729 -4206 -2969 -4053 -4638 -4463 -4480 -3752 -3459 -3990 -3333 -3708 -3253 -3847 -5069 -4233 -4906 -4944 -4124 -3649 -5872 -3878 -4556 -4473 -4656 -5161 -4528 -3626 -6265 -4561 -6414 -7585 -4175 -6095 -3260 -3903 -5849 -4443 -4552 -4662 -4363 -4606 -4314 -4382 -4617 -4443 -4368 -4829 -4942 -6417 -4744 -5915 -5186 -4876 -4295 -6004 -5735 -3750 -4964 -4579 -3968 -4432 -5041 -7542 -3730 -5167 -3255 -5391 -4768 -4453 -3249 -4127 -4782 -3379 -5269 -3423 -3951 -4686 -5218 -4384 -6214 -4834 -3985 -5912 -4577 -3161 -4942 -4138 -3502 -4672 -4659 -5008 -3290 -4554 -3925 -4059 -4842 -3351 -4567 -4266 -4106 -3887 -4404 -3596 -2679 -3586 -6025 -4519 -4713 -6270 -4356 -4694 -4032 -4862 -5185 -5288 -3396 -5911 -5783 -5258 -5041 -5633 -5960 -5094 -5476 -5603 -5001 -3476 -3491 -4753 -6319 -4028 -5486 -3791 -3509 -4284 -4349 -4764 -3889 -4995 -5072 -3676 -4922 -3276 -4639 -4518 -4885 -5305 -5934 -3391 -4877 -6236 -5742 -4518 -4952 -4011 -3318 -3626 -5372 -5863 -4131 -4909 -4797 -5061 -4195 -4384 -4236 -4910 -3728 -4026 -4905 -3758 -4486 -4269 -4309 -4843 -4779 -5531 -4090 -4983 -3472 -3081 -5155 -5205 -4930 -5273 -5098 -5104 -5167 -3447 -4466 -5397 -5495 -6344 -6490 -4179 -4814 -2552 -4172 -4484 -5475 -4289 -5001 -4535 -4358 -4301 -5157 -5009 -4063 -5989 -3727 -3789 -4336 -6528 -5283 -4381 -4396 -3532 -4578 -4772 -3730 -4105 -5669 -4757 -4177 -4921 -3421 -4476 -3497 -2432 -5035 -3859 -3092 -3523 -5048 -3671 -4064 -4043 -3349 -4557 -4925 -3907 -4308 -5415 -5353 -6235 -3864 -3663 -3605 -3541 -3806 -4108 -4867 -5011 -4832 -5925 -4799 -3252 -4546 -6621 -4324 -3286 -3972 -5341 -3006 -4838 -4103 -4385 -3351 -5289 -4504 -4848 -3375 -4260 -3965 -4551 -5219 -3178 -4841 -3176 -5570 -3904 -4753 -4282 -4101 -4022 -3941 -4501 -5597 -4696 -5592 -4542 -4489 -4619 -4364 -4369 -3677 -5308 -4571 -4113 -4756 -4912 -5581 -4081 -3741 -5555 -3883 -4199 -5490 -5048 -4093 -3910 -5496 -5749 -3713 -4071 -5071 -4017 -5339 -5456 -5322 -4617 -6286 -3851 -5475 -4198 -4879 -4066 -4030 -5089 -4304 -6154 -4437 -6308 -4837 -5698 -5178 -5519 -4424 -4550 -4687 -4387 -4786 -3401 -4711 -4843 -3869 -4361 -5948 -3974 -2626 -4295 -4301 -5285 -3627 -3812 -3741 -3519 -4577 -3831 -3788 -3471 -4352 -3733 -4784 -5674 -3650 -3573 -4868 -5623 -5203 -4861 -3458 -4817 -4264 -4519 -4651 -5978 -4610 -2997 -3743 -5995 -5183 -3802 -5960 -5018 -4876 -5331 -5407 -6037 -5657 -4860 -5405 -3991 -5660 -3175 -5279 -4772 -5374 -3480 -4386 -4414 -5608 -4328 -3546 -4210 -4425 -4274 -5313 -4863 -4396 -4067 -5631 -5393 -6313 -4153 -4847 -4702 -6333 -3660 -5246 -4299 -3516 -4742 -5693 -5178 -4266 -3683 -4114 -5547 -3880 -4743 -6357 -3674 -5330 -2779 -4530 -5668 -4126 -3512 -3975 -4019 -4295 -4584 -3867 -4184 -3984 -3451 -4999 -4894 -4364 -4103 -4461 -3988 -6157 -4548 -4811 -5692 -3847 -5101 -4515 -5129 -4905 -6633 -4987 -3765 -3992 -5808 -3899 -4083 -3005 -6004 -3825 -4104 -4711 -5210 -4960 -3409 -5106 -5185 -5221 -3805 -4076 -6847 -5427 -4454 -4160 -4677 -4420 -3582 -4440 -4343 -4780 -5048 -6474 -4889 -3304 -4638 -5572 -5846 -4675 -4668 -4763 -5084 -4182 -4292 -5952 -3895 -3645 -6042 -4588 -4187 -4582 -4992 -4391 -5829 -5514 -5244 -5940 -3783 -4895 -4859 -3967 -4665 -4006 -3027 -5785 -4613 -4793 -4200 -4738 -3916 -4500 -4816 -4152 -4516 -5107 -4635 -4356 -6127 -5019 -5497 -4160 -4504 -3833 -3402 -3764 -5251 -5610 -4596 -4987 -6055 -3580 -4166 -4985 -4070 -4574 -6119 -5230 -3407 -4297 -4257 -3587 -4730 -5530 -5178 -4763 -3995 -5178 -5549 -3919 -4688 -5419 -5305 -4422 -4445 -6589 -5442 -5822 -5242 -4420 -4322 -4541 -3911 -3754 -4191 -6251 -4649 -5215 -3989 -5705 -3422 -4547 -2894 -4343 -4058 -4609 -4902 -4140 -4683 -4599 -4307 -3033 -4634 -4146 -5213 -6706 -3655 -4841 -4715 -5898 -3562 -2984 -5504 -4877 -4773 -3407 -3687 -4596 -5435 -4672 -4498 -5557 -4660 -5089 -4051 -4580 -4702 -5480 -5475 -4324 -4562 -4402 -4148 -3777 -4170 -4423 -3956 -4563 -4753 -5817 -2203 -5501 -3541 -3698 -4451 -4847 -5416 -4067 -5873 -4654 -5113 -4354 -4844 -3958 -5185 -5170 -5930 -4480 -3711 -4961 -3892 -5939 -5060 -5363 -4252 -4679 -4264 -4806 -3460 -4922 -3183 -5581 -4505 -4216 -3039 -5275 -4716 -5715 -4477 -6540 -3293 -4394 -5151 -3185 -4819 -3865 -4756 -2685 -4101 -3936 -4339 -4417 -4324 -5488 -4765 -6171 -6071 -5698 -3990 -5935 -4302 -5160 -4677 -5508 -4351 -4887 -5868 -3614 -5640 -6242 -4815 -3789 -3614 -3737 -4900 -4222 -3872 -3767 -5677 -4006 -3867 -4320 -4295 -5074 -3936 -5420 -5457 -4665 -5565 -3098 -3630 -4994 -4763 -5298 -5245 -3209 -4250 -4487 -3174 -4924 -3410 -4826 -3903 -3258 -6226 -4345 -5115 -5844 -5952 -2542 -4972 -4245 -4820 -4718 -4001 -5520 -5478 -4671 -3541 -3989 -4590 -6188 -3711 -4271 -3986 -6445 -4506 -5221 -4950 -4943 -3369 -2811 -4068 -4102 -3604 -4351 -5714 -4933 -3671 -3664 -4009 -4029 -6346 -5330 -4860 -4888 -4481 -3903 -4638 -3228 -4746 -5007 -4611 -4030 -4349 -3467 -5385 -3929 -5269 -3822 -3627 -5067 -4680 -3856 -4044 -4800 -4722 -4242 -4539 -5015 -4159 -4492 -3586 -5477 -4721 -5377 -5961 -5379 -5129 -3555 -3232 -5761 -4129 -4731 -3525 -3080 -6054 -6653 -3739 -6140 -4016 -3476 -4147 -2734 -5338 -4729 -4402 -5080 -3472 -5535 -4607 -5069 -6225 -4746 -4129 -5671 -4848 -5322 -6300 -4190 -4609 -5682 -4630 -3963 -6117 -4841 -4632 -4452 -3532 -5244 -3978 -4696 -5486 -4841 -3510 -4069 -4296 -5813 -4446 -3333 -5071 -4570 -5768 -5459 -4102 -5759 -4859 -5985 -4097 -4533 -5596 -3901 -5197 -4412 -4222 -5614 -5847 -6798 -4731 -3689 -4200 -4613 -3932 -4505 -2724 -3893 -3742 -4815 -4504 -3170 -3922 -4760 -3348 -3611 -5471 -4793 -5021 -4975 -4002 -3951 -4498 -4054 -3448 -5202 -6092 -4341 -3468 -4287 -4881 -4728 -4625 -4607 -3898 -5025 -4286 -3757 -3542 -5295 -3751 -4702 -5483 -5499 -4034 -3324 -4365 -5014 -5937 -4814 -4996 -5120 -3241 -5931 -4130 -6280 -4023 -2914 -4839 -4801 -5164 -3728 -4352 -5285 -4763 -6201 -4321 -5651 -4080 -4911 -3571 -5184 -4267 -4746 -5015 -4736 -5007 -5013 -5005 -5801 -5246 -4896 -3849 -4283 -4619 -5048 -4334 -4834 -4570 -3928 -4668 -3440 -6951 -5559 -5521 -4572 -4764 -3325 -6575 -3015 -4877 -3373 -4379 -3507 -6070 -5240 -4288 -4173 -4338 -4045 -5061 -4757 -4929 -3773 -4537 -3922 -3760 -4068 -3274 -4929 -4548 -4400 -5358 -5407 -5761 -4353 -4189 -3837 -4139 -5661 -4690 -4149 -6219 -4731 -6138 -5642 -3768 -4468 -5090 -5017 -4817 -5626 -4157 -4402 -4846 -5799 -4131 -4001 -4382 -4576 -5343 -4473 -4267 -5896 -4998 -4678 -6151 -4372 -4756 -3775 -5944 -4204 -3859 -4177 -3925 -5097 -4740 -4960 -4364 -3330 -4285 -6433 -3643 -4616 -4222 -5996 -3516 -5522 -3779 -4744 -4940 -4129 -3468 -4077 -4414 -4871 -7097 -4935 -4761 -4832 -4330 -4861 -5541 -3075 -3887 -5657 -4739 -5297 -5763 -5963 -5241 -4156 -4227 -4726 -3645 -4148 -5106 -4245 -5304 -4337 -4675 -4957 -2960 -4953 -4764 -3373 -4126 -5525 -5373 -3220 -3983 -5083 -5406 -5422 -4509 -5116 -4632 -4325 -2869 -5219 -5117 -5878 -4179 -4247 -4062 -3844 -4130 -5275 -5206 -5878 -5425 -3976 -4967 -7073 -4649 -3203 -5298 -5560 -6085 -5699 -5479 -3802 -4517 -5171 -3459 -5063 -5083 -5767 -4233 -5039 -4463 -5029 -4428 -6122 -5129 -5736 -3480 -3370 -5171 -4800 -5601 -3945 -5409 -4870 -4420 -3614 -3919 -4819 -4084 -4474 -3980 -4297 -5548 -3044 -4480 -5128 -3686 -3657 -4086 -5294 -5057 -4856 -5295 -4960 -3396 -5052 -4306 -3085 -4543 -5037 -3992 -3764 -6331 -5162 -4807 -4152 -5123 -3983 -4877 -4623 -5277 -3782 -4650 -3879 -4339 -4450 -4187 -5681 -4461 -3473 -5040 -4879 -3438 -4482 -3764 -4014 -3576 -3989 -4734 -3444 -5553 -3683 -5499 -3592 -4419 -4439 -5101 -4679 -5512 -3662 -4494 -4162 -4109 -4753 -6625 -5434 -4502 -5367 -4956 -4692 -4523 -6406 -4027 -3916 -5411 -5299 -6500 -4801 -4183 -4414 -4744 -5337 -4214 -4319 -6824 -4477 -3196 -4143 -4009 -6761 -5867 -4007 -4162 -4924 -4378 -5246 -4214 -4784 -4795 -4385 -4197 -3734 -2814 -5247 -4564 -4701 -3674 -4984 -4425 -3307 -4138 -4081 -5919 -4225 -4207 -3547 -3392 -4713 -5063 -3695 -4233 -4795 -3264 -4193 -4108 -5744 -4101 -4411 -3474 -4043 -5685 -3166 -4642 -4603 -4021 -5440 -3827 -6538 -4800 -4999 -3155 -4676 -4573 -3594 -4173 -5177 -5136 -6264 -4482 -4203 -4265 -5211 -5006 -3162 -3338 -5477 -3931 -3270 -4600 -3984 -5577 -5117 -4465 -4576 -4996 -3693 -4958 -4717 -4270 -3170 -3714 -4075 -3091 -6082 -4239 -4111 -3195 -4595 -4800 -3903 -4974 -4998 -3950 -6200 -5145 -4060 -4968 -5131 -4339 -4405 -4975 -4929 -3911 -5281 -4849 -5563 -4029 -5054 -5065 -5314 -4374 -5868 -5057 -4233 -7031 -5489 -3964 -4855 -3970 -3085 -4416 -4906 -5409 -4494 -5631 -4813 -4782 -4770 -5569 -5407 -4732 -2530 -4709 -3791 -3108 -5829 -4555 -3846 -5726 -5841 -5135 -3303 -4372 -5289 -4367 -5166 -7331 -5362 -4673 -4762 -3899 -3702 -5969 -2989 -5781 -5097 -4096 -5405 -4080 -4225 -3984 -4817 -4234 -5156 -3325 -5146 -5841 -5501 -4278 -3680 -3644 -4636 -5055 -4136 -4234 -6519 -3470 -4188 -4673 -4381 -4657 -4433 -4789 -6979 -3834 -4157 -5024 -4835 -5375 -4777 -3626 -5555 -4398 -4711 -4552 -4236 -4260 -4610 -4290 -5680 -3625 -3971 -4444 -4455 -5277 -4798 -4519 -5708 -5658 -4756 -5682 -4427 -3395 -4653 -5168 -3923 -5073 -3418 -4171 -6369 -5199 -5209 -3880 -4593 -3766 -4436 -5901 -2844 -4994 -3830 -4544 -4129 -4107 -5063 -5798 -5855 -3863 -4480 -3463 -3537 -4453 -5596 -5030 -3974 -5772 -4453 -3979 -5188 -5291 -4871 -7274 -3732 -3544 -3400 -4900 -4154 -3851 -5994 -5384 -3867 -3653 -3795 -5719 -5824 -4458 -4149 -5154 -3290 -4221 -4496 -4364 -3915 -4215 -3595 -4958 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/optimal.txt deleted file mode 100644 index 116d80687..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -3566 -4511 -5447 -4050 -4655 -3341 -4472 -4556 -3884 -3711 -4356 -4874 -5262 -3565 -6081 -5253 -3593 -5111 -3602 -5179 -3509 -4535 -4793 -4377 -4078 -4676 -5271 -5725 -3675 -4938 -4363 -3545 -4725 -5454 -3348 -4815 -4271 -4593 -4915 -4370 -5296 -5632 -3777 -6341 -5479 -4890 -4608 -3523 -4669 -4175 -4160 -6761 -4087 -4529 -5258 -4088 -4506 -5380 -4349 -4247 -6483 -4990 -3944 -5099 -3883 -5970 -4540 -3458 -4009 -4288 -3805 -4231 -3941 -4158 -5428 -5738 -2885 -4984 -4024 -4339 -4617 -4928 -5908 -4742 -6394 -4944 -5180 -4473 -4390 -5195 -3193 -4873 -4114 -4256 -5593 -4765 -3636 -4401 -3055 -4526 -3985 -5335 -5503 -2752 -5539 -5934 -5309 -4915 -5267 -5953 -4307 -3368 -2984 -3829 -5129 -3957 -3820 -3705 -5395 -4399 -4089 -4624 -4072 -4293 -3911 -5569 -5055 -4660 -4911 -5740 -5066 -4546 -5310 -4741 -5134 -5123 -3202 -5154 -4587 -5269 -6691 -3483 -4028 -5057 -4158 -4567 -4358 -4678 -6112 -4063 -4608 -3462 -4787 -4885 -4562 -4757 -4418 -5165 -4847 -6056 -4380 -4708 -3598 -5115 -5151 -4623 -5487 -5590 -3446 -2186 -3732 -3068 -3177 -4031 -4286 -4004 -5513 -5647 -4066 -3733 -4308 -5490 -4645 -3884 -6377 -6256 -5447 -2709 -5279 -4675 -3851 -3960 -5135 -3027 -4953 -4763 -4172 -4879 -3386 -4221 -3635 -4716 -5835 -4756 -5203 -4323 -4675 -4466 -3964 -4813 -4432 -4627 -2988 -3728 -4283 -3466 -3889 -3288 -3595 -5505 -3408 -4697 -6023 -4605 -4900 -5611 -4190 -4277 -4704 -4205 -3381 -4178 -4574 -3355 -4634 -3535 -4128 -4625 -4505 -4715 -6114 -4065 -4517 -3514 -5234 -4539 -4759 -4841 -2673 -5191 -3367 -4815 -4242 -4120 -5226 -4269 -4085 -6576 -3798 -5076 -4557 -5571 -4319 -3879 -4016 -3428 -4048 -6408 -5068 -4190 -5682 -5074 -5990 -4784 -4564 -4084 -5489 -4148 -4337 -6172 -3985 -5660 -3991 -5173 -5230 -3134 -4855 -5715 -5231 -5175 -3593 -4383 -4370 -5685 -3944 -4941 -4404 -4530 -6169 -4982 -3796 -5292 -3888 -6449 -5790 -5032 -4039 -3682 -5217 -5127 -3618 -4056 -4530 -4347 -4860 -3807 -4818 -7000 -5046 -4571 -4821 -5435 -5300 -5792 -5289 -4705 -5555 -5278 -4311 -5933 -6479 -4337 -4890 -2950 -4054 -4244 -4001 -5441 -5317 -3630 -6342 -5592 -3059 -4334 -4643 -4912 -4856 -4329 -3690 -4751 -4443 -5225 -4200 -5170 -4244 -5484 -5092 -5860 -5097 -5600 -4038 -2573 -5814 -3179 -3628 -4846 -4465 -5228 -4447 -3876 -6633 -4500 -4474 -3574 -4117 -5011 -4921 -4182 -4734 -3957 -4392 -2838 -4382 -4684 -3305 -4412 -4217 -3743 -3408 -4676 -3779 -3663 -3919 -4140 -6355 -5672 -4324 -5006 -4480 -5240 -3906 -5021 -4275 -3527 -3771 -5744 -6155 -6272 -4234 -5019 -5620 -3632 -5170 -5069 -4798 -4277 -4372 -4901 -4845 -4101 -3876 -4343 -4863 -5031 -3393 -5798 -4736 -4118 -5056 -3793 -4445 -6206 -4219 -3362 -4153 -3938 -4920 -5490 -4749 -5850 -5423 -4557 -4410 -3824 -4934 -4563 -4513 -4499 -4603 -3639 -3465 -5529 -5602 -4976 -4057 -4400 -5076 -5332 -4240 -5558 -5355 -4524 -4121 -6847 -3891 -3974 -5729 -5029 -4502 -4473 -4638 -4463 -4726 -4385 -3988 -3990 -3333 -3495 -3253 -3847 -5078 -4233 -3016 -4944 -4124 -3649 -5480 -5137 -3485 -4473 -4699 -3879 -4528 -3626 -5654 -4343 -5125 -7585 -5247 -6095 -3260 -3903 -5849 -4443 -4552 -4662 -4042 -4606 -5400 -4480 -4467 -4443 -4368 -3319 -4942 -5063 -4744 -5915 -5186 -3345 -4295 -5385 -5735 -3750 -4964 -4579 -3642 -4508 -4102 -7542 -3587 -5167 -4803 -4540 -3661 -3225 -4834 -4127 -5258 -3379 -5269 -4155 -5769 -3458 -5218 -4384 -4252 -4834 -3985 -5912 -4577 -5760 -4942 -3989 -3502 -4672 -4782 -5008 -5493 -4430 -3375 -4863 -4461 -3351 -4661 -3106 -4106 -3420 -4374 -2704 -3864 -3586 -6025 -4003 -4740 -6270 -5610 -4930 -3733 -4646 -5185 -5072 -5419 -5911 -3991 -5258 -3461 -4705 -5567 -4638 -5476 -5603 -5001 -3476 -3491 -4566 -6319 -4028 -4748 -3287 -3509 -6055 -4349 -4764 -3889 -4995 -4198 -4921 -4190 -3276 -4639 -3773 -4885 -4781 -4739 -4804 -4877 -6236 -3232 -4518 -4952 -4974 -3318 -4217 -5372 -5863 -4331 -4909 -4804 -5061 -4926 -4802 -4236 -5029 -3233 -5768 -4905 -3758 -4326 -4269 -4560 -3726 -3635 -4896 -4090 -5934 -3780 -4427 -5186 -4679 -4413 -5273 -4939 -5104 -5167 -3447 -4466 -5604 -5495 -3449 -6490 -4179 -4814 -2552 -4398 -3461 -5475 -3949 -4973 -4535 -4358 -4301 -4165 -5009 -5312 -4292 -3727 -3789 -4465 -4842 -4664 -3850 -3858 -3726 -5091 -4772 -4740 -6336 -5669 -4757 -4177 -4766 -5445 -4479 -3497 -2432 -4451 -3859 -3092 -3523 -5048 -4483 -4064 -5118 -4648 -4557 -3963 -3707 -4308 -5415 -5353 -4627 -3864 -3663 -3605 -3541 -4394 -6789 -4867 -5011 -4372 -6364 -4799 -3543 -4546 -3464 -4324 -3286 -3996 -5817 -3006 -4081 -3457 -4806 -3734 -5289 -4658 -4848 -4264 -4260 -3965 -5029 -4774 -3178 -3126 -3472 -4547 -3849 -4753 -4906 -4101 -3189 -5696 -4501 -4796 -5000 -5592 -3548 -4489 -5267 -4226 -4616 -3677 -5308 -4571 -5349 -4361 -3397 -5581 -4361 -4351 -4360 -3883 -4485 -5490 -4889 -5542 -3910 -4389 -5749 -3330 -4091 -5071 -3092 -3818 -5645 -4308 -5122 -6286 -3851 -4848 -4528 -4879 -3029 -4726 -5089 -4304 -5241 -4437 -6308 -4837 -5698 -3604 -5519 -4910 -4550 -4687 -5852 -4786 -4105 -4711 -3921 -3887 -4361 -4901 -5354 -4288 -4295 -4301 -4609 -3627 -5533 -5753 -5070 -4577 -3831 -4299 -3673 -4352 -2748 -4784 -4014 -4548 -5353 -4868 -5623 -5203 -3044 -5199 -3699 -3919 -4519 -4595 -5978 -4279 -4666 -6517 -5995 -4575 -7009 -5960 -3799 -4092 -3858 -5098 -6381 -5657 -5065 -3620 -3991 -4529 -3175 -5279 -3037 -4684 -5389 -4386 -4224 -5608 -4328 -3808 -4210 -4425 -5538 -3690 -3566 -4396 -4067 -5631 -3329 -4180 -4153 -6388 -3993 -4274 -4709 -5246 -4299 -3516 -4742 -5693 -5178 -5440 -3683 -4114 -5547 -3880 -4714 -4423 -3674 -4865 -2779 -5647 -5092 -4126 -4648 -6011 -3305 -4295 -3715 -3867 -4184 -3984 -3451 -4999 -4894 -4807 -6039 -5073 -4594 -4501 -4548 -6399 -5692 -3847 -3695 -4429 -5129 -4905 -6633 -4987 -4676 -4525 -5808 -4737 -3846 -4301 -6004 -4664 -5414 -4711 -5210 -4960 -3409 -5106 -5185 -5221 -3805 -4076 -5133 -5427 -4454 -7014 -4677 -4135 -3582 -4440 -4343 -4774 -5154 -6474 -4889 -3304 -4638 -5572 -5205 -4321 -4668 -6381 -5335 -5764 -4292 -5039 -3895 -3645 -4670 -4632 -6122 -4060 -3571 -3799 -4675 -5064 -6627 -5940 -5717 -4653 -4764 -3967 -4665 -4006 -3027 -4229 -4431 -3195 -4200 -4738 -3916 -4500 -4816 -3768 -5207 -4004 -4635 -4356 -6127 -5361 -5497 -4160 -3781 -4476 -3402 -5310 -4183 -4796 -4596 -4987 -3519 -3580 -4166 -4406 -4070 -5710 -6119 -4952 -3407 -4659 -4874 -3587 -4630 -5530 -5178 -4624 -5350 -5178 -5549 -3919 -4688 -5419 -2610 -3916 -4445 -3955 -3927 -5822 -5009 -4420 -5627 -4541 -3911 -3754 -4377 -5552 -5718 -5215 -4573 -3996 -3422 -4290 -5777 -4762 -4058 -4961 -4842 -4140 -4800 -5865 -4770 -3011 -4634 -4146 -4466 -4170 -3655 -4957 -3758 -5898 -3562 -2984 -3234 -4580 -4773 -3810 -3687 -4452 -5435 -4672 -4498 -4927 -4660 -4218 -4051 -4932 -4702 -5480 -5475 -4324 -4562 -4402 -4148 -3777 -5565 -4931 -3956 -4493 -4753 -6350 -4881 -4822 -5239 -2508 -3786 -4702 -5416 -4067 -5873 -4304 -5113 -6560 -5349 -3958 -5185 -4082 -5930 -4709 -4367 -4961 -3409 -4434 -5060 -5363 -3945 -4679 -4264 -4806 -3460 -5046 -5308 -5100 -4405 -4216 -3039 -5275 -3837 -3615 -4477 -6540 -3856 -6753 -5151 -3185 -4879 -3865 -4756 -2685 -4101 -4944 -6754 -4417 -5331 -5488 -4398 -6422 -5209 -5698 -3990 -6126 -3249 -5160 -4677 -5508 -4351 -4887 -5123 -3614 -5640 -5969 -3760 -3789 -3614 -3456 -5182 -3475 -3872 -4996 -5677 -4467 -4581 -4320 -3361 -5074 -3936 -4415 -5457 -4665 -5565 -4828 -4208 -3254 -4763 -6578 -6150 -4919 -3731 -4485 -4752 -4924 -4292 -5244 -3903 -3258 -6226 -4345 -5019 -3969 -5952 -2542 -4129 -3817 -4820 -3513 -3320 -5520 -5478 -4671 -4057 -3989 -4644 -3719 -3711 -4271 -4646 -6289 -3768 -5221 -4950 -4943 -3369 -2811 -4068 -4102 -4317 -4351 -5714 -3655 -3671 -3664 -4009 -4460 -6346 -5330 -4052 -6149 -3895 -3693 -6115 -3228 -4746 -3729 -4149 -4227 -5388 -4412 -4243 -5499 -5269 -4822 -3398 -5024 -4680 -3742 -2957 -4800 -4722 -4242 -4539 -3243 -4159 -4492 -5838 -5477 -2856 -3773 -5961 -5379 -5129 -3555 -4854 -5761 -4129 -4731 -3525 -5897 -4623 -6653 -3739 -4910 -4016 -3476 -4147 -2734 -5338 -5372 -4402 -5080 -3472 -3923 -3942 -6492 -5269 -4746 -4129 -5671 -5418 -5322 -5470 -4190 -5902 -4363 -4630 -3963 -4340 -4841 -4215 -4452 -3532 -4581 -3978 -4696 -5486 -3915 -4350 -4643 -4296 -5315 -3403 -3333 -4390 -5205 -4654 -5459 -4102 -6452 -4859 -5985 -4097 -5985 -5596 -4109 -5071 -4515 -4222 -5614 -5847 -4560 -4731 -4295 -4200 -5047 -5067 -4505 -3378 -3082 -3391 -4045 -4504 -5046 -5250 -4760 -4516 -3951 -3392 -3147 -5021 -3283 -4002 -3951 -5604 -4054 -3901 -4711 -5866 -5026 -5231 -4489 -4881 -4728 -5140 -4607 -4458 -5025 -5609 -3757 -5044 -5412 -3751 -5103 -5483 -5499 -4034 -3324 -4365 -5014 -5937 -4814 -4996 -5112 -3241 -5931 -4130 -6280 -2783 -5284 -4475 -5623 -5164 -5744 -4352 -5285 -4763 -6201 -3850 -4536 -4834 -4759 -3571 -5184 -4758 -4746 -5015 -4736 -3810 -3641 -5005 -3875 -5246 -4896 -3849 -4388 -4619 -4617 -4406 -5786 -4458 -3730 -4668 -3440 -6951 -5559 -5521 -4572 -4630 -3325 -4902 -3015 -4877 -3373 -4379 -5255 -5028 -5240 -4288 -3935 -4338 -4045 -5226 -4757 -3760 -4479 -4537 -4669 -3760 -4068 -4757 -4715 -4436 -4400 -4703 -3815 -5761 -5137 -4189 -4699 -4139 -3779 -4525 -4149 -6050 -4731 -6138 -5642 -5446 -4468 -4092 -4248 -7053 -5095 -4157 -4402 -6109 -5799 -4131 -4527 -4558 -4576 -5343 -4473 -4267 -5896 -4998 -4729 -6151 -4379 -4942 -3564 -3869 -4204 -3859 -4177 -3925 -4434 -4740 -4960 -4921 -4516 -5547 -6433 -3643 -4616 -5896 -3592 -4472 -3965 -3909 -4744 -4940 -4129 -3468 -4077 -4414 -4871 -7097 -5266 -4761 -4084 -4330 -4861 -4302 -4750 -3887 -5657 -4739 -5404 -4276 -3431 -5241 -4156 -4625 -4726 -5055 -4078 -5106 -4245 -3192 -4337 -4675 -3477 -4234 -4953 -4764 -5525 -4126 -5525 -5373 -3220 -3983 -5309 -5406 -5422 -4509 -3670 -4632 -5068 -4152 -5219 -5082 -5878 -4170 -4432 -5555 -4026 -4316 -5275 -5455 -5878 -5425 -6002 -4967 -3462 -3060 -3203 -5298 -3907 -5910 -5699 -5479 -3802 -3341 -5171 -3459 -5063 -4987 -5767 -4233 -5039 -4463 -5976 -4428 -6122 -4105 -3981 -3480 -4251 -5171 -4800 -4640 -3945 -5544 -3342 -4420 -5027 -3919 -3852 -4084 -4474 -5371 -4297 -4776 -3968 -4480 -5018 -3302 -4346 -3762 -5294 -5057 -3506 -4384 -4960 -3396 -5685 -4306 -6703 -4543 -2662 -4298 -3764 -5829 -4492 -4067 -5778 -5123 -5921 -4877 -4297 -5277 -3782 -5233 -3841 -4462 -5981 -4187 -5681 -4461 -5590 -5040 -4879 -4907 -4798 -3764 -4478 -4128 -3989 -3740 -4300 -5534 -4583 -5499 -4766 -5875 -4105 -5101 -4511 -5512 -3963 -4494 -4999 -4109 -4664 -3270 -5434 -4985 -6442 -4956 -5910 -4751 -6406 -4027 -3916 -5214 -5299 -6500 -4801 -4183 -4862 -4744 -3847 -4214 -4319 -5563 -4477 -8029 -4143 -4868 -4260 -5867 -4007 -3880 -2928 -3884 -3762 -4214 -4784 -4795 -4385 -4027 -3734 -3768 -5247 -4564 -4701 -4198 -3525 -5582 -3307 -5070 -5819 -3944 -5720 -3597 -5402 -3392 -3829 -5063 -5289 -4233 -4795 -3264 -4193 -5389 -5744 -4101 -3870 -6512 -3753 -4148 -3166 -4642 -4438 -4021 -5440 -5486 -6538 -4800 -4999 -4659 -4676 -3575 -3594 -4173 -5177 -6748 -6264 -4482 -4203 -4265 -4455 -4204 -3951 -3338 -5477 -3931 -3270 -5061 -5690 -4108 -5117 -6585 -4576 -4996 -5051 -4958 -4244 -4400 -3170 -4324 -4075 -3091 -6082 -4239 -4264 -4156 -4595 -4800 -4125 -4974 -4998 -5767 -6200 -5145 -5128 -4475 -5132 -4339 -4374 -4975 -4929 -3911 -5281 -4849 -5146 -4614 -4433 -5065 -5099 -4374 -5868 -5057 -4233 -3305 -5489 -3964 -2713 -4033 -3085 -4614 -4906 -3674 -4494 -7125 -5107 -4782 -4770 -5569 -6159 -4732 -2530 -4604 -3791 -5887 -5829 -3982 -4039 -5726 -5088 -5135 -3303 -5694 -5323 -5598 -5166 -7331 -4210 -4673 -4762 -3899 -4087 -5969 -2989 -5781 -3826 -4251 -5405 -4080 -4225 -4470 -4817 -4511 -5359 -5374 -5119 -5202 -4649 -5715 -3680 -3649 -4636 -5055 -3658 -5972 -5552 -3964 -4522 -4799 -4543 -4657 -4433 -4789 -6979 -3834 -4036 -5024 -4274 -4775 -4777 -4448 -5555 -4398 -4711 -4552 -4321 -4317 -2470 -5038 -5680 -3625 -3971 -4889 -4455 -5277 -4222 -4519 -5708 -6166 -4756 -4342 -4427 -3395 -4653 -5168 -4622 -5073 -3418 -4171 -4059 -4939 -2669 -3880 -4593 -3766 -5185 -2823 -2844 -5242 -3830 -4544 -4828 -4440 -5063 -5798 -5377 -4624 -4480 -2870 -4906 -4246 -4406 -5030 -3974 -5772 -4060 -4707 -5188 -5291 -5449 -7274 -5857 -3544 -3400 -5267 -3719 -3851 -3844 -5384 -3867 -3653 -3795 -5719 -5824 -4458 -3990 -4326 -3290 -4034 -4344 -3484 -3915 -4215 -3595 -4697 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/random.txt deleted file mode 100644 index d2fdfbf4c..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -16795 -15999 -21165 -16901 -15471 -21736 -17501 -16916 -18244 -16728 -22235 -17051 -20268 -14410 -20113 -17897 -18738 -14522 -14862 -24454 -20369 -20703 -15811 -14899 -20712 -12389 -15958 -14569 -17185 -16247 -24671 -13654 -17976 -19773 -14885 -22524 -19483 -17470 -20709 -22203 -20015 -13973 -17784 -23611 -17104 -15291 -25769 -12891 -17710 -17015 -20447 -14162 -20306 -23630 -18626 -20496 -18926 -15797 -20192 -16518 -19831 -17201 -15963 -12092 -23764 -14190 -17116 -18471 -23340 -17770 -14087 -12718 -15522 -23656 -16587 -20140 -20340 -14706 -18011 -16413 -13141 -14395 -17683 -15604 -18335 -23650 -17855 -11239 -15022 -20232 -17390 -21903 -26802 -18439 -22980 -10937 -15621 -18797 -19259 -19088 -12165 -14551 -18623 -13335 -19074 -18525 -14745 -21087 -16087 -13865 -12220 -14494 -15759 -20304 -17407 -14947 -17594 -23580 -14793 -14961 -14153 -15046 -18879 -10617 -14452 -13092 -12998 -18657 -12933 -20195 -16508 -18369 -18989 -18191 -20382 -17622 -23210 -19759 -16167 -13932 -15306 -19363 -16310 -11644 -16261 -17182 -19592 -11381 -23301 -19429 -18536 -15846 -18979 -20772 -19671 -17810 -19633 -23511 -18534 -17165 -24098 -17523 -21881 -18375 -14172 -10366 -18280 -15679 -17502 -16924 -15364 -24497 -14465 -24518 -20921 -18200 -22381 -22818 -18007 -14191 -20692 -15810 -10065 -21328 -12539 -21283 -18696 -15669 -18036 -14375 -14615 -22516 -16196 -20254 -22330 -16964 -17150 -24452 -21621 -22579 -17900 -18540 -16428 -12590 -18168 -15572 -21754 -13854 -21284 -14647 -18434 -19479 -16912 -17580 -18897 -20733 -17795 -14115 -15926 -16707 -25371 -19350 -14247 -19085 -18272 -17792 -15897 -17397 -24073 -11670 -15225 -18565 -20965 -16967 -18376 -20950 -13569 -15915 -16389 -16509 -15237 -15347 -21048 -13986 -16684 -23617 -16593 -22225 -18897 -17861 -19281 -14999 -18600 -23170 -20538 -19531 -22755 -18485 -15628 -13275 -16357 -22956 -17314 -20348 -15211 -23089 -15772 -16697 -20452 -13403 -16549 -14731 -12538 -16760 -20161 -13692 -21664 -19197 -16717 -12685 -15169 -19261 -16562 -16349 -13618 -13121 -20481 -18442 -19552 -12374 -11294 -18044 -23763 -17612 -18435 -25748 -18689 -20778 -10066 -14660 -22628 -23589 -16032 -20893 -11693 -19263 -21112 -19861 -17685 -12650 -17773 -24249 -16457 -19682 -15402 -23040 -21954 -20509 -13796 -18413 -22856 -16379 -20454 -17901 -16687 -14250 -16502 -16151 -15842 -15168 -20107 -16192 -20822 -21488 -18825 -19528 -13939 -16121 -17252 -19527 -18376 -21236 -21136 -14328 -24577 -21964 -20478 -17125 -17099 -20217 -19524 -18139 -18737 -14210 -25847 -15939 -18352 -19724 -17481 -16491 -19321 -13411 -15543 -15225 -21819 -18806 -18144 -15047 -16200 -18350 -13118 -17404 -12584 -22660 -17902 -22627 -13988 -15332 -12866 -20300 -14337 -13237 -16928 -19837 -15988 -14182 -17416 -17847 -15397 -15524 -16764 -18889 -19629 -13896 -16785 -18858 -21608 -13999 -19625 -17578 -17383 -17956 -18727 -15449 -14838 -17572 -23650 -11694 -16583 -20568 -21225 -15432 -18813 -17634 -21444 -13804 -21524 -24165 -16504 -19825 -20128 -16029 -21841 -28253 -20270 -16284 -15575 -19643 -21895 -19321 -22143 -16001 -16911 -17543 -17792 -19170 -18858 -22444 -16275 -21410 -20425 -28279 -19820 -10335 -21079 -14873 -17633 -21040 -15312 -17872 -21640 -15674 -19402 -21176 -18256 -21779 -21451 -19473 -17610 -12619 -18515 -14974 -14514 -18070 -19536 -21403 -18266 -13465 -20294 -18505 -16729 -19294 -15057 -16979 -17068 -16486 -12838 -19076 -12838 -20581 -19420 -15975 -21722 -24005 -17223 -15697 -20416 -17000 -14689 -13811 -15390 -14378 -15119 -16680 -19608 -16223 -14931 -12783 -16527 -21644 -20729 -20608 -17436 -14990 -15905 -23230 -17269 -21787 -21389 -18887 -14838 -20108 -13254 -19256 -13203 -14959 -13572 -16757 -17425 -13926 -24321 -18714 -13451 -17993 -20770 -16203 -20203 -17490 -16372 -21365 -13147 -13630 -17751 -18984 -17453 -21502 -22710 -20299 -18924 -17759 -18389 -17236 -11695 -29186 -15660 -20156 -15866 -21421 -13696 -20618 -21299 -20689 -16568 -21167 -14545 -19985 -18523 -15434 -18336 -19473 -22123 -16422 -17690 -17396 -17165 -15924 -18378 -14967 -18429 -14736 -14193 -16612 -21395 -19261 -17897 -19840 -17717 -16097 -17275 -17324 -19042 -17119 -20721 -14316 -19026 -17806 -18356 -13999 -16630 -15502 -21097 -18887 -17645 -14443 -14723 -19850 -16859 -21200 -19956 -23137 -18487 -22805 -16489 -16261 -12886 -18165 -19899 -15836 -15453 -17220 -21902 -23196 -13225 -17898 -18641 -21524 -13192 -15081 -22681 -14427 -17901 -11341 -16262 -19778 -15609 -24211 -16960 -14781 -14779 -17429 -15121 -19165 -13673 -15278 -17377 -21863 -16829 -14593 -24335 -15980 -19225 -14119 -15241 -15362 -13842 -17488 -19361 -17954 -11944 -19106 -19831 -15950 -18735 -15436 -16079 -14752 -16454 -18797 -21577 -14233 -22689 -14836 -12138 -12693 -22419 -15706 -18347 -18264 -21163 -20780 -15011 -16556 -18034 -18717 -17971 -19026 -8594 -18757 -19258 -16139 -19322 -19460 -16078 -13932 -18112 -13266 -14273 -13959 -20038 -22309 -16986 -18340 -17983 -15063 -13884 -18156 -16718 -20776 -18240 -20952 -24413 -16879 -18507 -15442 -15813 -15202 -16069 -12938 -20521 -13964 -17906 -15123 -15706 -17082 -15120 -20026 -18096 -19364 -15271 -20897 -21246 -16657 -16228 -25665 -14971 -16329 -14496 -14807 -17594 -20682 -16027 -18590 -17471 -19293 -20843 -20754 -13776 -14131 -18690 -19285 -18279 -17415 -15193 -19542 -13102 -18764 -15568 -18102 -13220 -17187 -13632 -20518 -18820 -16143 -18959 -18060 -17352 -21502 -13272 -14836 -16395 -13228 -20243 -18073 -18786 -15163 -20205 -18256 -25105 -19382 -19147 -12931 -19934 -13400 -9747 -15279 -19441 -17412 -16230 -15273 -13675 -18122 -17060 -14622 -18954 -16723 -17399 -17672 -23387 -21639 -16179 -24216 -16447 -20082 -22922 -18844 -25963 -18152 -19589 -16879 -22665 -16504 -26265 -20723 -15870 -16690 -16819 -19082 -19764 -16090 -16971 -14992 -21463 -19771 -14603 -22028 -16320 -18336 -18060 -15907 -17712 -13899 -14873 -19634 -14938 -23263 -20919 -22524 -13806 -18314 -13910 -22578 -19750 -17491 -13720 -14633 -11257 -13120 -18590 -15420 -17972 -17341 -22234 -15546 -20674 -12438 -17111 -21870 -16603 -16320 -16432 -17132 -21019 -22399 -16654 -20219 -24413 -19397 -13329 -19235 -21713 -20229 -12858 -16148 -21146 -20209 -20193 -9788 -17565 -17534 -12766 -17011 -19596 -18988 -22356 -15881 -15352 -17370 -15370 -14553 -14202 -23037 -13009 -15707 -14569 -21845 -16790 -18941 -17671 -10800 -13874 -16196 -16652 -14227 -14737 -18525 -15992 -12642 -16431 -17973 -10892 -19483 -17243 -16949 -24194 -19033 -21192 -18056 -22518 -21312 -12217 -15746 -18901 -24038 -19560 -24603 -16646 -21278 -15553 -16419 -14827 -13303 -17967 -20535 -14129 -24960 -14235 -20971 -16854 -22569 -20133 -17516 -18617 -10800 -8982 -18105 -19015 -24009 -15977 -20271 -21768 -13851 -18228 -23086 -14502 -19711 -14332 -19627 -12765 -21910 -13764 -14922 -16805 -16428 -20119 -15696 -20208 -15418 -13438 -16507 -12116 -17491 -17677 -17376 -15591 -18707 -16934 -16963 -18960 -15937 -15615 -20270 -20196 -14457 -15112 -19639 -15818 -20565 -19982 -16615 -16197 -18971 -16102 -17519 -15815 -17731 -22114 -20740 -18234 -15335 -21099 -16857 -15273 -17763 -20882 -13931 -18167 -21456 -19124 -13001 -20525 -16499 -16414 -15859 -18271 -14250 -16349 -20525 -17437 -19490 -19966 -19036 -17536 -18442 -18132 -16318 -22166 -22028 -17593 -16697 -14899 -18999 -16398 -13917 -22480 -11853 -21095 -19256 -15881 -15909 -20257 -16055 -15007 -15735 -16969 -19849 -18422 -18591 -17435 -18409 -18531 -17607 -19179 -16953 -17595 -24840 -14569 -16437 -18501 -15521 -22048 -15791 -11011 -16838 -14875 -18113 -14542 -21243 -19738 -16473 -16116 -15239 -11987 -16740 -15849 -18367 -15831 -19592 -20054 -21952 -23440 -21364 -21232 -20973 -17851 -19139 -20213 -17173 -15024 -20451 -12477 -22909 -18251 -15132 -17313 -18139 -16755 -10633 -17985 -20280 -16817 -17859 -12562 -21699 -20900 -19243 -22015 -22143 -17223 -18479 -19272 -17950 -22494 -19883 -15170 -12385 -14845 -22508 -19084 -21751 -23176 -20831 -17199 -15103 -14987 -16540 -19704 -12574 -20315 -14769 -8053 -18585 -20001 -18997 -22962 -21003 -19045 -17983 -16712 -11713 -16480 -24041 -12277 -22244 -18761 -16219 -16315 -19870 -15680 -19579 -17958 -17377 -21293 -18772 -21000 -15023 -22555 -16818 -19811 -16124 -16367 -15991 -23046 -18935 -20812 -16799 -13430 -17987 -20083 -19875 -17296 -11246 -17974 -13140 -18566 -13420 -13132 -11470 -14584 -16969 -12651 -15238 -21626 -16267 -18741 -21920 -15438 -18481 -18512 -15838 -16681 -16031 -17757 -26037 -19561 -12655 -18780 -15808 -16185 -15289 -17738 -16918 -16487 -20685 -16669 -14694 -21893 -15632 -16271 -16973 -22382 -20302 -17244 -16911 -21506 -18839 -17768 -14844 -15786 -17989 -21827 -19652 -19759 -19901 -21158 -21063 -16051 -17343 -16613 -17676 -25306 -15915 -14225 -14146 -17188 -17861 -15438 -15723 -15651 -23770 -13068 -11319 -15636 -17884 -14188 -18935 -15075 -17790 -22877 -18676 -16083 -16878 -19718 -17675 -12704 -15688 -22223 -16083 -20882 -13528 -19755 -15062 -21441 -20814 -17574 -14145 -20158 -17397 -18351 -16277 -22369 -17774 -19260 -23481 -21384 -14446 -14901 -14359 -19306 -24588 -22363 -21242 -17184 -19789 -17209 -21361 -18004 -18089 -20211 -26646 -16267 -17887 -16305 -14117 -15794 -13713 -19639 -16997 -14184 -14292 -17171 -25595 -23005 -14461 -16813 -20072 -16004 -22916 -10715 -16260 -17613 -14357 -12688 -18136 -19295 -18636 -17653 -17538 -22153 -19483 -25167 -18845 -17629 -25719 -16110 -13059 -18067 -18245 -13852 -12717 -26294 -22469 -18908 -16823 -14152 -15235 -18325 -23732 -19400 -18795 -20112 -20435 -14021 -19322 -20213 -20036 -14038 -17644 -15550 -20626 -18001 -21727 -18795 -29270 -18635 -17967 -11934 -20288 -19598 -14727 -13830 -17595 -18875 -18754 -21894 -13837 -17262 -21349 -16617 -11763 -15854 -17421 -14858 -16151 -11492 -16783 -17563 -14476 -20917 -18873 -18884 -15927 -18605 -21484 -14086 -15766 -14275 -24413 -18031 -18279 -21299 -16434 -17919 -18148 -19642 -21319 -20563 -21726 -23209 -26349 -20982 -18325 -22260 -17081 -18288 -22575 -21924 -16195 -14432 -17693 -17711 -18401 -21878 -17452 -20481 -15147 -20396 -17948 -16846 -15751 -16852 -17290 -13611 -20940 -21258 -17613 -16328 -11581 -19270 -19283 -18857 -11703 -19076 -14508 -20038 -18232 -20430 -15327 -21390 -11215 -22931 -15080 -20189 -14448 -19531 -19744 -13290 -22511 -16728 -18347 -15823 -21316 -24400 -14574 -15102 -22036 -15150 -21079 -15349 -18153 -21033 -18170 -22438 -18375 -10458 -18749 -19161 -22012 -14509 -13267 -15975 -15873 -18219 -14549 -18751 -17969 -14122 -17554 -15868 -22533 -18603 -18044 -21958 -25054 -19820 -18259 -17005 -14675 -16030 -25976 -22514 -17031 -14567 -17524 -12067 -19396 -21660 -21591 -19070 -17545 -19098 -17856 -22629 -20484 -16079 -24416 -15185 -25042 -16475 -15527 -16536 -19731 -21871 -18390 -12422 -18165 -16638 -18342 -16356 -19579 -21302 -20076 -17462 -19937 -24237 -19599 -18026 -16827 -19308 -18050 -21718 -16102 -16528 -20000 -19127 -16609 -14743 -16237 -18827 -21463 -16814 -23228 -16008 -13631 -14505 -14098 -10334 -11675 -14784 -14790 -14053 -17332 -11340 -18398 -15671 -19479 -12401 -12458 -18976 -13579 -16102 -16728 -16027 -15824 -12406 -12242 -21226 -17414 -22657 -17584 -16340 -14189 -26143 -23240 -18572 -10562 -12585 -16298 -17102 -15692 -23202 -15638 -19322 -22170 -21063 -27694 -19048 -15135 -15246 -23217 -13967 -18340 -12954 -18588 -25994 -20652 -14856 -21944 -21387 -16325 -17898 -17726 -18816 -20144 -22884 -13782 -17077 -19930 -19051 -18179 -14641 -18778 -18032 -16030 -20223 -17962 -18052 -17546 -17698 -18811 -28329 -19495 -22895 -14525 -14342 -25042 -15216 -16303 -15501 -12604 -21042 -20159 -14985 -12553 -16536 -16644 -18667 -17179 -13843 -17973 -18139 -21604 -11996 -16706 -19407 -17804 -18655 -14587 -15210 -17623 -15533 -21024 -15168 -18443 -15388 -19104 -19604 -16428 -18506 -15992 -19163 -16212 -16185 -11590 -14851 -19541 -17147 -16596 -16657 -18626 -17154 -17408 -21308 -20021 -16756 -21328 -11374 -12860 -16506 -15515 -15721 -14514 -19027 -15366 -19898 -20997 -22659 -13894 -20984 -16886 -14030 -20377 -17728 -12539 -17574 -18079 -16118 -14319 -17662 -15864 -14651 -21235 -16598 -16895 -17603 -14204 -17308 -19450 -16538 -23645 -17896 -15724 -22517 -17621 -14584 -19618 -19348 -16515 -18430 -24068 -15423 -19838 -10921 -17152 -21373 -17757 -15683 -17352 -11949 -18879 -19120 -17349 -14534 -21978 -15829 -20028 -8755 -15031 -14555 -19583 -13183 -15975 -17410 -15516 -18241 -13977 -14761 -15165 -16451 -17442 -20302 -16949 -24397 -22088 -16030 -22936 -15798 -16925 -22165 -21630 -13971 -18943 -14076 -20216 -21552 -26008 -13662 -19042 -18194 -18397 -17124 -13727 -19548 -19469 -12288 -23207 -16685 -20221 -17248 -13529 -19256 -15765 -18363 -15219 -17178 -15001 -11668 -14993 -13798 -19363 -22946 -21294 -18220 -14075 -23590 -17155 -20759 -11914 -18944 -20702 -14798 -16085 -20353 -16418 -20120 -21073 -21494 -19338 -22538 -19125 -19193 -13820 -19532 -15298 -12548 -20859 -14314 -16761 -13411 -16579 -11880 -15821 -21550 -16024 -16600 -16873 -14724 -18476 -16773 -17329 -24006 -20470 -17100 -15291 -13716 -13440 -24599 -18360 -18370 -20162 -18965 -12261 -17102 -16834 -16271 -13269 -14079 -17249 -17848 -12107 -18894 -17148 -21677 -14050 -16847 -20892 -18898 -19771 -14661 -15260 -17758 -21721 -23909 -14596 -12152 -18805 -17237 -16295 -17075 -20538 -14991 -18939 -11080 -17839 -29358 -15196 -17714 -16966 -21617 -21826 -21505 -16897 -18403 -15847 -13170 -13121 -13726 -14726 -15416 -17332 -22395 -16883 -14232 -18803 -19380 -16852 -18309 -19644 -20983 -27080 -17774 -16600 -19040 -14693 -22701 -19952 -13358 -18418 -18969 -19363 -13263 -13112 -20901 -16373 -12505 -14775 -18633 -17080 -18275 -15002 -28040 -21928 -14960 -17812 -13198 -23484 -18159 -20510 -22707 -22538 -18098 -24672 -15887 -16918 -16183 -16203 -21345 -18945 -13583 -18771 -18766 -18982 -16349 -19058 -15517 -15539 -15506 -20317 -17668 -20229 -25130 -18041 -11972 -17080 -19816 -23200 -14375 -18977 -13326 -17338 -16363 -16435 -17431 -17749 -19711 -16808 -15690 -14306 -14739 -20400 -11782 -19029 -15496 -16598 -24029 -14060 -17547 -12520 -21704 -20912 -17818 -18255 -23450 -20453 -18923 -17697 -16588 -15743 -15708 -16108 -23049 -18315 -14823 -14981 -19033 -19586 -16963 -18465 -17843 -22221 -13217 -16460 -15509 -16453 -16738 -19736 -15054 -20593 -14785 -22781 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k4/trained_ddqn/best.pt deleted file mode 100644 index 5058f8b4ea741832ba3d1f8f65bbb2ad0d38f7a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/dqn.txt deleted file mode 100644 index c16e5978b..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4956 -5579 -5560 -3659 -6025 -3950 -4284 -4134 -4717 -5143 -5236 -4722 -5942 -3550 -6575 -4951 -3127 -4863 -3945 -5043 -4878 -4558 -4028 -5221 -5594 -5057 -3776 -3278 -5283 -5166 -3315 -4385 -3938 -6235 -5024 -4792 -3788 -5379 -4857 -4050 -4678 -4131 -5622 -4662 -6068 -4523 -4373 -4692 -4967 -3777 -4322 -4592 -4429 -4541 -4496 -2944 -3576 -5446 -4844 -4252 -5041 -5583 -4182 -4552 -5274 -4724 -4622 -5182 -3957 -4640 -3958 -4528 -5340 -5458 -5267 -3328 -4498 -4052 -4499 -6587 -4306 -4778 -4467 -4758 -3966 -3947 -5328 -4798 -5304 -3375 -4167 -5020 -4184 -3734 -3049 -6122 -4709 -4988 -6796 -3785 -4771 -3318 -3848 -2662 -4076 -5202 -5285 -4247 -4899 -5771 -3938 -4719 -6349 -3723 -5416 -5595 -4939 -5607 -4580 -6441 -3879 -5099 -4293 -4506 -4834 -4071 -4889 -4207 -3803 -2947 -5188 -4737 -6130 -6864 -4442 -4539 -4363 -4073 -4218 -5465 -3574 -5456 -6318 -3127 -3871 -4189 -4112 -6699 -5481 -4923 -4294 -4291 -5144 -4988 -5205 -5605 -4865 -3201 -3738 -3231 -5650 -6036 -5766 -4507 -5281 -3770 -5174 -5028 -4689 -4190 -4783 -4507 -3918 -4211 -2256 -4757 -4394 -3080 -4947 -5333 -3707 -5012 -4044 -4605 -3540 -3547 -5530 -4069 -4756 -4138 -3958 -4127 -4655 -4671 -3297 -4476 -4970 -4394 -5637 -4846 -3707 -4414 -3931 -4968 -5475 -4938 -5354 -5149 -3917 -3905 -4183 -3492 -3864 -5507 -4059 -4681 -3919 -5770 -4896 -5247 -4650 -3960 -4218 -5645 -5317 -4724 -4502 -5029 -4489 -4209 -7374 -6218 -4996 -5699 -4590 -4348 -5769 -5755 -4819 -3800 -4219 -4816 -2851 -4301 -4773 -5153 -3529 -4646 -4237 -4785 -5100 -3884 -4239 -3857 -4096 -4584 -4245 -4984 -4774 -4926 -4726 -5159 -3754 -4487 -4893 -4008 -3175 -3485 -4671 -3138 -4963 -5618 -4022 -4103 -3515 -6649 -5360 -4675 -3350 -3747 -5008 -4316 -4132 -4941 -5374 -5397 -5811 -4160 -4579 -5263 -3203 -2985 -5540 -4539 -3334 -5469 -3590 -5548 -4434 -4912 -5121 -4193 -4452 -3772 -4703 -3592 -4268 -4430 -5238 -5636 -4392 -4704 -3293 -4459 -4688 -6972 -4201 -4768 -4944 -4181 -4560 -3124 -3974 -4155 -4577 -4741 -3891 -5970 -2710 -2774 -3376 -4992 -5109 -3955 -4428 -3967 -5015 -4669 -4248 -5979 -2785 -3411 -5090 -6321 -4548 -5744 -4393 -4500 -3600 -3614 -4960 -4414 -5094 -5240 -4301 -6135 -5206 -3169 -3869 -4471 -4042 -3731 -4910 -3725 -5251 -5032 -4366 -4349 -4190 -6074 -4586 -5375 -2965 -4905 -4480 -5811 -5185 -3858 -5910 -4994 -3287 -4275 -3827 -3733 -5189 -4067 -5299 -5173 -3790 -3614 -4420 -3670 -4973 -3975 -5913 -4929 -4722 -3720 -4500 -3530 -5787 -4833 -4929 -4537 -3426 -4303 -6410 -3121 -3832 -4282 -4372 -5273 -4945 -4034 -4194 -4087 -5214 -4169 -4609 -3347 -4113 -5771 -4148 -4378 -3748 -4860 -4835 -4499 -5378 -3663 -4589 -4774 -4840 -4320 -5912 -6026 -5361 -4680 -6267 -4811 -5073 -7397 -5069 -3083 -3647 -4299 -4551 -4386 -2953 -4279 -5083 -5596 -4570 -4608 -3977 -5292 -3850 -4658 -4207 -4193 -4685 -4251 -4355 -5010 -4448 -5765 -5175 -6621 -4428 -3983 -5021 -4979 -6210 -4413 -4379 -4901 -4176 -5001 -4423 -4524 -3489 -5142 -5190 -5445 -4817 -3682 -5221 -6280 -3506 -4975 -3991 -4953 -5009 -5276 -3152 -3600 -3542 -3373 -7066 -4077 -4269 -4758 -2763 -4013 -6571 -5412 -5000 -5568 -3753 -3456 -4198 -4599 -5323 -4493 -3400 -4579 -6133 -4663 -5004 -5386 -4348 -4458 -4850 -6011 -4460 -4160 -4327 -3404 -3822 -6538 -3947 -4747 -5662 -4378 -5574 -5361 -4905 -4240 -4164 -4672 -4590 -3423 -5276 -4086 -5321 -5465 -5442 -5789 -3208 -3001 -4183 -4832 -4687 -5302 -5361 -3120 -5305 -5432 -6114 -7359 -4993 -4943 -4265 -3956 -5124 -4434 -3504 -4887 -6889 -3476 -4052 -3894 -5305 -4622 -5380 -3520 -5625 -4426 -6333 -4811 -4253 -3411 -4319 -4243 -5149 -4405 -6491 -3916 -5223 -4709 -4644 -3831 -5944 -4832 -4873 -4607 -3264 -4095 -4071 -4440 -6078 -4300 -4388 -6037 -4459 -5215 -4202 -3409 -4016 -4535 -3892 -3772 -4845 -4227 -4472 -4017 -4227 -4230 -3283 -4130 -3888 -4096 -6054 -5834 -4927 -3861 -4529 -2284 -4371 -6114 -4967 -4762 -4446 -3902 -5232 -5799 -2650 -3688 -4334 -4497 -3968 -4502 -4985 -4021 -5108 -4980 -4461 -5237 -3876 -3956 -5023 -5350 -6093 -3567 -4338 -4812 -5059 -4987 -5431 -5786 -5557 -4912 -4025 -5517 -3401 -3149 -4876 -4790 -5288 -4805 -3942 -4158 -4544 -4510 -3329 -4514 -4818 -3521 -3799 -5974 -4127 -4963 -4244 -4837 -4148 -4508 -4814 -6092 -5441 -4632 -4391 -3934 -5076 -2653 -5035 -4723 -4969 -3721 -3753 -3447 -4239 -3903 -6234 -4602 -5446 -3797 -4270 -4848 -3553 -4378 -5039 -4992 -6256 -3726 -6516 -4880 -4262 -4769 -5936 -3400 -3890 -5407 -3880 -4401 -4745 -4159 -4876 -4569 -5581 -4928 -4724 -2788 -5594 -3406 -6100 -5384 -3513 -4057 -5130 -4310 -4488 -5950 -4627 -5451 -3386 -5711 -4541 -3962 -4397 -4612 -4120 -3606 -4909 -4590 -5141 -4242 -5138 -3791 -5103 -3824 -4746 -4427 -4548 -5979 -4300 -3876 -3654 -5484 -3220 -4897 -4228 -3731 -5710 -4682 -5279 -4054 -3567 -4887 -4042 -3886 -3021 -4318 -3626 -5085 -4538 -4016 -7274 -4680 -3571 -3444 -3111 -4629 -4718 -3983 -5293 -4924 -4682 -6629 -4391 -4839 -3263 -5065 -4366 -4366 -4352 -4927 -5287 -3428 -4988 -4008 -4027 -6096 -4454 -4814 -4143 -4535 -3967 -6423 -5589 -4930 -2950 -4291 -5059 -4578 -4749 -4271 -4208 -4290 -4002 -5076 -5138 -4453 -5176 -4351 -5277 -5731 -4049 -6120 -4462 -4649 -6118 -4061 -3528 -3498 -3238 -4612 -4470 -3375 -4613 -5188 -4082 -5528 -5000 -5512 -4214 -3688 -4316 -4159 -4317 -5243 -4466 -4593 -5843 -3497 -4756 -4935 -3997 -4409 -3837 -4301 -4599 -3638 -6504 -4920 -4445 -5420 -4318 -6138 -2915 -4860 -3575 -5392 -3502 -3754 -5069 -4043 -4151 -4610 -4549 -4464 -4991 -4598 -3450 -3361 -5500 -5131 -5101 -3658 -3433 -3842 -4349 -3710 -4592 -4310 -4835 -6054 -4906 -4979 -4981 -4433 -4202 -4441 -5384 -3339 -2867 -5698 -4263 -4849 -4311 -4519 -4005 -4439 -5623 -5889 -3694 -4711 -5007 -5462 -3752 -3842 -5098 -4461 -3636 -3969 -7078 -4418 -5789 -5392 -4912 -4661 -4453 -5061 -6211 -4911 -3155 -3556 -6946 -5131 -4307 -5477 -4356 -6184 -3270 -4717 -3903 -2511 -5109 -6001 -4733 -4357 -4863 -7021 -3702 -4222 -3599 -3762 -4095 -5363 -3103 -3754 -4082 -3731 -6068 -4133 -5124 -3364 -3231 -4014 -3792 -3455 -4703 -4127 -4049 -4679 -5358 -4814 -4758 -4931 -2981 -5244 -3697 -4210 -4892 -4573 -5214 -5335 -4578 -5234 -4216 -4791 -4928 -4674 -2991 -4971 -4566 -4219 -4010 -3972 -5140 -5362 -5251 -5673 -3125 -4118 -5237 -5680 -5729 -5854 -4325 -2728 -4952 -5846 -4489 -4019 -5302 -2702 -4791 -4261 -3980 -2990 -5059 -3950 -4308 -4209 -4682 -4669 -3865 -4579 -4036 -4318 -4628 -4547 -5421 -3882 -5732 -4484 -4547 -4681 -4936 -4838 -5023 -5241 -4559 -5212 -3904 -3859 -5861 -3875 -6049 -3672 -6354 -3559 -4273 -4601 -4724 -5562 -3182 -5990 -4903 -4063 -4807 -3640 -4355 -3541 -3328 -4585 -4692 -3858 -4667 -5873 -5728 -2794 -3756 -4184 -5524 -3813 -6664 -4992 -5317 -4046 -5251 -4578 -4041 -4599 -5094 -3784 -3902 -5774 -3334 -4726 -4204 -4165 -3383 -3489 -3682 -4416 -3504 -3720 -5873 -4393 -4170 -4521 -5308 -4052 -3937 -5381 -2570 -4649 -5246 -5629 -5141 -4656 -5451 -3960 -3729 -3993 -3385 -5581 -5232 -3742 -4191 -5430 -4764 -3748 -3371 -4629 -3408 -3500 -4803 -5608 -5324 -3864 -3284 -5461 -4096 -4408 -5588 -4350 -5093 -3953 -4176 -4337 -4710 -3680 -5137 -4654 -4236 -3289 -4478 -4307 -4381 -5161 -5226 -4091 -4168 -5397 -5043 -5245 -2745 -5169 -4749 -3786 -4865 -6545 -3732 -4040 -4553 -4827 -5662 -3089 -4399 -4426 -4660 -3892 -4989 -4602 -4771 -5145 -3606 -3339 -5565 -3508 -4756 -5789 -4473 -4056 -4625 -3170 -4262 -5228 -3925 -5749 -3578 -5479 -4121 -5232 -5817 -5294 -3148 -5563 -5197 -7260 -4794 -4216 -4649 -4968 -4893 -3117 -4442 -5210 -4466 -4857 -3483 -6068 -3192 -4504 -5676 -5223 -2473 -4045 -5496 -4264 -5904 -3612 -5362 -4509 -5210 -3874 -4186 -3740 -5197 -4052 -3687 -4556 -4060 -3940 -3692 -3419 -5054 -3858 -5515 -5114 -4946 -4387 -5150 -3886 -3902 -4217 -4075 -4339 -4685 -3244 -4226 -4179 -3407 -5048 -4204 -5195 -4567 -3482 -4988 -5406 -3688 -4402 -4387 -4247 -2868 -4507 -3416 -5387 -5480 -5445 -3734 -4565 -4783 -5260 -4327 -3785 -5359 -4842 -5338 -3906 -3964 -3238 -4939 -4301 -4140 -4141 -4089 -5337 -4347 -5453 -3424 -3438 -3176 -5789 -4263 -4209 -4515 -4124 -4542 -4475 -6099 -4408 -4279 -6042 -4694 -5130 -4597 -4974 -4728 -4685 -4090 -4755 -4207 -4532 -4944 -3528 -4588 -3796 -4506 -3283 -3899 -4264 -5089 -5216 -4180 -4668 -4375 -5586 -5575 -4371 -6715 -4634 -4645 -5416 -3722 -3156 -4086 -5182 -5084 -5028 -3227 -5268 -5132 -3970 -4001 -5821 -3856 -5217 -4604 -3545 -5407 -4284 -4154 -4345 -3929 -3677 -4688 -3691 -4888 -4412 -4601 -5098 -3970 -4916 -3242 -4508 -5602 -4295 -5257 -5288 -3392 -4133 -3947 -3535 -4485 -5186 -4601 -4040 -4510 -5512 -3857 -4114 -5178 -3187 -2779 -4363 -4406 -4206 -4217 -5897 -4207 -5532 -4921 -5217 -4214 -4134 -5694 -4785 -3354 -3922 -4264 -5631 -5126 -4665 -4294 -5798 -4694 -4716 -5072 -4031 -4741 -3877 -3763 -4293 -3586 -6136 -3132 -3873 -4217 -3699 -5037 -4371 -3582 -4136 -3900 -4721 -4309 -4065 -3792 -5450 -4780 -4799 -5443 -5180 -4266 -4854 -4547 -5281 -4773 -4672 -3131 -4583 -3824 -4450 -4516 -3896 -4195 -4484 -5366 -5844 -4984 -3256 -5325 -3964 -6807 -3644 -4535 -5907 -5441 -5210 -4542 -4875 -4654 -6432 -3626 -5282 -4587 -3796 -5140 -6490 -3332 -4355 -3407 -4758 -4066 -3949 -4678 -4071 -5859 -5733 -3876 -4032 -5619 -3499 -3062 -3891 -4641 -5214 -4154 -4184 -5385 -4025 -4951 -3777 -4055 -3504 -4501 -4352 -3501 -4285 -4363 -3821 -4941 -6057 -3332 -4865 -4928 -4439 -3970 -4218 -3745 -4722 -4029 -5195 -5979 -4956 -5737 -4420 -6443 -4424 -6146 -4020 -4432 -5311 -5367 -3337 -6144 -3969 -3659 -5059 -4504 -4633 -4087 -5063 -4685 -4418 -3570 -4952 -4571 -5404 -4918 -3736 -4983 -4533 -4177 -6199 -3588 -4391 -4394 -3607 -4272 -3341 -4402 -3788 -5171 -3500 -3697 -2911 -4892 -3783 -5462 -3790 -3463 -5526 -3831 -3809 -5003 -3818 -5949 -5066 -4491 -5343 -5100 -3702 -3979 -5192 -4804 -3895 -5762 -5456 -3450 -5070 -6323 -3206 -6611 -5243 -5172 -4659 -4029 -5047 -4664 -6118 -4898 -4041 -3123 -4836 -5538 -4021 -4502 -4728 -4861 -4210 -4904 -3942 -4273 -3953 -6107 -4698 -5481 -5047 -5093 -4669 -3990 -3885 -4596 -4461 -4755 -4119 -5969 -3112 -3191 -2427 -4647 -5549 -4632 -4610 -4136 -3525 -4650 -4190 -4204 -5429 -5519 -4506 -4712 -3898 -4102 -3173 -6159 -4626 -5356 -4044 -5166 -5489 -3964 -5323 -3904 -3925 -3095 -4327 -4613 -5620 -4690 -5241 -3881 -5415 -4303 -4409 -4365 -4656 -4886 -4674 -3956 -4628 -4541 -5224 -4731 -5527 -4158 -5733 -4011 -4598 -3232 -4927 -5386 -3178 -5007 -4344 -5829 -4815 -3764 -4159 -6076 -5319 -3975 -4837 -4408 -5671 -4007 -4655 -4997 -4108 -2228 -5825 -4030 -3376 -4382 -5153 -5233 -4542 -3790 -5816 -4349 -3909 -5512 -5314 -3120 -4343 -4128 -3796 -3571 -4500 -4238 -3424 -4127 -2964 -4452 -4081 -4528 -3959 -4161 -3909 -3994 -4895 -5174 -4807 -3250 -4038 -3627 -4124 -4903 -4670 -3825 -4477 -4545 -4261 -3520 -5765 -3971 -4156 -4829 -4243 -4731 -5340 -3933 -4732 -5881 -4066 -4582 -4489 -4651 -4840 -4707 -4509 -3592 -4497 -4898 -3962 -3224 -4027 -4692 -4015 -4281 -5214 -5506 -4042 -3402 -4593 -3853 -4483 -4674 -4500 -5095 -4311 -4623 -3904 -5293 -4613 -5597 -3709 -5322 -4529 -3495 -3934 -2370 -4832 -4221 -4895 -4528 -4663 -4503 -3526 -5381 -3912 -3760 -3756 -4841 -3021 -4337 -5051 -4592 -3902 -4976 -5046 -2968 -4885 -4291 -5884 -5590 -4639 -5456 -4134 -4772 -5056 -3836 -4000 -2979 -4343 -4696 -5142 -2966 -3767 -3546 -4823 -4527 -5562 -4429 -4027 -6146 -5226 -4713 -4245 -5233 -2886 -4119 -4609 -4572 -6016 -3023 -4420 -4732 -4815 -3766 -4549 -4561 -4939 -4856 -4911 -4348 -4377 -5008 -5205 -4551 -5398 -5866 -3675 -4884 -4878 -2982 -5103 -5511 -5132 -5519 -3867 -5190 -2856 -5487 -5021 -6010 -3363 -5104 -4008 -3469 -4433 -2963 -4686 -4390 -4552 -3748 -4465 -4111 -4414 -4427 -3998 -5104 -4021 -4158 -3587 -3991 -5333 -4528 -3709 -5062 -4304 -4951 -4684 -3806 -4248 -3933 -3752 -4917 -5059 -4556 -3782 -5792 -3719 -5265 -3166 -5153 -4418 -4513 -4842 -3665 -4784 -4947 -4194 -5265 -5095 -5363 -4786 -3030 -4777 -3997 -4473 -4670 -4068 -3908 -3229 -5072 -4703 -6117 -3380 -3499 -3360 -4665 -3968 -4447 -3790 -3244 -5038 -5766 -5274 -5716 -4307 -3591 -3400 -5175 -3855 -4269 -5229 -3069 -3530 -5877 -4159 -3977 -4448 -4316 -3380 -4944 -5051 -4783 -5403 -5127 -4416 -4847 -5216 -4842 -4140 -4028 -5577 -6184 -5194 -4708 -5321 -4570 -2686 -5280 -4631 -4552 -3463 -4377 -3117 -3699 -2867 -6013 -4770 -3809 -4160 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/optimal.txt deleted file mode 100644 index 0686bf9a6..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -5123 -5579 -3726 -4766 -6189 -4365 -4497 -3356 -5567 -3012 -5642 -4144 -4853 -6863 -4544 -3933 -4589 -4858 -5204 -3169 -5215 -3809 -5887 -5281 -4435 -3862 -3642 -5002 -5283 -3916 -5128 -3701 -5344 -4971 -4928 -4868 -3788 -6045 -4857 -5571 -4712 -5008 -5721 -4302 -5021 -5177 -3253 -3739 -4880 -4056 -4974 -3851 -4891 -4603 -3372 -5530 -3087 -5233 -4277 -4630 -5148 -3778 -4244 -4139 -5055 -3685 -4041 -5342 -4779 -3612 -5006 -5550 -3495 -4651 -4334 -3763 -4056 -4359 -3490 -6587 -3377 -5488 -5505 -3762 -4608 -4761 -4334 -5688 -4323 -3109 -2836 -4482 -5550 -4893 -3049 -4217 -4784 -4463 -5001 -3466 -3370 -4718 -4897 -4570 -3751 -4607 -4526 -4089 -3907 -4477 -4169 -4363 -4490 -3723 -3696 -4355 -5293 -4476 -3940 -5262 -5676 -5099 -3806 -3613 -4776 -4061 -4047 -3942 -3003 -3211 -4428 -3289 -5933 -3499 -5193 -5519 -3216 -5596 -5931 -4058 -4368 -4560 -4571 -3882 -4957 -4102 -5357 -5483 -3814 -4110 -4496 -4783 -3920 -3121 -4044 -4850 -4700 -4879 -6147 -3351 -4893 -4002 -4316 -4507 -5951 -4176 -3515 -5597 -3737 -4719 -4083 -4947 -3564 -4778 -3897 -5641 -5056 -5492 -3432 -5581 -4179 -3849 -4626 -3191 -3956 -4167 -4860 -4673 -4246 -3672 -4270 -4947 -5235 -4650 -4810 -4476 -3669 -5083 -4801 -3401 -4889 -4983 -3643 -4602 -5524 -5255 -4794 -5428 -5556 -5133 -4815 -3560 -5271 -4422 -4059 -5212 -4641 -4154 -4910 -3777 -3983 -4187 -4138 -4022 -5128 -5284 -4760 -3007 -4281 -5403 -3832 -6218 -4426 -4624 -4543 -5642 -4179 -5402 -4460 -2726 -4022 -3525 -6162 -5213 -5358 -4867 -4974 -4589 -3805 -3274 -4500 -3299 -4950 -3801 -4307 -4460 -5119 -4489 -5312 -3993 -5133 -5491 -3569 -3772 -4647 -4398 -3722 -5789 -3592 -5960 -4382 -3592 -4022 -4172 -4087 -3961 -3343 -4130 -5588 -3650 -5159 -4936 -3925 -4320 -3689 -3603 -4209 -4038 -3521 -5042 -2870 -4429 -3736 -5559 -3438 -5757 -3924 -3603 -4045 -4972 -5435 -4193 -3855 -4102 -4670 -5617 -4481 -4702 -3704 -4535 -5530 -3200 -3709 -3709 -5567 -3902 -3401 -5752 -6094 -3834 -3263 -4895 -3974 -5066 -3633 -4675 -4633 -5342 -4227 -5370 -5102 -4697 -5688 -4622 -6292 -3975 -3240 -4513 -4057 -5131 -5013 -7135 -4660 -5159 -4548 -4998 -4618 -5026 -4717 -5100 -4101 -5266 -4255 -6519 -4870 -4502 -5960 -2950 -5610 -4724 -5033 -5440 -5698 -3725 -5353 -3791 -4693 -5149 -6343 -4454 -4023 -5562 -4065 -4274 -3546 -5484 -4978 -4641 -3119 -4891 -4257 -5159 -3785 -3617 -4584 -3819 -3843 -5173 -3691 -5681 -4914 -4351 -3526 -4895 -5913 -4807 -5799 -5612 -3595 -5282 -3853 -5320 -5836 -4289 -4769 -2526 -4900 -4568 -5051 -4385 -4675 -3592 -3556 -4110 -3872 -4410 -4775 -4088 -3645 -4860 -4313 -3784 -4026 -4712 -4619 -5394 -4328 -4142 -4279 -5815 -5740 -4339 -4345 -3640 -3592 -4704 -4552 -4848 -4723 -5132 -4678 -4909 -5686 -3854 -4451 -4518 -4551 -3871 -4286 -3856 -4530 -4388 -3913 -5007 -4002 -5490 -5445 -4868 -4811 -4118 -5269 -4695 -4230 -4789 -4448 -3366 -4189 -4890 -6534 -2887 -4399 -4318 -5861 -5438 -6120 -5431 -4677 -4432 -3992 -4261 -3474 -5383 -5779 -4116 -5217 -3891 -4042 -4407 -5151 -5219 -4267 -4436 -4153 -5112 -5766 -3600 -5806 -4795 -4221 -4080 -5390 -3583 -3600 -5145 -4363 -4194 -4359 -3520 -4609 -6133 -4198 -4842 -5225 -4920 -4568 -3952 -4588 -5689 -4151 -5519 -4166 -4458 -4721 -5204 -3692 -5614 -3487 -4913 -3822 -5685 -3548 -3052 -4405 -4140 -4388 -4115 -5590 -4901 -5851 -2120 -4640 -3789 -3774 -5473 -3253 -4530 -5926 -3626 -5171 -3676 -4467 -5182 -5458 -3410 -4186 -5256 -4744 -4971 -4841 -6250 -2994 -4564 -4448 -3238 -3839 -4890 -4201 -4512 -4309 -3536 -4834 -4077 -4407 -4764 -5008 -3235 -5625 -6476 -3543 -4252 -4253 -3411 -4959 -4660 -4306 -4202 -5419 -5429 -4756 -5919 -4810 -3831 -3765 -3987 -3784 -4614 -3368 -3251 -4311 -4029 -6078 -4780 -3285 -4806 -3963 -5215 -5482 -4349 -4936 -4689 -4176 -5934 -6476 -4227 -5474 -4346 -4086 -3383 -3283 -7164 -4997 -2993 -6054 -4507 -3961 -3894 -4736 -4952 -4371 -6728 -3812 -4821 -7419 -5339 -3321 -4328 -4337 -4945 -3629 -4598 -3686 -3617 -5631 -4663 -4206 -4468 -4461 -4511 -3754 -3768 -5291 -4041 -3203 -4162 -5174 -3802 -5560 -2598 -5003 -4759 -5898 -3598 -3512 -5429 -4358 -5731 -3768 -5104 -3052 -3917 -5932 -4628 -4647 -4360 -4147 -4961 -4935 -4451 -3829 -6203 -6410 -5159 -4276 -4572 -4281 -4441 -4549 -4640 -5441 -4367 -3455 -3934 -4955 -4764 -3900 -4936 -5132 -3391 -4451 -4302 -6348 -3573 -6234 -4283 -3564 -4440 -6099 -4608 -4851 -5707 -4836 -4309 -6256 -4102 -3667 -4687 -4704 -3853 -3230 -5692 -4676 -4380 -5483 -6057 -3250 -4143 -4876 -4308 -4544 -3572 -6301 -4729 -4603 -4999 -5984 -6195 -4621 -5038 -3765 -3400 -5737 -5168 -3954 -3640 -3923 -4862 -2913 -3962 -4010 -3722 -4057 -3454 -4699 -4724 -2902 -4242 -4070 -4432 -4821 -5074 -4392 -3354 -6520 -6039 -6066 -3667 -3872 -6160 -4244 -4530 -4386 -4791 -3724 -5199 -5993 -5778 -4322 -4171 -3532 -5002 -5594 -4355 -3626 -4323 -4424 -5404 -4818 -5391 -4082 -5818 -4365 -3874 -5081 -3462 -4217 -4673 -5718 -4390 -3273 -5271 -3886 -4159 -4496 -5152 -4445 -4405 -4218 -5029 -4322 -4829 -4027 -4454 -5009 -4814 -4285 -4881 -4667 -5545 -3849 -4613 -5076 -3944 -3677 -4139 -4397 -4639 -4782 -3521 -4964 -2806 -4558 -4925 -3871 -3341 -3807 -5337 -3566 -5063 -4462 -4222 -4565 -5366 -5419 -4769 -5642 -5525 -4768 -3375 -4198 -6997 -5092 -5222 -4565 -3874 -3505 -5042 -5165 -5022 -4317 -4693 -3713 -3797 -4355 -5362 -4272 -4868 -4129 -4592 -4744 -2956 -4261 -4500 -5900 -5719 -4295 -3679 -3221 -4304 -3422 -3248 -4798 -4402 -3927 -5490 -3388 -3791 -4279 -5150 -6240 -4925 -4697 -5584 -6288 -4373 -3731 -4046 -5429 -3658 -4517 -4983 -4132 -2690 -4214 -4616 -4112 -3362 -4171 -4067 -5261 -4684 -3123 -3259 -5261 -4857 -4543 -3958 -5142 -5235 -4520 -4380 -5372 -5980 -4870 -4518 -3596 -5010 -3795 -4264 -3752 -5176 -4935 -5352 -3636 -3179 -4224 -4467 -4143 -3476 -3723 -3860 -4529 -4945 -4350 -5389 -2795 -3839 -5717 -4014 -5592 -5477 -5677 -4516 -3960 -4026 -5271 -4727 -3561 -5664 -5835 -4357 -3621 -3627 -5466 -4006 -5162 -4333 -3485 -4023 -4182 -4219 -4476 -4559 -5694 -4623 -5887 -4062 -3231 -4393 -3792 -4517 -4703 -4149 -5429 -4390 -3890 -5170 -5750 -5449 -4485 -3390 -3098 -3453 -4547 -4879 -4266 -4351 -4658 -4102 -4105 -4833 -3425 -4409 -5865 -3005 -5043 -4219 -4409 -3488 -4221 -5571 -4931 -4107 -3837 -4786 -3785 -4749 -4434 -4318 -3787 -2728 -3846 -5678 -4523 -4885 -4913 -3155 -3150 -4984 -3032 -4002 -4411 -3685 -4405 -4443 -4465 -5258 -4785 -3061 -4036 -3430 -4850 -5723 -4038 -3134 -6468 -4138 -4645 -4681 -4213 -3856 -4517 -4465 -4108 -4866 -4066 -4774 -4728 -5009 -4492 -3656 -3511 -3172 -3307 -4353 -4727 -5353 -4237 -5102 -6494 -6097 -5389 -4227 -4408 -6455 -4074 -5154 -5321 -5182 -3693 -4244 -3281 -4626 -4495 -2776 -5524 -3439 -2972 -4926 -4633 -3189 -4857 -4231 -4318 -4013 -4230 -3413 -4635 -4023 -4479 -5130 -4905 -4241 -3383 -3861 -4261 -5305 -4842 -4201 -6213 -4360 -4563 -5009 -5487 -6254 -5019 -3665 -2570 -4000 -4589 -4415 -5887 -4072 -4644 -3822 -5473 -4186 -3385 -4382 -3602 -5441 -4887 -5430 -5237 -5088 -3739 -4779 -4390 -4548 -4997 -3688 -4044 -5254 -4599 -5461 -5124 -4072 -2936 -4141 -3867 -3685 -3615 -4425 -3482 -4269 -4663 -5086 -4236 -4586 -3552 -4307 -4055 -5095 -5255 -5135 -3898 -4729 -4848 -4541 -2745 -3788 -4908 -5564 -3942 -5615 -5469 -5298 -4553 -5010 -3608 -4883 -4067 -3727 -3915 -4371 -4079 -2951 -5294 -4727 -5212 -4970 -4703 -5246 -4009 -4033 -5362 -4950 -3672 -5531 -4441 -3890 -3301 -3707 -5773 -3536 -3298 -5232 -4252 -4856 -5141 -5358 -5360 -5046 -4093 -4828 -4611 -6052 -4893 -3687 -4322 -3940 -5092 -4040 -5118 -4664 -4375 -3858 -4209 -5377 -5431 -2960 -3800 -4518 -4015 -3724 -4955 -4754 -3566 -4479 -5028 -4729 -4921 -4517 -3687 -4556 -4060 -3847 -5278 -5026 -4714 -3484 -5235 -5754 -3517 -4470 -4805 -4911 -3902 -5547 -4075 -4159 -3106 -3793 -4948 -4526 -4760 -5048 -4191 -5618 -5838 -4681 -3933 -4269 -3647 -4308 -4387 -4833 -4025 -4483 -5006 -5072 -3846 -4216 -5304 -5205 -4749 -2890 -5004 -4382 -6488 -3522 -4741 -4510 -3801 -5066 -4939 -3667 -3037 -5356 -5220 -3270 -6056 -4539 -4165 -4583 -4216 -5542 -4456 -4088 -4670 -5522 -4236 -3750 -3283 -4136 -4603 -3406 -4789 -3912 -3736 -2763 -3678 -3853 -5209 -5300 -4166 -3721 -4944 -4615 -4372 -4085 -4326 -5085 -4678 -5056 -3518 -3484 -4179 -5356 -4566 -4695 -3932 -3835 -5589 -3575 -4906 -3344 -5268 -4287 -4614 -3721 -3800 -4676 -4533 -6932 -5527 -4051 -4578 -5022 -6099 -5397 -5748 -4488 -4553 -3571 -4417 -3215 -4135 -3516 -3975 -3952 -2838 -5471 -4529 -6930 -4271 -4001 -4941 -3894 -3619 -4375 -5162 -4531 -6001 -4141 -3718 -3438 -4127 -4409 -4277 -4594 -5349 -4729 -3857 -4257 -5850 -5111 -4660 -3473 -4406 -4389 -5248 -4431 -4932 -3994 -3732 -4057 -4988 -5201 -4073 -4886 -4029 -6175 -3147 -5358 -5233 -4927 -4431 -5798 -5559 -4840 -4141 -3455 -4841 -3676 -4581 -6374 -5166 -4533 -5641 -4250 -4217 -5835 -5037 -3465 -4044 -4136 -4558 -3438 -5796 -4691 -3643 -4345 -4780 -4446 -3723 -5830 -4958 -4854 -3974 -3734 -4088 -5498 -3131 -4983 -5815 -3254 -3750 -5690 -4818 -2109 -4055 -6041 -4328 -4165 -5269 -4451 -5132 -4142 -6223 -2996 -4424 -4485 -5464 -3850 -3774 -5315 -4545 -6190 -6590 -5876 -4270 -4455 -4267 -3298 -3547 -4488 -5118 -4740 -4364 -4331 -5859 -4658 -3397 -4151 -4118 -4532 -4221 -4209 -4641 -5004 -4154 -3916 -4585 -5240 -5074 -4250 -4386 -5558 -5222 -3100 -4847 -3779 -5231 -5561 -4696 -4412 -5986 -5503 -4222 -5086 -4482 -5335 -3656 -5346 -4109 -5480 -5899 -6049 -4155 -3323 -3505 -5062 -5994 -3113 -5276 -3953 -3331 -3703 -5353 -2721 -4991 -4194 -4504 -4203 -4283 -3643 -5204 -3104 -3640 -4476 -5092 -3187 -4150 -4805 -4329 -4470 -4821 -6199 -5941 -4391 -5209 -4438 -4516 -5829 -3979 -4844 -4503 -4767 -4536 -4435 -4605 -4282 -4807 -4833 -3993 -3740 -5548 -5059 -5256 -3412 -5216 -5066 -4185 -4377 -5532 -5469 -6466 -3032 -6476 -3312 -3615 -4247 -5722 -5628 -4929 -5532 -5876 -3139 -6246 -4694 -5140 -4572 -4253 -4573 -4508 -4507 -4196 -5269 -4500 -5321 -4578 -5951 -5038 -4756 -5629 -2966 -3922 -5698 -5134 -4698 -2902 -4500 -5011 -3861 -2910 -3885 -5433 -3959 -4158 -3757 -3622 -4640 -3191 -6167 -3302 -4778 -4632 -3535 -4136 -3525 -3415 -5849 -3573 -4443 -3803 -4476 -4230 -3903 -3337 -4587 -3939 -3753 -4194 -4044 -4625 -4873 -4518 -4252 -4077 -7347 -3537 -4117 -3207 -4958 -5677 -5060 -4628 -4074 -3974 -4517 -4341 -4660 -2881 -4797 -4958 -6446 -4122 -4075 -5601 -6508 -4663 -4735 -4730 -3755 -3909 -5321 -4012 -3946 -5032 -3668 -3159 -3443 -4710 -4159 -3064 -5939 -3975 -3798 -5310 -3008 -4007 -4651 -4226 -4553 -4977 -5733 -4046 -4548 -2651 -5063 -3791 -4985 -4598 -4283 -4882 -4765 -4580 -2685 -4762 -3026 -4409 -5171 -3647 -5344 -4569 -5620 -4998 -4730 -4024 -4034 -4682 -4692 -4141 -4570 -3869 -3387 -5174 -5531 -4072 -5716 -4095 -5078 -3564 -5536 -3623 -4421 -6315 -4681 -4993 -3903 -3485 -4049 -4481 -4194 -3849 -3816 -4751 -4840 -5106 -5550 -5457 -4584 -4651 -4758 -5078 -4381 -5025 -4228 -5499 -5258 -4848 -5054 -5620 -4015 -5163 -3505 -3429 -4297 -4449 -5535 -5293 -4397 -3135 -4646 -3962 -4717 -4741 -4633 -2812 -3935 -4976 -3222 -4377 -3448 -3495 -5553 -4523 -4293 -3911 -3673 -4502 -4207 -5217 -4665 -5219 -5170 -3760 -3756 -4111 -3917 -4337 -3793 -4914 -3902 -3442 -4721 -3824 -3368 -4835 -4041 -3932 -6394 -5456 -4134 -6460 -5875 -4643 -4168 -4898 -6098 -3332 -4444 -3855 -3925 -5038 -4531 -7430 -4320 -3815 -4526 -5478 -4697 -4762 -4471 -6193 -5003 -3775 -4232 -3974 -4556 -4510 -4189 -4890 -7215 -4959 -5789 -6001 -3994 -4523 -5206 -5734 -4473 -4296 -5420 -4593 -5303 -5141 -4782 -4774 -5955 -3583 -4301 -4604 -3819 -4962 -4183 -4474 -2856 -5304 -5648 -3089 -4416 -5208 -4470 -4224 -4390 -4583 -4209 -3977 -3324 -5901 -4585 -4471 -2981 -5259 -5911 -4353 -4246 -4590 -4738 -3497 -3909 -4209 -5382 -5600 -4255 -4320 -4467 -4954 -5843 -4144 -5347 -4229 -4170 -3702 -4763 -5319 -4330 -4832 -4737 -4852 -4523 -3895 -5714 -4377 -3927 -4670 -4194 -3522 -4362 -5238 -4193 -6807 -5247 -4495 -3957 -3979 -5212 -4535 -4324 -4261 -3746 -6117 -4958 -3604 -4525 -6361 -4741 -4308 -4476 -5474 -4940 -3621 -4472 -4633 -5237 -5160 -4131 -3268 -4315 -4893 -3592 -2890 -4562 -3070 -4876 -5259 -5826 -4502 -5394 -5003 -4009 -4050 -5427 -4445 -6085 -3956 -4913 -3141 -5176 -4275 -5577 -4688 -3897 -4708 -5321 -4754 -4383 -6223 -3974 -4157 -5273 -4705 -6200 -4300 -4842 -4369 -3708 -5902 -3915 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/random.txt deleted file mode 100644 index 36d7eace6..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -17597 -22851 -21615 -21119 -23377 -21986 -22315 -15680 -18007 -25789 -24736 -18101 -20502 -18914 -19225 -22778 -19692 -21823 -26402 -31166 -22495 -24554 -18942 -17227 -27044 -21677 -16985 -22471 -24711 -23702 -17913 -21430 -21048 -22651 -23551 -17373 -18536 -27410 -26189 -16616 -23235 -20995 -26239 -26202 -28367 -22096 -23638 -20049 -14822 -27214 -18462 -15091 -18904 -25683 -21162 -19225 -22783 -25663 -18211 -24142 -21549 -25973 -21326 -22916 -18326 -16879 -23924 -22151 -23987 -19613 -19422 -21623 -20474 -17546 -23309 -23221 -22766 -29763 -17879 -23011 -21706 -25970 -12448 -21804 -18656 -23319 -18209 -21944 -21761 -15158 -17405 -23610 -20450 -17900 -17292 -32762 -18559 -23937 -28906 -22031 -30675 -20215 -24958 -25343 -22530 -29835 -14508 -27248 -29361 -16235 -22678 -17372 -27180 -27710 -23547 -22785 -21031 -15940 -22210 -17373 -18028 -19677 -30289 -26309 -22182 -22506 -22697 -19703 -22822 -24107 -20998 -24688 -19573 -14291 -20688 -15840 -21145 -19987 -25450 -19465 -22947 -25221 -12695 -16297 -18937 -21304 -27387 -20082 -20216 -23436 -25062 -18117 -19513 -23974 -21271 -20697 -20713 -24665 -21816 -17894 -17734 -22906 -24008 -16086 -19714 -23989 -27096 -24347 -22163 -18940 -23059 -18341 -16138 -26127 -19658 -21133 -22734 -18048 -20128 -17767 -20757 -17823 -11190 -23585 -20706 -28225 -16994 -23465 -23942 -22346 -25391 -25359 -25880 -21232 -23338 -19599 -15837 -18502 -19543 -21645 -17690 -22625 -21048 -26404 -19646 -16996 -23772 -16555 -19766 -27772 -17191 -13596 -22502 -23031 -14944 -23752 -25319 -17997 -21566 -21541 -19369 -22990 -18386 -18125 -25737 -23747 -19548 -16984 -28541 -23467 -19819 -13261 -25188 -14184 -11833 -18508 -27860 -20426 -15531 -23013 -18502 -20525 -21771 -18374 -17478 -27731 -18632 -17090 -23353 -23126 -15789 -12193 -22804 -24781 -22042 -28096 -16885 -26191 -21131 -13163 -16506 -18518 -33962 -20343 -24958 -15511 -18767 -16796 -21411 -24249 -27088 -22275 -26727 -18742 -19174 -21662 -23629 -20044 -24172 -19360 -17341 -19106 -29539 -18916 -22198 -16252 -18265 -24562 -19605 -17828 -20038 -20741 -17551 -19694 -17292 -17992 -22057 -20017 -22130 -22101 -24563 -26505 -28026 -24048 -23310 -31643 -17918 -28867 -25863 -16368 -23894 -20742 -20490 -24895 -20819 -27658 -25247 -21280 -28518 -21527 -20560 -16624 -23023 -20226 -18850 -18539 -10823 -23624 -16750 -18203 -21845 -29143 -21659 -21697 -27743 -16433 -18626 -23260 -23363 -23718 -23031 -22249 -21398 -24587 -22406 -23814 -15286 -23474 -23544 -29694 -16979 -29055 -26894 -16695 -13648 -13779 -16903 -23868 -28500 -18624 -20412 -18781 -21602 -26837 -24838 -29609 -14853 -21692 -21275 -24326 -17628 -18291 -26729 -25561 -32707 -31695 -21467 -24212 -23049 -25853 -17425 -17216 -18366 -18020 -16398 -24829 -19923 -22103 -22374 -18458 -16764 -17983 -25620 -25065 -19234 -16148 -15863 -14421 -20634 -17057 -22858 -18101 -21916 -17952 -21738 -25981 -23862 -24556 -27735 -17009 -18416 -22043 -13107 -20588 -14315 -25907 -20730 -19255 -29823 -17566 -27138 -25335 -27879 -20315 -22923 -28894 -26672 -19444 -24267 -22010 -10430 -19153 -21361 -22243 -32157 -28105 -24013 -28471 -25987 -12201 -19128 -25709 -22653 -17666 -14741 -20942 -21874 -34388 -25648 -24274 -25280 -16787 -21514 -16982 -21920 -22147 -23883 -16886 -21177 -23019 -19227 -22525 -22440 -24324 -22005 -27574 -14085 -20319 -25163 -23111 -20091 -17976 -24553 -23658 -24352 -17794 -19683 -22718 -22303 -21120 -21927 -19075 -16452 -26309 -25070 -22795 -23653 -21747 -24836 -21274 -25033 -22730 -23817 -18249 -20026 -18265 -22908 -23948 -26856 -20616 -19894 -27158 -19623 -18398 -21115 -24372 -17817 -15084 -21018 -23075 -28839 -20490 -31140 -24286 -26668 -22752 -15944 -25712 -23917 -16950 -15465 -23790 -24664 -22087 -24052 -32872 -30225 -20987 -28572 -25586 -17687 -23733 -17951 -17083 -24539 -22549 -23561 -21960 -25740 -20573 -30817 -26322 -17067 -16458 -19258 -23844 -22269 -16332 -21771 -18091 -25037 -25769 -14609 -23920 -19468 -26994 -20449 -14395 -26223 -22230 -21001 -23922 -23785 -28374 -25497 -21503 -17522 -20093 -21599 -16657 -20143 -18233 -20862 -24021 -23794 -25298 -23562 -17300 -19878 -14864 -17847 -19571 -15317 -16614 -22973 -19340 -25400 -19204 -20828 -23451 -24796 -23660 -19537 -18641 -17938 -18601 -24312 -16613 -17417 -18218 -29681 -20466 -20592 -22665 -19874 -18533 -20214 -26562 -19121 -17639 -23312 -22931 -27736 -26715 -27773 -22991 -17375 -16269 -20329 -22896 -18930 -19556 -16513 -18652 -17381 -22893 -21935 -17484 -18137 -21301 -22477 -19868 -21880 -21833 -22792 -22234 -18978 -22796 -20240 -25652 -18095 -16352 -19203 -38760 -28216 -22688 -13304 -20476 -22556 -16639 -21804 -26548 -22205 -23976 -29493 -21610 -24055 -24055 -22366 -19892 -16731 -25110 -16757 -15757 -16982 -24722 -15453 -22097 -17542 -18927 -18167 -24716 -19403 -17507 -19436 -22340 -22520 -29995 -20727 -18047 -20206 -20033 -16422 -17332 -23502 -24085 -18183 -25309 -23650 -21601 -23021 -16531 -27065 -22958 -19706 -27917 -17614 -18483 -19885 -19261 -24356 -19844 -22328 -17872 -21950 -19017 -20954 -14899 -23359 -14968 -23135 -24351 -18095 -25688 -18151 -21972 -24798 -23647 -16255 -22802 -23475 -20896 -20752 -18951 -27348 -15380 -24074 -20123 -18674 -16656 -18421 -19889 -24253 -20459 -21517 -19620 -22987 -28104 -20255 -23180 -23876 -22639 -21298 -23500 -15828 -18000 -18034 -21889 -25012 -22646 -17492 -22313 -16884 -22641 -31484 -15256 -15228 -20793 -19981 -21286 -21075 -18563 -26032 -16033 -20603 -19320 -16134 -22187 -26216 -17267 -15225 -22775 -22991 -17897 -20820 -23322 -28093 -19570 -22315 -18678 -19601 -23597 -20414 -29145 -27579 -23489 -21798 -18892 -26071 -27844 -20421 -19037 -22236 -30170 -22118 -21151 -21400 -20691 -23904 -20544 -14996 -16881 -22219 -27920 -19131 -24389 -24315 -29197 -17569 -25546 -18699 -27173 -21220 -26637 -18251 -21733 -27154 -24771 -23011 -23458 -19963 -20371 -15098 -21478 -20014 -20925 -16632 -22944 -28256 -17742 -23632 -21567 -24865 -22695 -24702 -26011 -20916 -23009 -29152 -25628 -21258 -21511 -24678 -27599 -16655 -30136 -29430 -15628 -22404 -19619 -19707 -20685 -24834 -20908 -18804 -21468 -24454 -20243 -23304 -19550 -24601 -23417 -21706 -22269 -19302 -23680 -19566 -21650 -22166 -21001 -24432 -19093 -19397 -17527 -15865 -21766 -24064 -24152 -19668 -17283 -28404 -16255 -25086 -21709 -22746 -20448 -24653 -22919 -30568 -23300 -17779 -17462 -24107 -18494 -30529 -19770 -22678 -18090 -20489 -16605 -24611 -21482 -21843 -21009 -19987 -22488 -23686 -22960 -22941 -22377 -28460 -24219 -15835 -17926 -22041 -21130 -18676 -24646 -19939 -15399 -30208 -21451 -22403 -30577 -24060 -26488 -18027 -17061 -24027 -21871 -20126 -19696 -20568 -21538 -18845 -22561 -21893 -30251 -26364 -26776 -21873 -28447 -17699 -25563 -16126 -19676 -18515 -23521 -20329 -18101 -23346 -18785 -20522 -19560 -23156 -21718 -16217 -16994 -21908 -25793 -19830 -29921 -16633 -21324 -27950 -19155 -15478 -22128 -15754 -12494 -16981 -26441 -26120 -20200 -18816 -18928 -22887 -23478 -26604 -17877 -18988 -20879 -21163 -19045 -18751 -30171 -21539 -15535 -20989 -23478 -22064 -17813 -21243 -16394 -19392 -26703 -17790 -27776 -19637 -23992 -19820 -16440 -20102 -26763 -27774 -15771 -16419 -20893 -17393 -14807 -27348 -22669 -15462 -22290 -22518 -19759 -19463 -16856 -24732 -24011 -25897 -24554 -21568 -17146 -22519 -24767 -26774 -23903 -19589 -21735 -20528 -17517 -25495 -22297 -28456 -14864 -20587 -19053 -22591 -16314 -22744 -19264 -21327 -28417 -14639 -21980 -15304 -21436 -26262 -18417 -15265 -18880 -23177 -24242 -32089 -17225 -18083 -22151 -19438 -22098 -24745 -27504 -25166 -22111 -27494 -23418 -22292 -23739 -17574 -27482 -19087 -20492 -22373 -20694 -20331 -27380 -19183 -19773 -22560 -20626 -21326 -25185 -25652 -20728 -20573 -21189 -23428 -25319 -20320 -15684 -19219 -21292 -25397 -21264 -22280 -15339 -22687 -20991 -19408 -18938 -14628 -17845 -20050 -23175 -17475 -24098 -24742 -18639 -18683 -18983 -21899 -23378 -33794 -23771 -19080 -21474 -15963 -19758 -22117 -28152 -18964 -21515 -17857 -25649 -17566 -23686 -20304 -22700 -18229 -27614 -16550 -20327 -20466 -20979 -21826 -20968 -22361 -21531 -17676 -18588 -22133 -24322 -20650 -31101 -24884 -17008 -21130 -24829 -16412 -17417 -19476 -22085 -19677 -23393 -22940 -21256 -21692 -16994 -22237 -30426 -22517 -25143 -18970 -24160 -25189 -22788 -17224 -26499 -18781 -18299 -11746 -22751 -19047 -19683 -27650 -18569 -23963 -24554 -13976 -25295 -26580 -17334 -26292 -25364 -26344 -21502 -20759 -17705 -21784 -22441 -17569 -28511 -16085 -24840 -18827 -20971 -24578 -24803 -18670 -11118 -13308 -13128 -24431 -26535 -21606 -24666 -17885 -28380 -23176 -17762 -23181 -23291 -23974 -20676 -19660 -27227 -14215 -21148 -17850 -27414 -21865 -22368 -20429 -25250 -23992 -26745 -23328 -15913 -19790 -19599 -17913 -24470 -18042 -22449 -17699 -20461 -18231 -17450 -28516 -26928 -18155 -17418 -22188 -18602 -23586 -13176 -23873 -17099 -18405 -19506 -19766 -21795 -21495 -14253 -20516 -26896 -18717 -13613 -23209 -21186 -25580 -25053 -24667 -22988 -26847 -19256 -13170 -27570 -21329 -18525 -12826 -21174 -27962 -19396 -18036 -23599 -20818 -25717 -16604 -20311 -19290 -22002 -24939 -18906 -18423 -15909 -20757 -20760 -25483 -22108 -33068 -18804 -21704 -28464 -23935 -21683 -25778 -13890 -21348 -24974 -14567 -15344 -26769 -21004 -22376 -28910 -27261 -22423 -13472 -24882 -17583 -23754 -12011 -22107 -19431 -33506 -19759 -18114 -18072 -21172 -19684 -26715 -22381 -20241 -23366 -22766 -20421 -24346 -22872 -18424 -17123 -16399 -16664 -23279 -15670 -13853 -26550 -15146 -17164 -16244 -27403 -22672 -25034 -17986 -24841 -28293 -22653 -25613 -21443 -25171 -20261 -28420 -23536 -26196 -22456 -16821 -23356 -16792 -21881 -25332 -24957 -21289 -18121 -26871 -24635 -22708 -31020 -19398 -18595 -23756 -21444 -19580 -28077 -22859 -21305 -17939 -25168 -24357 -18378 -16416 -23981 -19306 -23060 -19455 -21205 -22976 -24123 -20582 -16647 -20808 -26881 -25468 -27501 -17994 -22748 -29720 -31090 -25212 -25078 -24401 -18127 -21582 -20688 -31148 -16380 -15917 -15092 -18395 -19697 -24145 -22676 -19067 -19191 -27932 -24640 -14598 -21759 -20589 -21717 -18774 -26522 -24735 -22145 -25863 -24347 -16705 -19648 -22066 -18765 -22135 -22583 -19370 -26614 -22412 -23328 -19877 -25795 -26376 -20364 -20087 -22297 -26482 -18808 -21732 -25409 -21869 -16925 -22478 -18384 -17850 -25475 -19025 -26989 -24750 -22804 -24289 -22410 -23152 -15838 -30106 -19066 -25235 -22317 -22926 -23092 -24078 -22501 -18373 -18997 -20632 -20424 -20949 -13686 -14832 -26050 -17706 -21215 -17931 -17968 -20627 -24866 -19026 -27228 -16915 -17348 -17713 -15491 -21229 -17825 -27393 -15232 -17123 -27649 -21833 -19300 -21123 -18015 -17587 -19053 -24512 -24248 -18463 -24394 -23340 -15847 -27171 -19288 -26723 -20660 -25325 -22023 -29757 -17682 -26974 -24243 -18953 -25872 -22366 -19221 -22850 -15516 -16527 -26070 -16743 -18836 -17889 -20558 -15072 -30909 -24026 -17752 -25574 -19284 -26140 -14343 -21458 -22870 -26563 -28446 -21507 -29557 -22802 -24076 -20096 -17793 -24005 -18702 -22123 -24668 -14800 -22267 -19091 -18683 -20516 -25375 -24424 -22066 -14185 -14263 -21804 -28885 -20534 -20226 -27496 -24810 -20036 -23344 -19757 -25086 -22336 -20616 -19328 -25018 -18909 -24635 -19582 -23565 -22672 -19341 -18395 -17442 -22156 -14110 -17531 -25633 -28769 -19415 -20665 -15264 -15841 -11055 -19989 -21757 -17616 -20054 -18808 -21370 -23025 -22544 -21991 -21508 -20531 -25195 -25308 -23902 -15807 -24712 -22432 -21585 -20581 -22765 -23404 -24349 -14728 -17855 -18568 -21162 -26616 -14660 -26787 -16412 -23879 -26766 -20394 -21420 -19977 -14809 -21984 -22326 -22556 -15243 -16470 -27837 -19310 -14619 -18694 -17784 -19115 -22050 -20093 -22887 -22157 -23389 -17104 -17318 -19493 -28207 -16111 -23282 -25653 -28868 -23847 -20139 -23738 -17511 -24576 -21411 -19604 -18785 -24513 -18161 -22741 -18007 -23749 -26549 -17456 -27312 -23024 -18686 -22663 -17131 -20375 -23947 -22282 -29354 -30631 -18241 -21795 -17922 -21914 -19452 -11183 -27451 -22744 -18984 -19492 -17559 -29826 -19986 -27695 -23408 -24284 -21319 -21990 -21397 -17691 -22376 -17500 -20821 -26583 -25119 -24230 -14606 -22344 -25977 -20319 -22777 -19611 -20674 -18760 -22487 -15219 -25218 -19595 -20534 -23176 -24134 -28966 -24810 -19363 -24687 -23003 -25637 -28498 -19836 -18557 -25936 -21016 -15222 -20076 -21685 -23854 -18146 -23218 -26543 -17825 -13013 -18827 -20894 -17784 -22794 -21286 -26249 -17832 -29305 -21778 -19200 -26962 -23580 -21965 -23869 -18163 -24322 -29293 -24775 -15210 -14787 -29275 -20791 -20240 -24722 -22564 -19594 -23671 -23022 -22701 -24505 -23664 -24703 -20310 -20949 -20970 -20572 -16614 -16947 -22739 -23324 -19458 -22896 -23294 -16064 -25522 -24895 -25033 -24043 -19837 -21598 -25111 -20467 -23047 -24168 -20889 -23478 -18667 -25123 -19591 -19949 -23207 -24850 -18019 -19857 -18257 -18625 -17935 -18943 -23299 -28533 -17263 -27324 -21447 -18793 -26827 -24233 -28858 -23365 -17556 -12250 -25066 -18303 -20745 -17117 -21612 -24500 -21479 -24639 -23940 -19838 -23999 -17631 -16490 -16239 -21290 -19688 -21939 -23201 -17436 -21814 -20432 -18982 -24924 -22917 -19740 -26802 -24735 -20293 -25636 -19645 -18176 -18736 -21212 -17910 -21356 -27689 -20379 -16311 -19012 -20178 -19248 -18822 -33563 -24392 -27152 -31887 -18916 -19213 -24629 -27831 -19416 -22115 -12441 -24761 -16656 -24849 -26793 -28242 -13132 -23587 -20113 -15362 -19380 -25220 -20552 -27862 -21989 -21691 -26152 -18285 -20933 -20425 -25358 -23996 -27704 -20369 -19465 -26100 -21227 -15909 -20402 -22065 -23334 -22836 -20709 -19833 -23084 -16493 -20955 -27492 -17844 -22666 -23519 -13950 -22252 -23732 -26517 -21483 -22871 -23005 -27224 -15597 -20341 -24959 -26568 -22964 -18502 -17123 -19211 -22688 -16496 -15757 -21715 -16911 -14957 -24756 -16027 -25789 -21720 -17948 -20396 -20197 -22320 -28949 -24714 -14360 -20545 -16614 -15960 -23606 -21903 -17833 -21784 -13901 -22957 -24104 -34225 -21224 -22137 -25250 -23633 -16126 -16903 -20127 -16673 -28701 -24936 -19894 -22431 -26939 -20799 -26059 -18658 -21933 -17926 -22268 -21277 -21924 -23845 -18458 -24072 -16316 -30367 -22597 -17517 -16441 -21417 -26770 -30018 -29609 -22548 -23327 -18390 -20995 -21671 -14005 -16189 -26524 -15453 -22853 -18819 -20518 -19699 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k5/trained_ddqn/best.pt deleted file mode 100644 index d7e55ced494c03ddca50acff243782874784d509..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 z 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 QrG9;u>HquH|Ifbv2f@Vd3;+NC diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/dqn.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/dqn.txt deleted file mode 100644 index 24d7358d8..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4512 -3676 -4571 -4489 -5346 -4393 -6264 -5248 -3620 -5139 -3596 -2938 -4082 -6234 -4756 -4306 -4805 -3842 -5007 -3584 -6447 -4072 -4965 -5146 -3820 -5005 -5737 -4812 -4137 -4914 -4399 -4513 -4494 -5415 -5783 -6421 -5808 -4010 -5755 -5857 -4510 -5418 -4493 -6235 -6204 -5921 -5597 -4767 -4870 -4851 -7018 -4812 -4303 -4632 -5710 -3995 -5118 -3267 -6083 -6254 -5693 -4868 -3984 -5035 -3213 -5876 -6304 -4355 -4449 -6761 -4798 -5802 -3305 -4072 -5619 -5672 -4329 -4006 -4310 -5367 -4922 -6066 -5011 -3998 -4405 -5611 -4553 -3566 -6785 -4129 -4003 -5229 -4818 -4697 -5228 -4986 -3950 -5618 -4710 -3577 -4637 -5412 -4299 -4723 -6035 -5742 -5290 -3682 -6923 -6460 -5639 -4926 -3694 -5170 -5501 -4695 -5053 -3882 -6546 -6123 -4348 -3995 -4544 -5661 -4864 -5256 -5246 -5409 -4937 -4190 -3812 -5460 -5529 -6029 -4603 -2969 -3745 -6242 -4418 -4680 -4734 -4443 -5337 -4447 -3587 -4895 -4387 -6592 -3927 -5983 -4127 -4432 -3410 -3750 -3790 -4478 -4035 -4992 -4975 -3659 -4746 -4455 -6530 -4259 -5912 -5349 -3263 -4512 -5128 -4485 -5917 -5006 -4906 -4531 -5031 -3429 -4811 -4195 -4896 -3499 -3999 -4571 -4271 -3506 -5988 -4143 -6870 -4185 -6370 -3777 -5398 -4998 -4179 -4018 -5263 -4858 -5083 -3126 -4381 -3649 -3759 -3742 -3708 -4987 -6562 -5848 -3357 -5173 -5689 -5957 -4569 -3460 -4464 -5499 -5788 -4313 -4179 -3386 -5528 -4882 -4608 -5000 -4435 -5922 -6603 -3959 -4212 -4859 -4408 -4096 -4141 -4607 -4500 -4624 -4996 -6342 -4144 -4054 -6872 -5422 -4413 -4294 -4691 -3980 -5180 -6985 -6282 -5255 -5223 -4223 -3843 -4283 -3902 -3106 -4920 -4404 -4037 -4324 -3660 -4328 -3993 -5550 -3995 -6313 -5393 -4975 -4217 -5411 -4000 -5170 -3773 -3076 -4776 -4927 -5686 -5764 -4953 -6551 -4562 -5681 -7055 -5119 -4891 -4955 -5472 -4339 -4449 -4487 -3045 -5245 -4606 -5040 -3879 -5370 -5800 -5555 -4195 -4750 -4375 -5041 -5384 -5409 -4717 -4487 -3981 -4638 -5131 -3178 -4509 -3203 -5140 -5045 -6120 -4233 -7535 -6207 -6102 -6012 -3628 -5352 -4171 -6787 -4763 -4823 -5206 -5102 -5972 -5326 -5197 -3623 -4229 -6262 -4512 -5185 -6049 -3700 -4249 -5110 -3407 -4902 -3104 -4213 -6017 -6402 -3688 -6129 -3855 -6501 -4864 -4730 -4625 -4619 -5683 -5515 -4815 -4642 -6103 -3740 -6497 -5066 -5630 -3902 -3956 -5277 -5808 -5425 -5629 -5503 -5071 -3746 -5009 -5556 -5392 -5537 -5475 -4606 -5606 -4663 -4324 -4380 -3746 -4848 -5481 -5398 -6990 -3705 -6402 -3997 -4879 -3852 -4256 -4517 -4861 -3183 -4949 -4823 -4752 -4812 -5256 -6779 -5219 -5234 -4030 -3949 -4636 -4837 -5158 -5793 -5798 -6004 -5053 -4863 -5079 -4792 -4410 -5185 -4903 -3531 -6473 -5388 -4950 -4596 -5026 -5913 -2815 -4506 -3377 -3986 -3453 -5187 -3533 -5175 -3760 -4768 -4375 -3948 -4315 -5230 -4267 -8010 -5601 -5706 -4695 -5487 -3919 -3659 -4445 -4122 -5951 -3002 -5177 -4604 -5266 -4780 -5079 -4995 -3913 -4052 -4682 -3761 -4263 -6043 -3019 -4280 -4229 -5471 -6360 -4098 -3623 -5728 -4011 -4073 -4609 -3813 -3635 -4008 -4132 -6631 -6549 -5140 -5872 -3918 -4713 -6658 -5516 -4949 -6694 -5153 -6640 -3624 -5552 -4473 -4883 -3908 -4727 -4060 -3333 -4411 -4828 -5166 -4757 -4433 -4520 -3666 -5181 -5252 -3966 -5664 -4473 -4410 -4353 -5007 -4998 -4609 -4780 -4359 -5302 -5210 -5449 -5303 -4629 -4340 -4295 -3874 -4701 -4082 -6004 -7340 -3890 -5172 -4772 -5386 -4650 -4710 -4515 -3684 -5725 -5090 -6968 -3852 -5191 -6153 -4320 -4223 -4496 -4481 -4229 -3254 -3299 -5717 -3924 -3076 -5420 -3458 -5234 -5589 -5261 -3964 -4523 -4427 -5803 -5393 -4481 -5860 -4982 -3881 -5004 -3844 -4400 -5493 -6057 -3934 -5136 -4801 -5560 -3720 -5089 -4531 -4838 -5306 -6176 -5390 -2926 -3385 -4511 -3947 -4496 -5186 -5902 -4116 -3418 -3189 -4118 -3998 -4210 -5173 -3668 -4698 -3335 -5133 -3725 -4679 -5069 -4471 -4463 -5248 -3119 -3936 -4307 -3657 -5339 -5527 -4866 -4598 -5139 -2926 -4827 -4485 -4907 -5469 -3976 -4745 -5306 -6410 -4127 -3535 -4273 -5914 -6919 -4063 -4967 -5710 -5384 -4350 -3834 -6890 -3593 -5530 -3846 -2642 -4962 -5116 -4589 -6153 -5202 -4525 -4451 -6168 -5694 -5436 -4922 -4387 -4943 -4174 -3298 -4488 -5357 -4930 -5619 -3623 -5000 -6127 -5539 -4318 -4350 -4665 -4994 -6393 -5419 -4897 -5644 -4515 -4710 -4077 -4714 -3822 -3857 -6024 -5718 -5147 -4685 -4731 -4973 -4876 -6484 -3982 -6238 -5081 -5933 -4325 -4765 -6666 -4656 -3916 -5273 -4357 -6122 -4002 -5206 -4089 -4646 -5010 -5319 -7497 -7234 -4738 -4907 -6293 -6560 -7295 -5405 -5485 -5200 -5465 -6371 -4206 -5898 -4534 -4323 -5846 -4745 -3584 -4303 -4475 -5634 -4879 -4507 -3979 -5677 -3882 -5144 -4038 -3163 -3670 -5250 -3794 -4486 -5099 -4323 -4557 -4069 -4168 -5512 -5303 -4659 -6176 -4322 -4510 -3714 -7697 -3575 -4747 -4054 -4731 -4972 -4116 -3693 -4960 -4927 -4251 -5713 -3982 -4940 -3670 -5084 -3951 -4031 -6590 -4752 -4644 -5754 -6601 -5165 -4935 -4577 -4957 -4666 -4508 -5856 -5346 -5063 -5657 -4897 -4190 -4332 -4879 -6090 -4566 -5217 -4654 -4143 -3595 -4705 -4908 -6856 -4944 -4559 -3536 -4512 -4728 -5421 -3333 -3608 -4370 -3760 -4670 -4869 -4023 -5087 -5228 -4882 -4044 -4021 -5363 -3383 -3957 -5380 -4119 -6960 -5837 -5045 -4127 -5839 -5655 -4563 -4651 -6060 -5586 -6082 -4662 -4326 -5370 -4426 -4535 -5503 -4704 -6291 -5868 -4677 -4063 -5174 -4096 -5127 -7042 -3901 -4777 -5745 -4593 -5377 -4539 -5494 -4262 -4946 -4537 -5773 -5000 -4488 -5508 -5619 -4820 -5362 -4650 -3325 -6169 -5426 -4436 -5395 -4545 -5037 -5735 -4106 -4438 -4594 -4309 -5525 -4051 -4596 -5977 -4972 -5094 -4114 -4496 -4332 -4002 -4312 -4885 -4736 -5966 -4633 -3250 -5259 -5153 -5422 -6230 -3345 -5574 -4114 -4759 -5443 -4236 -2926 -4309 -5631 -5600 -5430 -4890 -5709 -4877 -6523 -6353 -3864 -5299 -3816 -3868 -6031 -3540 -3797 -4653 -4225 -3732 -3060 -4961 -3859 -4793 -5352 -5876 -4420 -4957 -4622 -4435 -4891 -4843 -5051 -5188 -4349 -5527 -5235 -4443 -3318 -5245 -4608 -4906 -4098 -4519 -3957 -5230 -4867 -3739 -4286 -4990 -5501 -4097 -4162 -5170 -4955 -4724 -4417 -3379 -4429 -3348 -4754 -6465 -4163 -4007 -5011 -4474 -4444 -5458 -5243 -5834 -5737 -4364 -4325 -5788 -4413 -3911 -3864 -4992 -4613 -4780 -5431 -4829 -3595 -4771 -5639 -5502 -5174 -4924 -4910 -5064 -4640 -5007 -4340 -5375 -4887 -4510 -6219 -5619 -4950 -4210 -3786 -5844 -4834 -5135 -4432 -4887 -4447 -4680 -4436 -4728 -6079 -3898 -4989 -4057 -4948 -4722 -4460 -3962 -5578 -3993 -3117 -4403 -3770 -4727 -4696 -4189 -5509 -4223 -5657 -5110 -4085 -4476 -2754 -3975 -4628 -4158 -4517 -5132 -4426 -4283 -5683 -4114 -7271 -4864 -5031 -5162 -6554 -3944 -4514 -5572 -4303 -3811 -6172 -3954 -6037 -6112 -6002 -6414 -4210 -4160 -4725 -5327 -3341 -6783 -4931 -5572 -4025 -4335 -5948 -5372 -3863 -5462 -4275 -3744 -4289 -3945 -5720 -5490 -4098 -4563 -3889 -5494 -6053 -5650 -5069 -5102 -4581 -5462 -6153 -6341 -4865 -5701 -3558 -4779 -4840 -4315 -3909 -4497 -4345 -3821 -5360 -5236 -4343 -5457 -4566 -5575 -4559 -6287 -5547 -4566 -5853 -5436 -4623 -4350 -3620 -4600 -5249 -4582 -5467 -4135 -4586 -4117 -4752 -4302 -4739 -5906 -5053 -3852 -5113 -3943 -4147 -2484 -4709 -5311 -4556 -3402 -5529 -5291 -4098 -5082 -5525 -2962 -4659 -5284 -4069 -4798 -4518 -6069 -4309 -2798 -3552 -4282 -5022 -4355 -5243 -4301 -4953 -3869 -6073 -3722 -5885 -4155 -6063 -5161 -4061 -4605 -5133 -5195 -5992 -5002 -6178 -4991 -5544 -4451 -3621 -4524 -4301 -5877 -5449 -4546 -4501 -4567 -4160 -5700 -5869 -5951 -4457 -3890 -4753 -5383 -6370 -5355 -5929 -5427 -4059 -5459 -5755 -4800 -4108 -5677 -4133 -3877 -5957 -5534 -5264 -4779 -5740 -5526 -5158 -4319 -5567 -4526 -3848 -3975 -4243 -4578 -5045 -4458 -4191 -4389 -6985 -6776 -5062 -4922 -4591 -5642 -4839 -4069 -4886 -4051 -5121 -4313 -5207 -5653 -4150 -5069 -5571 -5464 -5375 -6091 -4526 -3992 -3856 -6314 -4077 -5773 -4856 -4247 -4777 -4633 -5205 -6191 -4646 -4647 -4807 -5812 -4205 -5744 -4460 -5847 -5564 -5445 -5717 -4151 -6093 -4437 -5155 -7608 -5503 -5386 -3288 -6385 -5010 -5070 -4082 -3461 -4459 -3835 -4976 -5856 -4002 -5131 -5351 -6034 -4785 -5277 -4687 -4956 -5429 -5350 -4731 -6448 -5038 -5379 -4189 -3538 -5258 -4426 -4523 -6214 -5264 -5637 -4869 -4624 -6029 -4502 -4508 -4355 -4882 -5886 -5794 -4110 -4796 -5054 -5625 -3183 -4566 -4812 -3961 -3898 -5163 -4002 -5555 -4696 -5061 -6072 -4468 -5036 -4443 -5727 -4058 -6376 -3728 -5429 -3742 -5128 -4805 -6471 -5992 -6095 -4141 -5535 -3478 -4219 -4059 -4674 -4722 -4664 -3817 -5959 -5049 -6026 -5136 -4118 -6076 -4945 -3921 -4001 -4851 -5345 -3750 -5849 -3822 -3797 -6525 -4199 -3509 -5027 -4554 -4939 -5147 -4608 -4201 -3829 -5560 -6560 -3895 -4355 -4285 -4502 -3488 -4126 -4235 -5107 -4459 -4949 -4823 -5223 -4793 -4441 -5801 -3855 -4794 -5605 -5285 -3404 -5164 -5223 -4493 -6266 -5245 -4319 -3801 -6391 -3595 -3946 -4849 -5079 -5296 -4754 -5455 -7879 -6066 -3753 -2843 -6353 -5466 -4585 -4953 -6218 -6044 -5644 -4568 -2615 -4647 -6534 -5312 -5368 -3968 -4026 -4600 -4418 -4067 -4894 -5309 -4041 -3182 -5282 -5061 -5529 -3456 -3608 -4124 -6626 -4228 -4819 -4800 -4575 -5604 -5187 -4743 -4778 -3522 -4480 -6246 -5051 -3120 -3943 -3667 -4415 -6198 -4364 -4675 -6325 -6540 -5098 -4605 -4692 -5648 -4212 -6765 -4259 -5029 -5754 -4536 -4715 -4599 -3746 -5597 -7144 -4244 -5291 -4901 -3259 -4872 -5283 -4135 -4477 -4647 -4142 -4125 -4327 -4790 -3649 -4669 -5375 -4541 -5093 -4154 -5007 -3781 -4856 -5714 -4836 -5185 -4379 -4279 -6292 -4638 -4902 -4644 -5372 -7058 -5271 -6596 -5100 -5415 -4888 -4575 -6720 -5848 -4306 -6443 -6363 -4779 -4809 -6111 -5627 -4415 -5208 -3848 -4410 -3771 -3911 -3419 -4983 -3805 -4378 -5211 -6342 -5713 -4772 -6370 -5590 -4613 -4578 -4714 -5047 -5688 -3627 -4153 -5881 -5045 -3784 -6239 -4449 -5963 -5024 -4381 -4088 -4713 -5751 -3863 -5770 -3663 -5120 -4165 -4885 -5215 -5067 -5080 -4290 -2768 -5910 -5103 -4300 -5394 -5341 -4363 -4108 -4400 -4026 -5533 -5920 -4916 -5106 -6754 -5180 -5237 -4466 -4574 -3411 -4894 -4657 -6307 -2698 -4009 -6105 -4611 -5941 -4576 -5002 -5133 -4682 -4300 -5221 -5231 -5114 -4517 -3233 -4976 -4880 -5129 -4566 -4246 -4492 -5831 -3609 -3671 -5025 -3952 -5644 -4405 -4241 -5039 -5537 -4725 -5409 -4384 -5208 -4271 -3516 -4456 -3691 -3919 -5121 -5910 -3838 -5045 -5065 -3584 -4273 -4183 -5455 -4897 -4856 -5138 -6187 -4654 -5397 -5523 -5364 -6198 -4316 -4657 -5307 -4203 -4854 -4970 -4744 -3960 -3405 -5703 -3978 -5634 -6204 -5116 -5482 -5964 -2994 -4324 -4510 -6000 -5538 -3606 -6329 -4597 -3626 -4677 -5661 -5550 -3766 -4124 -5044 -4814 -5042 -5523 -5753 -4972 -4872 -4901 -5167 -4694 -5838 -4989 -3168 -2851 -3927 -4157 -5363 -5135 -4353 -4928 -5100 -5317 -4807 -4564 -4577 -6220 -3445 -5511 -5109 -4939 -4603 -6277 -4799 -4978 -4360 -4587 -5584 -3666 -5826 -4524 -5285 -4209 -4688 -3615 -4712 -3846 -6101 -5826 -4065 -5479 -4550 -4175 -3050 -2572 -4552 -5818 -5112 -4043 -6353 -3524 -4860 -6597 -6019 -5349 -4592 -4744 -4764 -4760 -5011 -4790 -4081 -4205 -3659 -4388 -4102 -4498 -5443 -5231 -2742 -4824 -4106 -5540 -4065 -4677 -4452 -4066 -5796 -3679 -4476 -4153 -4478 -5283 -4851 -4386 -4493 -3476 -5909 -5797 -4496 -4345 -4672 -3796 -4526 -4080 -4724 -4402 -5365 -3851 -6193 -4091 -3285 -6653 -3870 -3049 -4055 -4077 -5720 -5590 -4977 -4952 -5343 -4988 -3786 -4632 -4842 -4902 -3881 -5741 -3496 -4070 -4916 -4086 -4838 -5449 -5053 -5704 -3802 -5380 -4793 -6380 -6134 -6452 -4868 -4928 -4297 -5704 -4303 -3190 -5280 -4343 -4689 -6052 -4303 -4464 -5142 -3667 -4183 -4804 -6265 -5501 -6074 -5367 -4193 -4979 -4344 -4725 -4063 -6137 -5564 -5459 -3141 -5297 -5394 -3724 -5562 -4879 -4971 -4843 -4570 -3999 -3913 -5482 -5262 -3825 -5331 -5056 -3444 -4117 -6062 -4008 -5696 -4142 -3622 -5090 -4341 -5618 -3749 -5685 -3708 -3751 -5065 -5326 -4742 -4687 -4695 -4543 -4854 -3882 -5273 -3913 -4450 -4324 -5288 -5601 -4557 -4473 -4275 -4050 -4528 -3699 -4092 -4413 -3574 -6356 -5000 -4734 -6542 -4190 -4500 -6099 -5930 -3131 -4035 -5843 -4214 -5463 -4760 -4231 -4049 -4210 -4322 -5680 -5163 -5221 -4966 -5309 -4113 -3479 -4957 -3589 -4761 -3304 -5013 -5092 -4936 -4767 -5381 -5218 -5236 -4804 -5965 -4693 -3776 -4240 -5162 -5597 -5762 -5656 -4705 -5122 -3403 -3498 -4649 -3253 -4186 -4194 -4368 -3786 -4955 -5095 -4156 -3857 -4998 -4544 -3360 -5731 -4613 -3151 -3971 -6692 -2851 -3937 -4732 -4803 -4926 -5453 -4910 -5624 -5084 -4756 -5193 -5668 -5332 -5431 -4376 -4315 -5924 -4394 -4548 -6028 -4471 -4726 -4913 -5298 -5515 -5959 -4310 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/optimal.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/optimal.txt deleted file mode 100644 index 37177b0e1..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -5046 -5134 -5488 -4476 -5160 -4571 -4043 -4035 -5092 -5110 -5278 -3667 -4078 -5593 -5364 -4492 -5028 -3038 -4447 -3610 -4460 -4806 -4527 -3311 -3673 -3511 -3327 -3904 -4198 -3937 -4930 -3599 -5897 -3845 -4430 -4786 -6374 -2849 -4426 -3788 -4339 -3826 -3981 -4668 -5287 -4562 -4616 -2995 -4454 -5672 -3946 -4677 -4283 -5863 -4195 -4995 -3612 -5525 -4376 -5029 -4815 -4390 -3908 -4927 -2846 -5418 -2955 -5388 -3289 -4112 -2838 -5529 -5229 -4280 -3506 -4074 -4015 -5292 -3526 -4251 -4765 -3476 -3975 -4148 -4242 -4297 -4357 -3467 -4116 -4116 -3825 -3923 -3556 -4568 -4918 -4393 -4291 -3132 -2852 -5036 -4171 -4772 -5983 -4272 -4047 -4311 -3060 -5907 -5042 -4566 -4897 -4582 -5283 -6050 -4255 -6455 -4084 -4559 -5386 -3061 -4380 -4650 -5204 -4252 -3684 -3685 -3400 -3885 -3932 -3509 -3586 -3922 -6201 -4542 -3656 -5435 -4113 -6997 -4991 -6672 -3202 -4656 -3392 -4159 -4084 -3876 -3744 -5996 -3725 -3804 -5194 -4940 -4367 -5068 -3972 -3522 -5032 -3351 -4533 -5049 -3838 -3735 -5996 -4083 -3786 -3786 -3365 -3843 -4849 -4074 -4651 -3795 -3941 -4002 -4247 -4016 -5032 -4653 -3435 -4808 -3718 -3678 -3260 -5467 -4137 -6076 -2852 -3637 -4531 -4472 -4273 -3833 -5043 -4710 -4105 -4154 -5754 -4924 -3932 -3968 -4669 -4527 -3942 -3454 -3762 -4320 -3980 -4808 -3332 -5276 -3012 -4744 -4430 -2898 -3057 -5571 -5143 -3309 -3260 -4986 -3170 -3509 -4610 -4934 -3946 -4314 -4720 -4612 -3707 -4949 -3429 -4444 -3021 -4102 -4003 -3854 -3611 -4364 -4638 -4802 -5028 -3661 -3723 -5161 -4658 -4499 -3911 -4004 -5207 -3853 -5916 -5021 -5695 -4669 -3687 -4072 -4944 -4948 -5544 -4463 -3743 -5103 -4025 -4643 -5195 -3185 -4527 -4078 -4000 -4548 -5393 -4341 -3914 -5205 -4431 -4591 -6148 -4734 -3207 -3546 -3642 -6208 -3824 -4742 -5060 -5882 -4579 -4932 -5249 -4588 -4989 -5429 -4284 -4810 -3374 -3200 -2935 -4394 -3434 -4257 -5846 -4041 -3830 -3790 -3966 -3955 -4282 -5030 -5005 -5706 -5402 -4261 -4915 -4274 -4593 -5339 -4809 -3331 -4408 -3329 -4586 -4098 -4333 -4831 -5100 -5299 -4124 -4392 -5268 -3825 -3627 -4462 -5106 -3682 -4598 -4540 -4467 -4548 -3367 -4336 -6174 -4098 -5481 -5813 -4069 -4829 -2737 -4648 -3842 -4798 -4637 -5087 -4896 -4093 -3969 -4305 -5777 -4379 -5576 -5428 -5137 -4334 -4369 -4559 -4345 -4928 -3997 -4668 -1993 -3976 -4397 -4164 -4755 -3119 -4020 -5847 -4849 -5220 -3507 -4483 -3666 -4553 -4090 -4039 -4015 -3843 -4335 -4383 -4144 -6519 -3105 -4593 -4318 -4851 -3360 -4783 -5071 -3975 -4556 -3485 -3970 -3967 -4218 -4961 -4745 -3840 -4970 -3936 -5024 -4274 -4252 -4201 -4749 -4376 -4581 -4313 -5562 -4647 -3853 -3690 -5036 -3642 -5439 -5642 -4156 -2490 -4837 -4243 -3085 -4236 -5260 -4203 -4980 -3922 -4219 -4407 -3704 -5948 -4298 -4240 -3184 -4268 -2039 -4544 -4964 -5274 -4186 -5656 -3546 -4475 -3846 -3817 -4289 -3347 -4876 -4930 -3824 -4334 -5607 -4497 -4826 -4112 -4753 -4257 -4426 -4580 -4090 -3679 -3778 -3717 -4735 -4737 -4826 -5556 -4308 -4169 -4123 -4122 -4005 -3091 -2943 -4620 -5193 -4380 -3805 -4376 -3566 -3487 -3705 -5008 -3671 -3588 -3269 -4837 -2615 -3499 -5462 -3587 -4317 -6072 -4490 -4252 -3916 -2837 -4394 -2571 -5019 -4519 -5061 -3473 -6631 -4829 -2985 -3959 -5046 -3713 -4640 -4672 -6005 -5266 -3805 -6239 -3416 -3995 -4419 -3316 -4071 -3493 -4033 -4537 -5437 -4300 -3432 -4058 -3551 -4355 -4316 -3710 -3924 -5097 -4875 -4197 -5003 -3793 -3746 -5544 -3732 -3888 -5676 -3843 -3680 -5481 -4477 -4565 -5412 -5788 -5564 -4160 -5147 -4470 -5070 -3716 -4963 -6137 -5437 -4113 -6419 -4689 -4001 -3732 -4428 -4603 -2587 -4401 -5186 -4025 -5479 -4815 -5686 -4797 -4383 -5856 -3611 -4619 -3737 -3599 -5924 -5037 -5304 -4968 -6516 -4110 -4896 -5617 -2996 -4148 -4041 -5247 -5602 -3949 -4412 -3073 -5242 -3157 -2217 -3093 -3430 -4953 -3768 -5472 -4842 -5197 -3174 -5664 -3953 -3057 -6377 -3698 -4332 -4444 -4078 -5104 -3369 -6664 -4670 -5466 -3136 -3479 -5557 -3900 -4163 -4225 -4210 -5626 -3616 -6054 -4896 -4462 -4446 -4829 -3114 -4712 -3704 -4938 -4094 -4088 -3052 -3574 -5983 -4841 -4477 -4594 -3797 -5260 -5180 -4733 -5214 -3791 -5314 -4197 -4013 -4453 -4499 -4156 -5242 -3867 -3595 -4718 -5973 -4714 -4359 -4682 -3401 -4236 -3039 -4743 -4672 -4069 -6544 -2814 -7091 -4084 -4735 -3784 -4782 -3749 -3100 -3670 -4824 -3689 -4387 -4112 -4298 -2487 -4070 -4592 -2881 -4463 -4340 -4605 -3532 -5218 -4415 -3655 -4727 -2202 -4801 -5616 -4417 -6141 -4816 -5301 -3174 -4455 -3792 -4904 -5565 -4684 -3780 -5370 -3740 -4580 -3779 -5531 -4626 -5763 -3687 -4331 -4475 -3455 -4668 -4687 -3680 -4425 -3578 -5226 -5169 -4815 -4555 -4120 -4617 -3366 -4046 -5723 -3840 -3775 -4156 -3929 -5206 -4771 -4172 -3091 -3691 -3468 -3448 -4238 -2971 -4500 -4357 -4618 -5070 -2965 -4407 -3730 -5215 -5000 -4375 -5475 -6124 -4671 -4708 -5591 -4710 -3979 -4121 -6190 -6312 -5119 -3858 -6746 -4076 -2452 -4243 -4510 -4361 -2827 -5348 -3136 -5328 -4720 -3961 -5784 -4939 -4719 -4384 -3550 -3986 -4184 -5371 -4314 -3675 -3773 -4504 -4775 -3764 -5464 -4280 -5533 -4508 -4472 -3757 -3412 -4018 -5224 -4301 -4948 -3651 -3834 -4511 -4162 -4886 -5218 -4585 -4648 -4069 -5077 -4880 -4463 -4133 -3479 -3777 -5382 -4210 -3550 -4805 -4447 -3775 -4660 -4930 -3650 -3566 -4407 -3913 -3978 -4443 -3546 -4389 -3988 -4205 -4139 -5160 -5238 -4623 -4741 -3990 -5961 -3728 -4826 -4805 -3720 -3004 -5047 -4399 -4731 -4095 -3837 -4876 -3226 -5832 -4558 -4023 -4342 -5108 -3902 -5293 -3243 -3168 -5011 -3956 -5112 -4745 -3895 -4013 -5712 -5218 -5478 -4682 -4007 -3209 -2862 -5858 -6272 -5316 -4284 -5520 -2903 -3934 -5317 -2967 -3515 -4716 -4016 -4328 -4871 -3826 -4343 -5148 -4127 -3960 -4314 -3249 -4690 -4133 -3975 -5166 -3572 -3682 -3488 -3789 -3755 -4823 -3798 -3384 -4245 -3901 -3052 -6889 -3325 -4908 -3163 -4017 -4560 -3640 -4749 -3905 -3394 -5094 -4209 -7087 -5987 -3876 -3879 -4957 -3883 -4669 -5994 -4363 -4050 -5310 -2608 -3715 -3266 -4456 -3874 -4383 -5840 -4597 -4452 -3451 -5310 -3946 -3407 -4898 -3933 -4704 -4915 -4573 -4598 -5179 -3526 -5355 -4613 -3642 -4795 -5293 -5713 -5428 -4024 -6696 -3929 -4564 -3579 -3212 -4471 -4809 -3448 -4115 -3856 -4825 -3865 -3771 -4440 -4985 -4573 -3688 -4183 -3869 -4240 -2746 -4205 -4035 -4519 -5484 -4778 -4352 -6747 -5086 -4839 -4906 -4143 -4701 -3994 -5135 -4701 -4319 -4639 -3535 -5130 -4371 -3463 -4672 -4444 -4582 -3568 -3924 -4675 -4454 -4545 -4423 -3472 -4816 -3146 -4457 -3848 -4232 -4796 -3665 -3948 -4192 -4109 -5158 -4642 -6245 -5426 -3629 -3217 -5047 -5329 -4901 -3810 -3425 -4088 -4815 -3941 -5068 -5163 -4480 -3732 -2727 -6041 -3478 -6370 -4822 -4438 -4725 -3688 -3737 -3852 -4071 -3746 -4964 -3946 -4035 -4684 -3669 -4194 -2970 -4236 -4663 -4036 -4246 -5038 -4529 -4439 -3309 -3461 -3567 -4159 -3783 -5423 -5507 -4029 -4635 -5176 -3146 -3068 -5094 -3896 -4702 -4839 -4437 -4252 -4947 -6146 -4490 -3652 -4095 -4038 -4387 -4382 -3471 -5377 -4329 -4868 -5879 -4192 -5630 -3411 -4094 -4659 -4635 -4513 -4203 -4148 -5693 -5876 -5727 -5465 -4645 -5881 -5291 -4624 -5970 -4738 -4262 -3706 -4779 -4558 -4050 -4659 -2934 -3691 -2950 -5072 -3439 -3857 -4161 -3815 -4623 -4353 -3574 -6045 -4360 -4724 -3658 -4216 -3840 -5553 -4197 -4689 -2193 -4442 -3672 -4750 -5857 -4596 -5261 -6102 -3702 -4516 -5266 -4190 -4372 -3506 -4827 -3915 -5018 -4020 -4633 -4544 -4433 -5244 -4000 -5356 -3259 -4628 -5216 -5277 -4564 -4598 -4474 -4266 -3452 -5399 -7398 -4594 -4606 -5156 -4240 -4682 -4032 -4024 -2988 -4519 -4176 -4924 -5201 -4349 -4172 -4591 -3372 -4119 -4223 -4394 -4326 -5518 -3687 -5714 -4732 -5376 -4687 -4825 -4086 -4391 -4402 -3918 -4136 -2916 -3916 -3892 -3855 -5034 -4713 -3959 -5069 -4398 -4465 -3519 -6392 -4375 -4161 -3457 -2634 -5107 -4310 -4525 -5342 -3943 -3868 -4568 -4624 -4046 -3780 -4485 -4786 -3660 -3352 -6861 -5588 -4077 -4432 -4672 -5764 -5034 -3786 -4405 -2913 -4722 -5359 -3967 -5755 -4404 -3506 -3868 -4009 -4941 -4571 -4991 -4931 -5243 -3845 -3480 -4376 -3788 -3722 -5336 -4793 -5079 -4356 -4313 -5427 -4050 -4895 -4183 -3674 -4430 -3685 -5656 -4936 -4231 -4881 -2953 -5740 -3772 -5578 -5449 -4988 -3658 -4298 -3982 -4494 -3939 -5089 -3846 -4566 -4865 -3701 -3546 -5474 -4094 -4155 -3970 -4467 -3897 -2635 -4915 -4369 -3304 -4054 -3827 -4233 -5109 -5387 -3661 -4970 -5143 -4621 -4625 -2764 -3839 -3047 -3825 -3383 -4903 -3907 -3231 -5625 -3307 -3109 -3191 -2337 -4256 -4422 -4272 -4421 -3698 -4436 -4348 -4365 -4483 -4797 -3461 -4546 -4184 -3681 -7243 -4194 -4458 -4448 -5307 -5053 -4498 -4289 -4294 -4985 -3840 -3851 -4288 -4085 -3912 -5107 -3827 -3451 -4941 -5494 -5046 -4236 -4116 -3007 -5352 -4155 -3469 -4756 -5187 -3913 -5461 -4264 -5086 -3744 -4157 -5154 -3800 -4017 -4169 -4453 -6172 -4108 -4837 -4736 -4713 -5458 -5119 -3582 -3603 -3903 -4439 -4307 -3801 -3492 -5339 -3075 -5988 -4975 -4431 -4070 -5452 -3694 -5041 -3413 -3782 -3670 -4625 -4989 -4416 -3827 -4340 -4639 -4898 -3682 -4531 -5252 -5444 -5272 -3065 -5046 -5137 -3780 -3626 -4154 -5546 -4330 -3749 -3718 -3781 -4292 -4007 -4801 -4530 -3272 -2913 -4679 -4679 -4147 -3203 -3065 -4548 -2638 -5011 -2929 -6272 -4041 -3363 -5419 -6216 -4477 -3139 -5194 -5201 -4354 -5759 -4396 -4915 -5400 -4182 -4493 -3245 -4037 -5373 -5100 -6425 -4078 -4206 -3704 -5488 -5532 -5437 -4686 -3904 -4354 -4202 -3133 -3695 -4380 -4611 -3941 -4286 -4561 -3974 -3896 -4243 -5302 -4441 -5351 -4085 -3843 -4390 -6356 -5062 -4350 -4769 -4229 -3855 -4096 -4266 -3557 -4652 -4312 -5131 -3850 -4570 -4140 -4380 -5120 -4559 -4759 -3356 -3806 -4068 -3955 -3963 -3477 -5782 -4848 -3968 -3860 -3222 -3578 -5317 -4751 -3806 -3765 -3320 -4088 -4172 -4112 -5276 -4828 -6007 -5230 -4330 -3862 -5908 -4546 -5704 -4248 -3754 -4153 -4573 -4185 -4865 -3981 -5032 -6041 -4013 -3968 -3951 -4811 -3801 -4403 -3127 -6896 -5264 -6104 -3892 -4508 -4170 -6372 -4885 -4553 -5769 -4155 -4150 -3962 -3535 -2999 -4657 -6406 -5210 -3747 -3827 -5334 -4088 -5252 -5681 -5188 -5297 -3891 -2849 -4096 -4006 -4427 -4329 -5111 -4029 -4655 -4104 -3770 -4347 -5445 -5861 -4105 -3753 -4932 -4925 -3818 -5254 -2999 -5030 -6979 -4064 -3913 -4204 -4869 -5447 -3578 -5111 -4671 -4514 -5214 -3558 -4792 -3428 -4352 -4712 -4733 -4093 -4837 -4897 -5079 -4381 -4015 -4259 -4816 -4423 -4796 -4673 -3184 -4838 -3613 -3501 -3764 -5494 -4086 -5269 -4999 -3484 -4947 -4702 -3293 -3546 -4821 -4426 -4093 -4752 -4993 -4563 -4208 -5420 -3791 -3937 -4403 -4923 -4400 -4860 -4870 -4305 -3255 -3190 -3570 -4194 -4204 -4466 -4384 -3925 -3291 -4550 -5882 -3864 -4792 -4637 -3551 -4719 -4069 -6047 -3979 -4820 -4121 -3415 -3808 -4283 -3703 -4021 -4604 -5124 -4806 -5859 -3467 -3984 -5249 -4853 -4795 -4588 -4402 -4028 -3228 -5532 -3224 -3686 -4469 -4795 -4457 -5172 -5588 -4486 -5672 -4719 -4461 -4417 -3672 -3732 -5164 -4533 -5777 -4921 -4668 -3995 -5792 -4043 -5045 -3874 -4736 -5558 -3104 -5063 -3326 -4421 -3848 -4792 -4452 -5307 -4857 -3732 -5347 -3838 -5198 -4244 -3788 -3652 -4758 -4071 -4536 -3530 -4052 -4216 -2969 -5567 -4112 -4000 -4538 -4115 -4650 -5459 -4336 -3393 -4464 -3464 -3731 -4229 -3558 -4050 -5278 -6417 -4925 -5359 -3416 -4511 -4370 -3356 -2939 -5688 -4311 -3959 -3352 -3186 -5082 -4491 -3391 -3334 -4054 -4356 -4497 -4248 -4761 -4548 -4350 -3428 -4316 -4820 -4651 -4965 -5452 -4258 -5292 -4124 -3596 -3488 -3213 -5180 -3505 -4552 -4200 -3833 -3090 -3778 -3226 -4931 -4481 -3404 -4476 -4661 -5361 -5410 -4221 -5210 -3944 -4181 -4228 -4273 -4913 -2949 -3110 -4421 -4237 -4407 -4951 -4976 -5407 -4257 -4148 -3390 -5070 -3357 -3603 -4959 -4917 -5359 -4350 -4969 -2999 -3876 -5333 -4370 -3658 -5483 -5099 -4210 -5227 -4492 -2214 -3859 -5225 -3772 -5054 -6153 -4154 -3752 -4546 -4149 -5916 -4257 -4728 -5641 -4088 -4346 -3256 -3929 -3417 -4542 -3040 -3891 -4076 -4461 -4613 -4619 -3847 -4874 -4443 -5076 -5603 -4984 -3029 -4462 -4149 -4464 -4366 -6049 -3870 -5089 -3979 -4216 -3803 -3958 -4326 -4643 -4648 -4963 -3968 -3364 -3611 -5645 -4956 -4422 -5220 -4269 -4561 -4432 -5480 -4387 -5073 -4794 -4442 -3900 -5174 -4727 -4914 -4458 -3646 -6018 -3147 -4323 -4090 -7025 -4539 -3822 -5062 -4487 -3920 -4503 -4571 -4499 -3948 -4256 -3217 -5552 -4965 -4606 -4523 -4651 -4110 -5011 -4587 -4849 -4512 -2987 -4576 -3872 -4310 -5385 -3914 -4270 -3247 -3692 -4794 -4554 -3431 -5563 -4119 -3683 -5024 -5627 -3826 -4143 -2916 -2870 -5642 -4344 -4773 -4246 -4335 -5652 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/random.txt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/random.txt deleted file mode 100644 index cb6263229..000000000 --- a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -25467 -26826 -29440 -25590 -32388 -27314 -31532 -28737 -30348 -25920 -25450 -23929 -33323 -31450 -23450 -24862 -25404 -26358 -37244 -33536 -45805 -20401 -30234 -25867 -16638 -34966 -23267 -31685 -35849 -32349 -27944 -35179 -37322 -33628 -36178 -31477 -31713 -24533 -29812 -19064 -30187 -42676 -35816 -32817 -30891 -33355 -29350 -32478 -27416 -25104 -28154 -25525 -23374 -26876 -33035 -27202 -29470 -32457 -28952 -21692 -19976 -29777 -30457 -31839 -24660 -29181 -22917 -28014 -25274 -33949 -31191 -32648 -36047 -30996 -24510 -27390 -40914 -37126 -37546 -30447 -19639 -35176 -29635 -30339 -33184 -23905 -31882 -30754 -34660 -24177 -27684 -18472 -34709 -28297 -29365 -28719 -23631 -35877 -27847 -33177 -30774 -22894 -26044 -24891 -25649 -28212 -29609 -29136 -28260 -28014 -33120 -26929 -31178 -25622 -29263 -25136 -34515 -31486 -18088 -27988 -21251 -29886 -23438 -38987 -30528 -26668 -22764 -31379 -24366 -30298 -23349 -35933 -34444 -34481 -31748 -35354 -17706 -40314 -23812 -27061 -28541 -26804 -27585 -29677 -26423 -33589 -20374 -28725 -31252 -29016 -24168 -29124 -32056 -26925 -32387 -26366 -24107 -28278 -24340 -29066 -22775 -30329 -21176 -29440 -24645 -29462 -22974 -32429 -36469 -30451 -27504 -35978 -31447 -24407 -32347 -26300 -32068 -31953 -31646 -35366 -20540 -23680 -25247 -21657 -29341 -23759 -28727 -25155 -35197 -23115 -24569 -24291 -43931 -26387 -37540 -24243 -29034 -24241 -29652 -18110 -32320 -23210 -32013 -26521 -31110 -36237 -26764 -38909 -20491 -30480 -28099 -28002 -42075 -19758 -24536 -24496 -32434 -28006 -29639 -36395 -34730 -32756 -26612 -26036 -38022 -29240 -30288 -29311 -31675 -28212 -27538 -24546 -28447 -31633 -27778 -27102 -34954 -28750 -35076 -27899 -28762 -24343 -40869 -20889 -31746 -44139 -25875 -20709 -33303 -26419 -22581 -30203 -32766 -27374 -26024 -26985 -33109 -34609 -28254 -31986 -25985 -27803 -34386 -21620 -29741 -33716 -31779 -31727 -27787 -26284 -21189 -31241 -27121 -33992 -28479 -27491 -33776 -30331 -19588 -22269 -31650 -35522 -34312 -38173 -29899 -34764 -23317 -27439 -30761 -28214 -23483 -31614 -31434 -26274 -26006 -28297 -35843 -32556 -31562 -27426 -21058 -17404 -26882 -16653 -27873 -26537 -29613 -28710 -29838 -32816 -31880 -35625 -29065 -25711 -23584 -35156 -30503 -27691 -27730 -34100 -25861 -34752 -30358 -40481 -30930 -36657 -31906 -23180 -38521 -28864 -34855 -28093 -34260 -28405 -28201 -34659 -26435 -25666 -30080 -26864 -24757 -28316 -23198 -32876 -30834 -23674 -36594 -27580 -31018 -19728 -29650 -23756 -35034 -16716 -38848 -28050 -36580 -19136 -30257 -25990 -29921 -24764 -32299 -22429 -30011 -29412 -30825 -22313 -35141 -30265 -32570 -23442 -21647 -21749 -19005 -29780 -31483 -25135 -23525 -28546 -19213 -24198 -23615 -37637 -28067 -24996 -29074 -32418 -29872 -28862 -38957 -27083 -35581 -30467 -38572 -22151 -26954 -36847 -29618 -22754 -25107 -44837 -28017 -33131 -34890 -29274 -27789 -20328 -32727 -27665 -32117 -24983 -24283 -27438 -29240 -32352 -30883 -28455 -24030 -25138 -32920 -31306 -38387 -22366 -26104 -28537 -19244 -24272 -28753 -28658 -30981 -28830 -27054 -26054 -23680 -39599 -28887 -18476 -30878 -25998 -23537 -26765 -32988 -32850 -35323 -24307 -23288 -36367 -23399 -43868 -29645 -24387 -22910 -24789 -28159 -24657 -26006 -26908 -24099 -32462 -30142 -24017 -27321 -28797 -33969 -43664 -39227 -24394 -25081 -26760 -33376 -25905 -31476 -29409 -30632 -26433 -39736 -29459 -24991 -30603 -22944 -26843 -34397 -36690 -29894 -25582 -22510 -30501 -25701 -28686 -32146 -30735 -43888 -25499 -36478 -22306 -25671 -25349 -35569 -31711 -33701 -29309 -22380 -32131 -27310 -30430 -28478 -34931 -30944 -28223 -30263 -23132 -39714 -33089 -35287 -28991 -23418 -34737 -31989 -21484 -25295 -21454 -30878 -37014 -41885 -31613 -21781 -32650 -34978 -28093 -30655 -25192 -21403 -33079 -28585 -24365 -23760 -22732 -38445 -24257 -22002 -24198 -26478 -26050 -40598 -28378 -31792 -39470 -21181 -24667 -24549 -25312 -28177 -28725 -37076 -22546 -20350 -28161 -36689 -36090 -26679 -30215 -30158 -28228 -28996 -27281 -25338 -30461 -27690 -18260 -20130 -30993 -20794 -26127 -31311 -29770 -28584 -29391 -27324 -29717 -26215 -21031 -21895 -29834 -31591 -31915 -32281 -26126 -32736 -36029 -35192 -32806 -30760 -20699 -23825 -26106 -25428 -36654 -38613 -26871 -29172 -27911 -25450 -37171 -27448 -31177 -27421 -48475 -26801 -27587 -25944 -31517 -29490 -40401 -27317 -33703 -28417 -28639 -25031 -33611 -31697 -20689 -31454 -23462 -21371 -38259 -34972 -35767 -28127 -21603 -30303 -20432 -19833 -21899 -30013 -21614 -31981 -31269 -36203 -28121 -33719 -30237 -27097 -29661 -28330 -36133 -25070 -25146 -22765 -28330 -23840 -26707 -24042 -26684 -23606 -28079 -30954 -25686 -30407 -22562 -21346 -29224 -34062 -25744 -34455 -21914 -28310 -24598 -29376 -27238 -32804 -27611 -24085 -22189 -33628 -24415 -31932 -24483 -37025 -35298 -20936 -34014 -30238 -31536 -21032 -30220 -25647 -23113 -26701 -32921 -32639 -24049 -25055 -34878 -46749 -17346 -26850 -34543 -31769 -25088 -27359 -20644 -33679 -27179 -31618 -28096 -39698 -24822 -31437 -25339 -25292 -30530 -28321 -32814 -33980 -30693 -32833 -20916 -21140 -36218 -25689 -27483 -33017 -37314 -22509 -31323 -31722 -31116 -28686 -27520 -37124 -40304 -22474 -34045 -27075 -25855 -23826 -38341 -37321 -27992 -22106 -29701 -24154 -36464 -19200 -28819 -23227 -34475 -38165 -32095 -26479 -26408 -27123 -32783 -30124 -25881 -28368 -34624 -24068 -36641 -26379 -28625 -21895 -25717 -31079 -18958 -34320 -28168 -26788 -31094 -26757 -25313 -39539 -26563 -22133 -29597 -33392 -23843 -21599 -27253 -21372 -28347 -38260 -35185 -31276 -18664 -24735 -28746 -33751 -26289 -34819 -30133 -22464 -22629 -24131 -29951 -21735 -24949 -24006 -28022 -31657 -37911 -24920 -30479 -18102 -27087 -33221 -33432 -24384 -20969 -36402 -30665 -33625 -26722 -29669 -34871 -33601 -29388 -33209 -31492 -24392 -37000 -22029 -30342 -37441 -23470 -31901 -34206 -26801 -24439 -30929 -31203 -20874 -33182 -29469 -25425 -32986 -26051 -31143 -19880 -28604 -31269 -30070 -31910 -20209 -35465 -26622 -30425 -32830 -30159 -33948 -28383 -29986 -30049 -23868 -33011 -42404 -31430 -38070 -23064 -30890 -30199 -17892 -47323 -29448 -24504 -29775 -29841 -43392 -23052 -32992 -29565 -32975 -22003 -24834 -25914 -32917 -28098 -33303 -27121 -21702 -27764 -24443 -25053 -15956 -33323 -22655 -28277 -21264 -18667 -24253 -29577 -35480 -29134 -33471 -31812 -27880 -19950 -31034 -26399 -33565 -33437 -27712 -35400 -27408 -22611 -22376 -23346 -24629 -26094 -27215 -27911 -20524 -29502 -28771 -29303 -20897 -19724 -32494 -32594 -25064 -26772 -30200 -25535 -22384 -20230 -26180 -21538 -22215 -23398 -28548 -33598 -34492 -33031 -34683 -23245 -22424 -27939 -29266 -30747 -21269 -35686 -24341 -22156 -23560 -36682 -31602 -23201 -31148 -29936 -24588 -25330 -34165 -28058 -29215 -26087 -17866 -24806 -19521 -25137 -34101 -33414 -30180 -27042 -30417 -22434 -32285 -29690 -39199 -30776 -28453 -30921 -27300 -26012 -38492 -23009 -23512 -34519 -20303 -29112 -31226 -28029 -27983 -26242 -28483 -25957 -36251 -30627 -27489 -27121 -31090 -25020 -24642 -24719 -35454 -26647 -24454 -28775 -36047 -27138 -25744 -24854 -37308 -27049 -14462 -25453 -32157 -30544 -33607 -25613 -31924 -23987 -43031 -38458 -25983 -27463 -31081 -22727 -21961 -36354 -31433 -25597 -24156 -31639 -30319 -28790 -21254 -24362 -24874 -18970 -40051 -34580 -29132 -26893 -32418 -21443 -22688 -32014 -35343 -32994 -20945 -28229 -28957 -30738 -28262 -30382 -26818 -33800 -23084 -24137 -27074 -29573 -27969 -21194 -26015 -32340 -21478 -31749 -31358 -35647 -32254 -37959 -34332 -36242 -29331 -24446 -40811 -31995 -21426 -36811 -41947 -31151 -26612 -29802 -25138 -30903 -21746 -28196 -31056 -21656 -35465 -29104 -34699 -36242 -18878 -42509 -28099 -28886 -26070 -26714 -26717 -22436 -19050 -28168 -25936 -29629 -35471 -23476 -38619 -34788 -29853 -24691 -35424 -37184 -32511 -25271 -31040 -26834 -33933 -39950 -32544 -25585 -38318 -31634 -26822 -28100 -33654 -30325 -22760 -33675 -27719 -30751 -24205 -27200 -27861 -29453 -32774 -20631 -34323 -26341 -31195 -33713 -30315 -28824 -36569 -24824 -33419 -30965 -25402 -33845 -36318 -27931 -23309 -30121 -32715 -25292 -33398 -25954 -31039 -35239 -22277 -24418 -40194 -34807 -31559 -21744 -18297 -30154 -31189 -28897 -30075 -26809 -27666 -38590 -31802 -30574 -29180 -25189 -16325 -29264 -21386 -27202 -26067 -27751 -26939 -26974 -26922 -34110 -26352 -24466 -25911 -24555 -32348 -24790 -29747 -28424 -31793 -28213 -26908 -29657 -31624 -28584 -22133 -41602 -28186 -44342 -44262 -35860 -32152 -28736 -31319 -26224 -39449 -33495 -23840 -33208 -18091 -29392 -27631 -26108 -19672 -34178 -25827 -45829 -26222 -31206 -29284 -28642 -25050 -35271 -27094 -23631 -28339 -29971 -24782 -33798 -35234 -32039 -26940 -22934 -43568 -25886 -20776 -33337 -26054 -20711 -38366 -19815 -22706 -36453 -19007 -31151 -30169 -29463 -30334 -21038 -28436 -25748 -28156 -27691 -24256 -35864 -25634 -30062 -25440 -31330 -25533 -25808 -34318 -29963 -26555 -36810 -32291 -27078 -29615 -27380 -31377 -26926 -32860 -22053 -21028 -31227 -32438 -36702 -30415 -24470 -22446 -26426 -25481 -40967 -19233 -34280 -27454 -25354 -30742 -23167 -32937 -20894 -18608 -22392 -33160 -28839 -22818 -21122 -21863 -24751 -34149 -35836 -29151 -36063 -29401 -31695 -32332 -23101 -23243 -37743 -26644 -28864 -26999 -29780 -30719 -28871 -22257 -26993 -25672 -24145 -28151 -32217 -24110 -24647 -29545 -27825 -20033 -33747 -25263 -29136 -28314 -34292 -27613 -29087 -30475 -29701 -19718 -26554 -31095 -34618 -21743 -21117 -31525 -25697 -31821 -22704 -22544 -30324 -33289 -34277 -23643 -37781 -30655 -28246 -26885 -46737 -24465 -30514 -32124 -25338 -28957 -29014 -23953 -25334 -25714 -44251 -18165 -24930 -18831 -24314 -23019 -29806 -28736 -22449 -24093 -27449 -26282 -27817 -32545 -20539 -36667 -32657 -38604 -23121 -29562 -29161 -25299 -22158 -22495 -21121 -26262 -31740 -18334 -27644 -25961 -38316 -24698 -32426 -30810 -29798 -22783 -23352 -36514 -29347 -28635 -39907 -23519 -28762 -31262 -36288 -32195 -30451 -22951 -26566 -23317 -23912 -25971 -18548 -30223 -18098 -19105 -20806 -31506 -23570 -30983 -33602 -27656 -26989 -40227 -34771 -24080 -31646 -40302 -20705 -23136 -29941 -38256 -37251 -35559 -33070 -23762 -26525 -28545 -34431 -31667 -28939 -18402 -26998 -20695 -24004 -32751 -33533 -34119 -27225 -30032 -20442 -27431 -33784 -26962 -31808 -30280 -25207 -42351 -25864 -27931 -24099 -30803 -28061 -27599 -28788 -28650 -27529 -24020 -21949 -32603 -34751 -42911 -32940 -35244 -30731 -37800 -24215 -34852 -24053 -33316 -18490 -28382 -28082 -27625 -25169 -29918 -24019 -35401 -29047 -31640 -22589 -30365 -33221 -33867 -28200 -38287 -28713 -29194 -26973 -27855 -31461 -29574 -29433 -27565 -24662 -33062 -26129 -17289 -20847 -24778 -23390 -28329 -36957 -28496 -27831 -37640 -28366 -31376 -25565 -28342 -30065 -19594 -18935 -27721 -31696 -30042 -35499 -20875 -28250 -28282 -30684 -21114 -25568 -23699 -28657 -25959 -29945 -25094 -35605 -32332 -28693 -32286 -26965 -37297 -29095 -31758 -26409 -20754 -20798 -24842 -29422 -33231 -29032 -22338 -33526 -27947 -30982 -25444 -29263 -34423 -22290 -25275 -34769 -30397 -27438 -35881 -28939 -28122 -31881 -27068 -37259 -31552 -33382 -31921 -30791 -24222 -26403 -28811 -21695 -35766 -29400 -28377 -28403 -30917 -25486 -28607 -34277 -30584 -43024 -19819 -30813 -36483 -31560 -29743 -29572 -42299 -37570 -38847 -33098 -34713 -28029 -15564 -27304 -28511 -25668 -28746 -18962 -29055 -21593 -31880 -40365 -37018 -21934 -26691 -28968 -27911 -25276 -34453 -32744 -35573 -34083 -30370 -36279 -33470 -21102 -32651 -22880 -28986 -31620 -19939 -32040 -17199 -25491 -34729 -23955 -16138 -32696 -32795 -36140 -28827 -26559 -27010 -40783 -34983 -24039 -29338 -29931 -30048 -32619 -36928 -30482 -37611 -26169 -22796 -27277 -35164 -29897 -27637 -30001 -24789 -30867 -33153 -25884 -28483 -40137 -32424 -39557 -30794 -26884 -33805 -28366 -27699 -28856 -34177 -40151 -32388 -30202 -32166 -24413 -37605 -27929 -24570 -23058 -28672 -29252 -26501 -29725 -43650 -26476 -26719 -24818 -34833 -21660 -29435 -25890 -24486 -20397 -29266 -43527 -37335 -30717 -29258 -30484 -35095 -24258 -30281 -39497 -42462 -23605 -40975 -31591 -28097 -37499 -30721 -22397 -25536 -26784 -33792 -28318 -36710 -30718 -24250 -30253 -28888 -39004 -23818 -19897 -30690 -27140 -31916 -25827 -23726 -23355 -25714 -37922 -21967 -29217 -34178 -35147 -25857 -25892 -16478 -32581 -33121 -38355 -31250 -26330 -25046 -23646 -20819 -28238 -43890 -32230 -30559 -34869 -28412 -24941 -27894 -21262 -21433 -24114 -24413 -31658 -25961 -39950 -29049 -26706 -28480 -26825 -22457 -25453 -37641 -27878 -35540 -22246 -24634 -31684 -37769 -28692 -21944 -25094 -29100 -29749 -33136 -22131 -29289 -34559 -20890 -41590 -37042 -28702 -21205 -22363 -26277 -28258 -36029 -36031 -35218 -30311 -29380 -28104 -35631 -24561 -34322 -28436 -27799 -29394 -36254 -25144 -26692 -26955 -24424 -21139 -27141 -33232 -27764 -27488 -27083 -21399 -39130 -27915 -29159 -30955 -22311 -24689 -29100 -25903 -35808 -26262 -22470 -31293 -30703 -24000 -34764 -40983 -14737 -28954 -37220 -26123 -36910 -22345 -23446 -27194 -30310 -27361 -21185 -29553 -24214 -28606 -21512 -25060 -32708 -23352 -25171 -39847 -28807 -34325 -34536 -28880 -35866 -28440 -39875 -32594 -26233 -32319 -30327 -31314 -28742 -23016 -32393 -45712 -29633 -23958 -31008 -30747 -37080 -31678 -22023 -25874 -23426 -20268 -20063 -26093 -24907 -43742 -27215 -20776 -27804 -31217 -25633 -32635 -29298 -25273 -25331 -27638 -29371 -31883 -30423 -39534 -21697 -23204 -21715 -23242 -33357 -30181 -18445 -32293 -25703 -35799 -22416 -16430 -28048 -25920 -31343 -22108 -34391 -27487 -19646 -20932 -30083 -25471 -35091 -33129 -28353 -27761 -24931 -39930 -27502 -35821 -38575 -31940 -23945 -28259 -23387 -30319 -28805 -28384 -35388 -40021 -17569 -36766 -31764 -28858 -32537 -28593 -27702 -29314 -23938 -39662 -32343 -30135 -19558 -22215 -18002 -30629 -29293 -34105 -27119 -31063 -33405 -33361 -26172 -27567 -22166 -28033 -26725 -34636 -24178 -20976 -32348 -27129 -36364 -42092 -26054 -24643 -31559 -33682 -28811 -23374 -27939 -24948 -29776 -27616 -23764 -34110 -25483 -26445 -29817 -29292 -27235 -25298 -30644 -27235 -29079 -33624 -26799 -27465 -30452 -26921 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best.pt deleted file mode 100644 index c113c6c49cdb76d1ffeb833af1c9fe65cf990055..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14231 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 HUv>W%s2-6C diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_1.pt deleted file mode 100644 index c35e68868f259719418be69aa4b13a012023fee2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14231 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 ZP5A5i_uum!q-B0T$%%fy+yB+}e*ueSf?ogt diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k7/trained_ddqn/best_seed_2.pt deleted file mode 100644 index e65d286be6219b209c9d4a7e763fb2c5b557db4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14231 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 F{~uC9wEO@7 diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_1.pt deleted file mode 100644 index 112b62c01b20c2bd25b2f345dade6900f6c86395..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14423 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 CgYs7Z diff --git a/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n100_evenly_spread/k8/trained_ddqn/best_seed_2.pt deleted file mode 100644 index f01590441cae3c2ecb03b0812c290ad4e8dcf233..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14423 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 G{r>={p1HmN diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/optimal.txt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/optimal.txt deleted file mode 100644 index 407ef7dd6..000000000 --- a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -11633 -9246 -10178 -9305 -10486 -9479 -8495 -11441 -12411 -10897 -10585 -11646 -11411 -8899 -11207 -13141 -9702 -10016 -11178 -9770 -8199 -9463 -9692 -9746 -8542 -11895 -12658 -10533 -10385 -10853 -8677 -9146 -7514 -11865 -14460 -9178 -11444 -10123 -8012 -10653 -10262 -11219 -12704 -7679 -11512 -9251 -8055 -9179 -8677 -9982 -10408 -8974 -7391 -7112 -8319 -10778 -7998 -8122 -11356 -10468 -10469 -9942 -11615 -10980 -9493 -10813 -10426 -11645 -10422 -10721 -10669 -11333 -12436 -10381 -10704 -7096 -7173 -10659 -10357 -9424 -9471 -12522 -8655 -9871 -11690 -7793 -8626 -14148 -9627 -10586 -10161 -8888 -14311 -10039 -8809 -10625 -8502 -10667 -7826 -9206 -11422 -10481 -11256 -9544 -10602 -10840 -12691 -9048 -10723 -11482 -8276 -9666 -11037 -12299 -9034 -10831 -10985 -11122 -11634 -10554 -9616 -9884 -11403 -9778 -10328 -11155 -12340 -9860 -11222 -13968 -8366 -8337 -9499 -12331 -9134 -9286 -10088 -13370 -10775 -10953 -8783 -9424 -10325 -9994 -9880 -7705 -10782 -11098 -11083 -10149 -13774 -9299 -8968 -11858 -12138 -11120 -12360 -9117 -9230 -12230 -10088 -14385 -10377 -11380 -11372 -9263 -10723 -11359 -12066 -11278 -9997 -9587 -13187 -12698 -12872 -9461 -9629 -10693 -9959 -8400 -11837 -11600 -10193 -11553 -10499 -10271 -11573 -11651 -11435 -10679 -10166 -7413 -10190 -12299 -12787 -10480 -13822 -8413 -9774 -10781 -10033 -12074 -7253 -9563 -15372 -9136 -9980 -8147 -9132 -10522 -9212 -12558 -10988 -11984 -11286 -11237 -10310 -9994 -8184 -9391 -11418 -9741 -12295 -9449 -10955 -9769 -11214 -10496 -9157 -10886 -11196 -11036 -9758 -9050 -8981 -9592 -10518 -9738 -11285 -10870 -10230 -10751 -7582 -10096 -14513 -14112 -11000 -8757 -10703 -13300 -9258 -7034 -12811 -10846 -11635 -10690 -10296 -11664 -10814 -11888 -8124 -9435 -13009 -8962 -8818 -7484 -13085 -11391 -9819 -12493 -12810 -11266 -10103 -8675 -13997 -10284 -11957 -10773 -9721 -6881 -11495 -9317 -12345 -9979 -11433 -11611 -10878 -11520 -13348 -11253 -12471 -10030 -11478 -8851 -11030 -9038 -8978 -11654 -9879 -8847 -10822 -10346 -9963 -12545 -8521 -11436 -10532 -12167 -13554 -9907 -9842 -10497 -9952 -8550 -7181 -12771 -10234 -9941 -10362 -8058 -11326 -10501 -10642 -11072 -10246 -9503 -11921 -9147 -9791 -10324 -11162 -8142 -9871 -9948 -11735 -8807 -9397 -10658 -9250 -11857 -8579 -11196 -9291 -11199 -9562 -12972 -8124 -11102 -9737 -12693 -10170 -11389 -8643 -8014 -11935 -11213 -13125 -11981 -8902 -7975 -10883 -10992 -9516 -13685 -10436 -10665 -9440 -10914 -11715 -10646 -8879 -10737 -11409 -10576 -9678 -12888 -7660 -14380 -10078 -10160 -10361 -10773 -8640 -11534 -9953 -12458 -9820 -13344 -10460 -12453 -10866 -10043 -10761 -8783 -10040 -10143 -12798 -14334 -10853 -8743 -9782 -10480 -12215 -11245 -9055 -9289 -11292 -9718 -11368 -10884 -11329 -9820 -9917 -11466 -10587 -10195 -10461 -11074 -9850 -10406 -12503 -12795 -9339 -10608 -10039 -13079 -9274 -11541 -11853 -9865 -8161 -10009 -10025 -10191 -8518 -10867 -13417 -8537 -8565 -12795 -9611 -8372 -11778 -9862 -11517 -9565 -8197 -8702 -11280 -11189 -7533 -10157 -11355 -11217 -10563 -11386 -10588 -10042 -7338 -8457 -10389 -10544 -11758 -10092 -10099 -11019 -9719 -7299 -10345 -9416 -10823 -14583 -9724 -10127 -12360 -11200 -9113 -11681 -8505 -9485 -8639 -10238 -13082 -10602 -13009 -9268 -9801 -12683 -8599 -11398 -10058 -7005 -11410 -13329 -11738 -10034 -9961 -9878 -8895 -11027 -8812 -12751 -9630 -11240 -11210 -11442 -8947 -12146 -9946 -11005 -11322 -11727 -11565 -8760 -7859 -12098 -12939 -10973 -11767 -9322 -11622 -12237 -9374 -9209 -12813 -10428 -10752 -12843 -13596 -9476 -12169 -12029 -7221 -10935 -11593 -9471 -9021 -10139 -13887 -9017 -9633 -9811 -9997 -10787 -13295 -10903 -9509 -11534 -9633 -10725 -11383 -13435 -11224 -11788 -9233 -11047 -9170 -12344 -10413 -11170 -10329 -10277 -9840 -10123 -9614 -12142 -9514 -10086 -12287 -8765 -9364 -12514 -10504 -12324 -11133 -12639 -11863 -11128 -10018 -10907 -11982 -11430 -10188 -16164 -11530 -10340 -12593 -10343 -8343 -10819 -9884 -11593 -8217 -7103 -9060 -11020 -14635 -12069 -11297 -10941 -11293 -11326 -12753 -13180 -10603 -8382 -10798 -10783 -11462 -11915 -11192 -8942 -11221 -10909 -10414 -8665 -8071 -11961 -10266 -9541 -10227 -9664 -11597 -13829 -11508 -12712 -11466 -11744 -11819 -11730 -11457 -11162 -12262 -11820 -9218 -10843 -13000 -11727 -9410 -8986 -10308 -13136 -14080 -12743 -10767 -12954 -10259 -8600 -10618 -7704 -9354 -10387 -6960 -12160 -10836 -9784 -11199 -11502 -8337 -8743 -10504 -9376 -8764 -13303 -12622 -9500 -8243 -10783 -10472 -12235 -10958 -7254 -8611 -8828 -12280 -9203 -10875 -10486 -10984 -8423 -14175 -10239 -11684 -12653 -9678 -8069 -10541 -11249 -11731 -12476 -11779 -11172 -9464 -11633 -9095 -12578 -9372 -8802 -9069 -11609 -11947 -12363 -8143 -10325 -10997 -12352 -8666 -9864 -11804 -9495 -10487 -10773 -9684 -8636 -8153 -10179 -11997 -11535 -9894 -9724 -11652 -11794 -10359 -11072 -8578 -11769 -11294 -9246 -9367 -13966 -10250 -11217 -11314 -12002 -9285 -9377 -11397 -11025 -11669 -9309 -10355 -9330 -10593 -12711 -13663 -8081 -11772 -14592 -10516 -12896 -13765 -12883 -10341 -11262 -13051 -8163 -9785 -9804 -8578 -11460 -9817 -11677 -10330 -11373 -8620 -12045 -10316 -13965 -9087 -13921 -8165 -9697 -12662 -11801 -12150 -10801 -10256 -7950 -11071 -11188 -11047 -9742 -11285 -12678 -10543 -9534 -11743 -9915 -10168 -10961 -9146 -10134 -10917 -10822 -10600 -10948 -10456 -9713 -12875 -12155 -11949 -8174 -9331 -11694 -10550 -10020 -11115 -11540 -9346 -10086 -10062 -10915 -10672 -9223 -10458 -9473 -8683 -8046 -9944 -11310 -10594 -10729 -11770 -11030 -10217 -9033 -12592 -9465 -8464 -11024 -13006 -10795 -11251 -10359 -10682 -13010 -10379 -9150 -9282 -12213 -11255 -13287 -9389 -11706 -11665 -9832 -10512 -8636 -12124 -11798 -10583 -9182 -12074 -10959 -9405 -7427 -10956 -7962 -9544 -11889 -10515 -10594 -11304 -10996 -11967 -9345 -11503 -10380 -9895 -10537 -8564 -13460 -12234 -13780 -11097 -11720 -10653 -9016 -10406 -8989 -9462 -9477 -9720 -10150 -12346 -9005 -8989 -9994 -13254 -9384 -10568 -9081 -11314 -10522 -9231 -11470 -12493 -10243 -13099 -11151 -12346 -9938 -11831 -8304 -10025 -8966 -10141 -8865 -11284 -12081 -10467 -9891 -10895 -8963 -10711 -9945 -8357 -10763 -9556 -8477 -10312 -11115 -11495 -14171 -10987 -11568 -12616 -11090 -13262 -7095 -10199 -12816 -9723 -10382 -9220 -9093 -13053 -12462 -8482 -8830 -10941 -11343 -10607 -9602 -10599 -8450 -11386 -11130 -11508 -11668 -11670 -8368 -12013 -9339 -12157 -12782 -6897 -11837 -10473 -9756 -10846 -9389 -10208 -14315 -9306 -8716 -9617 -15658 -13038 -7760 -13176 -11271 -10133 -10661 -10450 -7829 -10208 -10758 -10537 -11862 -9221 -12035 -12778 -9985 -12911 -11012 -9855 -12394 -10299 -12195 -11055 -10296 -10732 -10479 -10657 -10139 -8759 -11107 -9498 -11754 -10966 -13150 -14414 -10987 -8357 -9764 -10824 -15569 -10668 -8316 -10010 -9411 -8099 -9975 -9100 -11672 -11200 -10167 -9725 -11817 -10930 -12001 -7923 -10912 -11885 -10112 -9736 -8553 -10461 -11737 -9477 -11276 -8304 -10322 -13123 -12160 -10180 -12228 -12852 -9384 -8597 -10301 -9172 -10324 -14546 -9770 -10901 -10252 -8566 -11490 -10147 -10737 -10415 -9770 -9387 -8828 -11316 -8181 -9280 -9817 -10497 -11537 -10417 -11746 -10285 -10617 -11436 -9600 -9998 -9542 -9047 -7462 -8554 -10855 -8621 -10899 -10253 -11684 -10491 -9200 -11922 -11834 -11528 -10170 -8848 -13578 -10459 -9631 -10836 -13614 -10844 -13272 -11704 -7782 -8723 -7747 -10115 -9667 -12506 -10657 -9720 -10547 -11135 -9260 -12554 -10179 -11551 -15297 -11544 -11509 -10495 -9135 -11490 -11357 -12105 -9811 -7756 -11521 -9722 -11906 -11046 -9671 -9220 -13441 -10470 -9002 -12264 -9924 -9158 -10313 -13161 -11511 -8693 -11567 -11867 -10414 -12197 -13453 -11623 -10361 -10426 -13869 -9306 -9304 -12927 -11460 -10321 -11797 -11973 -11885 -11681 -10452 -10047 -10804 -11521 -12701 -16120 -8526 -11442 -11306 -11152 -9838 -14314 -13411 -10114 -11126 -9942 -10527 -10903 -12582 -10740 -10018 -10946 -11576 -12058 -9888 -13877 -12059 -13500 -11843 -11723 -10060 -10452 -11838 -11619 -9630 -11680 -12030 -10598 -9128 -11837 -10857 -8659 -8997 -8620 -12870 -10692 -9350 -10704 -9456 -9846 -8734 -8176 -14990 -10622 -9027 -9348 -10383 -9277 -14956 -10179 -9451 -11823 -11140 -11688 -11955 -11070 -7712 -11126 -12416 -9990 -10284 -9494 -8859 -8990 -10314 -8976 -9890 -12372 -12134 -10802 -12034 -8484 -10604 -9885 -8066 -10966 -11029 -11826 -10105 -9594 -10432 -10643 -10577 -9947 -11098 -8081 -11298 -10627 -12713 -11114 -10703 -9365 -7687 -10583 -9904 -9592 -10089 -10278 -11282 -9832 -12045 -10790 -12981 -11776 -13621 -9536 -11502 -10959 -9636 -10822 -9691 -9795 -13018 -7592 -9801 -10325 -12240 -8096 -9754 -10283 -8777 -11873 -11577 -8669 -11449 -10805 -7817 -9277 -13153 -9338 -11410 -11120 -11788 -11261 -11103 -7633 -11138 -10234 -10441 -10812 -9730 -8989 -13069 -12065 -9189 -8615 -7901 -12400 -10578 -12271 -15701 -10360 -8881 -11044 -9885 -10166 -9836 -12803 -12470 -7209 -13155 -9937 -12134 -12640 -11579 -10228 -10533 -10726 -12398 -11854 -8839 -10592 -15327 -11035 -12531 -11644 -9380 -11192 -12585 -9579 -10884 -12099 -12303 -10208 -10446 -12085 -9300 -9832 -10389 -10164 -14104 -9695 -11972 -11490 -12750 -13747 -9897 -9933 -9532 -9939 -11157 -9490 -10945 -10777 -10567 -11820 -8274 -9847 -10344 -11982 -10575 -10771 -10585 -9688 -8095 -10799 -8473 -13933 -7638 -9637 -10631 -13352 -10550 -9003 -10598 -10334 -8923 -9084 -9339 -12248 -10207 -13904 -10748 -8997 -11750 -10780 -12846 -10026 -11230 -8377 -8893 -8258 -11013 -10914 -12244 -9188 -9649 -10726 -8506 -14076 -9185 -7395 -9630 -10609 -7962 -8497 -9647 -9837 -13535 -9322 -11102 -10959 -10636 -9714 -11374 -12918 -11626 -11574 -9331 -12752 -9761 -10637 -11523 -11406 -11605 -9601 -11139 -11150 -13011 -11116 -11324 -10725 -9008 -9533 -11971 -7320 -12846 -8176 -10631 -10160 -10930 -8421 -10174 -11177 -11042 -12306 -10329 -11511 -11624 -13644 -9787 -10858 -10337 -11783 -10625 -11263 -6757 -10689 -12390 -11660 -11471 -11268 -11421 -7304 -9910 -10077 -10516 -11151 -11252 -7938 -10258 -10966 -10630 -9910 -9315 -11426 -12437 -10698 -10427 -12665 -11282 -9774 -9910 -8950 -8310 -11106 -9647 -11283 -10759 -11168 -7828 -11437 -8447 -9174 -8762 -12336 -12661 -10125 -11761 -13085 -9695 -10626 -9968 -8215 -9743 -12192 -9549 -12477 -12092 -9779 -12714 -8363 -11107 -7983 -13130 -11510 -11046 -12588 -12103 -9673 -5974 -10359 -10814 -12795 -8446 -9394 -10291 -7537 -11002 -12110 -13438 -11839 -10777 -9555 -10851 -8936 -11785 -10527 -10462 -8983 -7691 -9462 -9351 -9450 -11541 -9111 -11022 -9912 -10174 -9286 -8891 -10164 -11494 -10522 -11804 -12427 -12370 -12571 -9841 -12040 -12109 -11186 -12351 -10616 -11562 -11617 -11454 -14583 -9186 -10000 -9522 -9061 -9846 -8682 -13341 -8592 -9750 -9315 -15145 -10145 -8648 -10219 -8537 -10947 -9989 -10756 -13041 -10286 -9934 -11336 -13327 -12869 -14129 -9007 -10976 -9717 -12007 -8709 -13431 -12135 -11149 -11857 -10434 -9606 -9037 -10274 -14488 -12870 -7680 -11442 -8837 -9856 -9591 -11998 -9254 -10662 -12683 -11361 -8481 -9819 -12301 -11804 -9023 -10491 -11744 -11850 -12277 -12910 -10836 -12474 -10240 -9671 -11791 -11034 -11355 -8055 -8340 -11301 -9905 -10769 -10060 -9583 -13913 -13359 -11925 -9366 -9855 -11228 -10653 -11064 -10052 -13558 -9337 -11269 -11880 -10760 -12162 -9733 -11419 -10168 -12793 -10162 -11099 -11189 -10548 -11874 -8880 -10379 -12036 -12033 -11015 -8798 -7161 -9709 -12381 -9968 -12574 -10670 -12512 -11349 -13087 -9966 -10989 -11446 -9434 -11534 -10519 -8765 -9362 -8478 -10558 -10565 -12066 -11619 -7909 -11802 -13072 -10502 -11228 -10055 -10125 -11377 -13779 -12633 -11317 -10390 -10141 -11501 -11031 -12978 -12104 -9450 -11461 -12285 -10695 -10645 -12730 -9483 -10087 -10705 -11842 -10964 -9403 -8951 -11265 -9624 -13996 -9423 -10062 -12097 -11668 -10883 -13852 -7501 -10697 -9856 -12001 -12471 -10479 -12579 -11559 -8972 -11830 -11696 -10688 -11078 -10687 -7733 -10550 -10366 -11533 -10091 -11137 -9466 -8123 -11809 -13582 -9310 -11768 -10284 -9993 -9689 -12189 -9314 -8351 -10900 -10601 -12033 -10774 -9913 -14659 -11297 -9273 -10312 -10253 -10721 -9384 -8946 -11440 -11219 -9267 -9513 -7268 -12303 -10646 -8833 -10039 -8399 -8890 -9884 -8966 -11130 -12865 -12005 -9206 -11429 -11977 -12021 -11992 -10937 -8996 -10753 -9349 -9620 -10419 -8441 -10843 -12808 -9163 -12376 -9796 -9864 -11003 -10248 -10465 -10359 -9272 -11456 -10266 -10628 -9437 -11461 -9346 -9485 -12053 -11473 -10834 -10470 -8247 -8447 -11585 -10032 -11459 -10975 -9731 -8819 -9748 -9830 -12199 -8731 -9315 -9591 -11850 -11667 -12967 -10519 -9180 -12547 -7538 -9355 -9294 -10930 -12822 -11448 -9568 -8950 -9010 -9338 -9092 -12956 -9684 -14201 -12581 -9705 -13097 -8931 -10791 -7474 -12049 -15317 -11261 -11576 -9513 -10182 -8879 -9311 -11255 -11296 -7502 -12855 -10568 -8201 -9066 -8864 -6853 -8965 -14412 -11955 -10040 -12427 -12030 -9525 -9760 -9398 -11189 -9764 -10432 -10489 -14008 -10471 -9922 -10056 -8051 -10023 -8519 -10000 -10120 -9396 -13529 -11388 -11905 -11072 -10547 -10493 -9015 -9730 -11598 -9627 -12725 -11700 -11602 -9101 -11960 -11867 -12423 -13470 -9167 -10782 -11024 -9331 -11901 -7777 -11764 -11691 -12185 -9455 -12685 -12102 -10265 -12598 -9249 -9572 -11634 -11685 -14352 -11395 -8620 -14962 -10620 -12231 -10801 -12196 -9529 -10334 -12348 -13792 -11101 -8991 -12401 -10389 -11840 -11230 -11482 -9778 -10554 -10149 -9763 -9038 -11236 -9871 -11125 -9633 -10341 -9372 -8341 -10416 -9470 -10080 -8577 -8643 -11466 -12558 -11493 -11691 -10174 -10182 -9137 -9801 -10502 diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/trained_ddqn/best_seed_0.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k3/trained_ddqn/best_seed_0.pt deleted file mode 100644 index aa58d549ac8f3ca362bfb88c017262a89ba60055..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13463 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 Y41PcV`rFc6RP5K21poJ|{qMH_2e1RlD*ylh diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/optimal.txt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/optimal.txt deleted file mode 100644 index 5c75625f4..000000000 --- a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -10476 -11960 -10664 -9093 -10895 -8675 -10423 -10981 -10115 -11553 -11718 -10597 -8008 -10865 -11110 -12019 -10255 -11499 -12163 -10404 -9765 -9369 -7244 -9170 -10505 -9714 -10789 -9264 -9433 -10139 -10443 -12428 -10083 -12274 -12682 -9946 -9637 -10439 -11314 -8815 -8767 -10129 -12201 -8136 -10182 -10639 -12948 -10881 -10188 -10601 -11394 -9291 -9874 -12066 -10654 -9698 -10040 -9467 -9995 -10091 -10126 -12597 -8158 -11853 -9958 -8915 -9825 -11441 -10063 -10840 -9384 -10529 -10947 -10595 -13646 -7530 -8778 -8844 -9177 -14332 -9029 -9897 -9339 -11052 -8235 -13927 -9692 -9459 -10173 -13085 -13526 -11865 -9422 -11243 -10312 -11162 -12300 -8591 -8441 -13433 -11541 -10105 -11705 -7799 -11026 -11821 -9421 -8248 -12616 -10359 -9898 -8312 -9678 -10914 -10915 -11328 -12682 -12238 -10364 -13473 -11856 -7331 -13159 -11566 -7520 -7532 -11679 -10144 -12377 -9112 -10879 -10448 -13328 -8143 -8938 -9643 -10567 -10466 -10923 -9279 -9978 -9716 -13714 -11199 -10779 -9778 -11861 -10905 -12634 -9309 -11594 -10855 -9864 -12206 -9557 -8022 -9064 -8612 -11472 -10723 -12165 -13150 -12791 -8940 -12571 -8723 -12803 -12005 -9243 -10404 -10241 -10891 -10185 -11269 -10554 -9853 -10079 -11613 -11892 -9556 -7798 -10164 -8788 -11089 -10677 -10561 -12339 -12067 -14883 -11004 -10487 -10565 -8870 -10033 -12109 -8063 -8288 -10559 -9116 -8706 -8466 -8316 -11972 -12514 -9318 -10484 -7270 -10407 -7829 -9371 -9249 -11991 -10065 -7695 -9288 -10595 -10362 -11713 -10751 -8902 -9630 -8338 -12278 -11959 -10188 -12087 -10693 -11107 -11588 -9016 -10070 -10185 -10484 -8248 -10785 -8707 -9988 -10872 -13146 -9398 -11757 -11495 -11127 -12081 -10112 -12007 -10499 -12432 -11531 -9873 -9652 -10751 -10615 -9226 -10975 -10461 -8773 -10857 -9671 -16024 -11240 -9824 -9663 -10090 -9846 -12464 -9240 -9278 -8743 -7683 -10644 -7392 -11523 -10555 -10323 -9642 -12289 -11974 -10774 -11000 -9399 -11813 -8908 -9701 -9402 -9370 -9031 -10275 -10254 -11122 -10184 -9281 -9560 -10457 -12095 -12112 -8398 -9752 -10260 -11480 -9166 -10189 -9849 -11196 -11331 -11802 -12593 -11679 -10498 -11065 -9791 -10017 -13132 -11060 -10434 -10126 -8768 -12496 -12349 -8328 -8028 -11695 -8596 -12545 -12509 -9459 -9557 -11396 -13282 -10804 -10332 -10487 -12041 -8810 -9821 -12601 -10308 -10464 -8331 -10746 -10323 -9453 -12822 -10064 -11610 -8750 -8812 -10018 -10062 -13467 -10857 -10759 -8841 -11787 -9476 -13599 -8313 -11326 -10178 -12086 -10498 -8947 -12673 -10783 -10720 -8078 -10911 -9940 -9074 -11121 -10591 -9732 -9681 -9276 -10719 -10266 -10931 -9356 -12511 -10520 -10570 -10449 -11277 -8898 -9459 -11197 -11896 -9545 -8522 -9643 -12333 -10766 -10589 -10527 -8950 -10055 -10281 -11128 -11500 -8254 -10407 -11814 -10850 -10080 -10068 -8960 -11150 -11277 -10214 -11731 -11310 -9524 -12950 -10973 -11340 -10236 -12009 -12067 -8913 -12496 -11906 -11249 -11477 -11078 -8726 -11949 -12627 -11105 -10406 -9331 -9120 -9020 -11998 -8343 -10399 -8206 -10986 -12821 -9683 -10765 -8056 -7809 -8902 -10256 -10085 -11861 -10510 -10400 -10958 -11251 -13322 -8412 -8963 -13269 -7569 -10337 -11597 -10447 -12532 -11177 -11550 -10264 -11296 -9759 -13618 -10839 -9733 -11818 -13307 -11085 -9958 -7615 -10853 -13489 -7618 -14343 -9938 -10952 -13118 -12747 -11327 -11427 -10043 -13200 -12188 -13170 -10465 -11373 -6989 -8706 -11895 -10738 -12528 -11494 -9669 -9828 -8954 -11540 -10673 -8974 -10702 -10462 -7431 -11770 -12180 -12835 -9033 -12280 -8078 -10888 -8677 -11131 -10967 -12544 -10179 -7626 -10305 -10697 -12637 -9119 -11005 -7920 -8266 -7951 -13168 -10758 -8581 -13658 -9350 -8622 -9842 -12737 -12362 -12731 -11532 -12586 -10629 -9227 -12388 -9568 -9206 -8534 -10060 -8335 -9886 -11571 -9393 -9872 -10689 -13351 -15541 -14295 -8564 -13500 -10097 -13383 -10596 -13696 -9979 -9560 -8156 -11372 -11285 -11118 -9643 -10261 -11168 -11836 -9907 -9548 -11753 -12879 -10726 -7809 -10670 -9937 -10305 -12159 -10398 -10224 -9271 -9551 -8953 -9791 -12469 -8899 -8354 -10661 -10078 -12850 -9476 -10436 -14640 -10706 -9580 -11349 -9667 -11947 -9158 -7288 -9344 -8906 -9217 -10220 -9907 -8875 -10720 -11827 -8467 -8463 -10136 -9324 -10405 -10743 -6760 -10316 -11625 -10084 -13291 -10511 -7685 -10909 -9142 -11222 -9201 -10405 -10617 -7777 -11896 -10355 -10718 -11947 -10801 -9305 -11401 -11324 -10099 -10310 -10028 -7913 -11331 -8559 -12577 -10241 -8101 -8714 -8711 -9710 -12818 -13646 -9491 -7433 -10521 -9415 -8648 -11100 -9297 -10062 -10918 -9012 -12256 -8155 -9652 -8930 -12844 -9315 -11078 -11342 -8704 -9913 -10235 -10915 -9259 -14857 -9636 -10929 -9394 -12218 -10742 -11475 -9582 -10510 -10250 -11539 -8291 -7265 -10711 -8928 -10241 -11545 -8486 -9804 -9909 -8721 -11331 -9223 -11276 -9700 -11376 -9993 -9784 -9780 -10613 -11292 -11953 -10164 -8785 -8490 -10595 -9400 -7655 -7701 -10493 -8838 -10813 -10404 -13458 -9102 -9122 -7978 -8237 -9009 -10305 -13445 -8172 -12011 -12481 -12764 -7806 -12946 -9674 -9724 -9940 -10693 -8566 -9018 -9246 -10996 -10689 -11511 -9878 -11307 -12092 -7831 -11524 -9582 -9772 -9785 -8583 -10359 -10512 -10575 -10456 -12663 -10434 -14717 -12894 -10355 -7569 -9494 -10919 -9988 -10953 -10968 -8057 -9663 -11062 -13728 -11933 -10033 -8659 -11207 -9382 -11065 -7630 -11905 -11836 -10412 -11643 -12650 -10508 -12230 -9820 -10030 -10205 -14037 -11156 -12943 -9751 -9372 -9167 -10955 -9420 -9262 -10576 -11911 -9015 -10994 -12222 -9695 -11532 -11123 -12172 -8024 -9703 -10888 -9098 -11515 -13027 -11044 -11671 -11142 -8688 -10860 -11661 -10414 -10833 -9382 -10785 -8900 -9581 -8593 -9169 -11778 -8265 -11627 -11686 -10056 -13427 -11372 -11221 -12365 -11467 -8301 -8233 -10877 -10503 -9125 -10828 -9139 -9923 -12843 -10669 -8791 -11183 -10769 -13148 -11100 -10474 -11934 -9418 -11024 -10022 -8572 -11602 -9270 -9799 -10845 -12572 -9075 -11884 -10471 -12460 -10159 -11760 -8258 -11211 -10056 -12946 -11534 -11936 -12449 -10822 -11675 -11619 -11405 -13898 -13143 -10171 -12618 -11379 -10471 -12013 -9271 -10191 -12201 -10994 -9147 -11662 -9592 -8541 -11496 -10261 -9765 -8884 -7740 -10649 -11445 -10296 -10397 -14314 -9377 -11318 -9709 -10122 -9796 -11902 -12822 -10162 -10979 -10126 -10056 -10914 -12169 -12291 -11246 -12482 -9931 -9153 -6789 -10359 -6735 -9487 -9676 -11679 -9659 -10634 -9319 -11653 -14241 -10593 -11117 -13329 -11711 -10713 -9466 -9757 -9928 -8908 -9378 -8243 -11107 -10378 -11726 -9628 -12140 -10408 -9922 -12129 -11032 -10172 -9793 -8301 -12964 -10402 -10840 -12081 -7904 -13158 -9730 -13330 -11089 -9708 -11844 -9192 -11181 -11096 -11941 -9402 -11446 -10219 -10576 -11029 -11132 -12437 -10543 -10408 -9839 -8831 -11369 -9415 -12379 -10645 -11062 -10967 -13639 -9773 -13324 -11562 -7931 -10439 -13176 -9969 -9191 -10601 -10224 -7048 -11420 -8753 -11339 -9959 -8267 -10646 -10177 -11366 -11579 -9354 -10553 -9971 -11414 -11906 -11436 -10011 -9923 -11959 -12637 -9706 -9487 -10286 -11719 -13271 -9718 -9970 -11678 -8227 -8857 -13552 -8649 -10454 -11617 -12426 -13432 -9614 -10756 -12664 -8011 -10519 -10655 -10076 -12426 -9449 -10622 -11793 -12279 -8723 -11172 -9121 -8263 -10702 -8622 -10176 -10640 -9178 -8678 -11273 -11785 -7680 -11607 -12432 -10308 -8782 -10515 -12056 -11341 -11728 -8881 -10427 -10113 -10618 -10736 -7750 -9397 -12007 -11859 -10598 -11450 -10777 -11424 -11615 -10973 -11473 -9080 -10664 -11259 -10966 -9145 -11160 -12855 -10185 -8930 -9636 -8846 -9113 -10920 -9407 -11489 -10068 -8850 -9706 -12047 -14017 -10803 -7722 -9579 -9325 -12014 -11759 -9602 -10725 -11965 -11638 -10997 -8855 -8265 -12228 -10942 -10542 -8663 -8208 -10971 -7966 -12411 -10966 -12744 -7173 -9852 -9723 -12085 -10625 -10961 -9332 -8569 -9821 -11514 -11700 -9638 -11687 -8571 -9723 -9896 -11002 -9326 -11084 -7690 -9723 -12254 -11328 -10050 -10035 -11574 -11116 -11999 -11651 -11709 -7785 -11181 -10003 -9683 -10535 -10482 -10007 -10161 -10855 -11707 -11299 -11440 -13003 -10089 -10539 -11768 -15892 -11809 -11762 -8006 -9777 -9265 -7354 -9909 -13070 -12602 -11031 -9945 -8720 -7311 -9920 -8855 -10427 -11103 -7904 -8990 -9231 -10485 -11105 -9900 -10784 -11549 -8383 -9753 -11470 -9291 -11894 -10146 -10578 -11670 -9729 -11296 -13302 -8499 -11701 -9565 -11429 -10668 -11528 -10781 -12785 -8726 -10868 -9307 -8430 -10454 -12402 -10010 -12666 -11670 -7680 -11805 -7198 -12748 -11058 -11681 -13308 -9380 -6669 -11310 -10861 -9289 -7878 -9376 -9606 -10274 -8137 -10626 -10277 -10090 -11460 -10196 -9227 -9874 -10234 -11338 -10308 -10494 -10904 -10086 -11754 -8816 -9905 -10482 -9192 -11013 -10254 -10374 -9416 -8763 -8547 -12080 -9464 -8779 -12912 -11973 -10791 -9064 -10514 -12036 -10543 -9485 -12238 -13152 -10518 -12073 -8579 -13100 -11175 -12062 -11636 -10116 -10332 -8735 -14116 -8583 -9478 -8991 -13021 -8956 -9978 -13927 -8499 -10737 -11651 -12151 -9303 -11664 -11318 -12319 -11357 -11925 -8589 -10222 -6709 -12141 -8162 -8701 -9617 -9288 -8818 -11147 -9186 -10058 -11620 -10161 -9435 -9101 -8056 -9340 -10264 -10203 -10179 -8766 -10540 -10107 -11586 -9854 -10828 -10146 -7884 -11430 -9249 -10581 -8455 -8949 -9548 -9013 -9602 -12644 -7275 -10577 -9372 -13051 -8490 -10424 -8441 -9671 -13189 -7104 -10087 -12939 -10454 -11555 -8301 -8097 -10735 -12014 -12451 -10684 -11478 -10622 -10872 -10495 -13494 -9931 -12221 -11050 -11680 -11539 -12432 -10553 -9047 -9470 -8540 -10623 -13359 -7755 -11565 -10098 -11974 -10310 -10890 -8929 -8630 -10882 -12564 -10051 -11718 -11685 -10730 -10655 -10292 -10925 -10441 -11182 -8353 -10183 -10086 -10212 -11281 -8982 -8745 -9477 -10281 -12067 -11182 -10056 -11469 -10178 -11206 -6479 -9646 -10859 -9318 -10925 -10233 -9549 -11902 -9032 -10922 -12192 -11466 -10412 -8067 -12711 -10368 -10157 -12203 -9775 -9573 -10994 -11069 -11074 -7888 -8801 -9244 -9487 -8531 -10922 -10444 -11609 -10780 -10512 -10410 -10104 -12813 -11583 -10301 -11676 -9247 -9052 -12521 -11087 -11593 -11745 -11780 -7910 -12905 -10363 -11496 -12934 -8222 -11309 -11171 -11290 -9246 -8592 -10571 -12965 -11032 -9107 -10064 -11135 -8845 -14532 -10106 -8637 -12488 -8289 -11756 -13291 -11673 -12879 -10125 -8922 -11227 -14103 -12192 -12424 -11544 -10979 -10223 -9334 -13675 -7809 -14177 -13118 -9693 -10052 -12731 -10726 -11189 -10413 -11179 -9610 -9794 -11427 -13057 -9504 -10995 -11368 -12954 -11300 -8921 -10799 -11259 -10839 -9917 -11711 -10865 -12115 -8473 -13294 -10782 -11602 -13260 -8536 -9429 -10327 -10700 -11300 -10533 -10181 -10631 -7173 -8228 -10753 -11560 -13277 -10686 -8527 -8957 -10549 -11893 -8257 -8321 -9612 -8706 -11927 -13212 -10436 -8453 -8566 -11043 -10980 -10833 -11385 -9247 -7690 -9142 -9999 -11064 -10601 -9001 -7905 -10930 -10683 -8739 -9323 -11614 -11633 -11626 -10353 -11479 -9347 -9302 -9549 -9689 -10602 -9821 -8603 -11118 -13635 -15683 -9111 -10633 -10451 -9983 -9784 -10723 -10073 -10812 -10195 -12824 -10710 -9181 -11646 -12300 -11135 -11673 -10591 -9674 -9237 -12604 -6407 -10034 -9627 -9631 -10936 -10455 -10790 -10061 -10225 -11351 -10011 -8903 -10180 -8591 -11590 -8816 -11271 -9731 -10395 -9086 -11997 -10259 -8932 -9007 -9852 -9178 -10701 -10897 -9172 -10251 -11239 -11513 -9329 -10755 -11560 -8703 -10535 -9254 -13288 -9893 -12220 -10614 -14752 -9471 -10292 -12845 -11485 -10518 -13211 -12031 -9116 -9783 -11117 -7643 -9925 -9888 -8115 -10035 -12290 -12782 -11391 -9518 -9017 -9646 -13437 -9232 -11181 -13245 -10169 -10390 -9665 -11334 -9692 -10909 -10943 -8752 -11076 -10005 -12001 -9218 -8973 -10366 -12211 -10945 -10080 -10952 -9445 -10470 -9515 -11516 -8892 -12045 -9221 -10909 -9093 -11038 -10661 -11541 -11806 -11453 -10131 -10377 -10530 -9060 -8679 -9580 -10981 -7753 -9788 -9337 -8992 -9659 -11899 -10203 -9260 -9834 -7315 -9030 -8626 -10506 -11607 -8982 -9487 -12047 -8972 -10161 -9605 -8983 -9895 -12430 -12908 -10906 -12092 -8030 -13131 -10982 -10020 -11817 -10861 -10633 -11097 -10440 -11268 -11859 -11422 -11571 -9575 -10040 -13276 -10531 -12760 -12248 -10881 -10552 -10810 -10489 -9518 -9634 -11716 -11116 -11364 -8450 -9544 -12088 -12128 -12165 -7895 -10456 -10569 -11342 -12534 -8687 -10296 -10901 -10842 -11397 -10283 -12451 -10471 -10635 -12258 -13363 -12075 -11848 -14529 -11359 -7500 -10567 -10629 -9312 -8727 -9675 -9654 -9184 -10256 -12795 -9212 -12890 -9676 -10603 -9877 -9590 -11410 -10839 -10622 -13307 -10449 -7614 -9521 -11277 -9418 -12635 -12151 -10062 -11545 -10948 -11661 -12040 -8305 -10021 -12427 -11216 -10040 -15744 -7771 -8951 -9678 -11635 -11734 -8700 -12902 -9765 -12357 -12351 -8518 -9871 -11902 -8923 -12412 -10609 -10619 -14716 -10806 -11879 -10803 -12292 -7090 -9802 -9908 -11907 -10096 -8579 -8639 -9988 -10366 -10993 -6156 -10553 -8920 -11485 -9528 -11138 -9156 -11072 -9001 -13234 -12551 -11735 -10475 -15007 -10019 -10599 -9183 -9832 -8025 -10242 -9216 -12177 -10011 -9665 -11371 -9005 -8966 -9326 -11284 -11233 -9974 -8184 -7526 -9792 -11674 -10973 -10677 -10302 -8897 -12035 -13698 -12846 -7898 -11202 -10655 -9158 -9559 -9954 -10931 -10816 -12457 -9575 -9902 -8955 -10944 -10911 -9616 -9736 -9993 -12985 -12127 -7619 -12052 -13878 -12003 -12782 -11970 -11340 -11940 -12129 -7930 -9744 -12832 -11060 -12397 -11267 -9501 -9379 -10600 -8549 -9931 -12588 -10019 -10554 -9223 -9744 -11777 -11663 -12170 -12517 -10331 -7306 -10864 -7517 -8856 -9509 -8502 -10724 -10977 -11555 -10689 -12676 -9064 -10556 -9547 -12034 -9845 -10802 -10902 -10583 -11757 -10161 -9087 -10522 -9086 -8959 -7873 -11266 -9482 -6674 -9098 -9826 -9947 -10874 -11777 -11413 -12329 -9879 -9289 -11497 -11362 -10982 -12301 -9656 -9628 diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_0.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_0.pt deleted file mode 100644 index 82ad90f2c5f8837fdb46aea5aecefb6e53346a34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 RDk=5rOGfzjtNdSO{}%!-a~A*r diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_1.pt deleted file mode 100644 index 0d4bf00e55d02b154f7a1c44c3fbc74ebf67aeab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 F{{uKqlOO;9 diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k4/trained_ddqn/best_seed_2.pt deleted file mode 100644 index 6368d8baf0b3e148295140f6adb726b131d81594..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 L{(iOpv+e%@t=$(y diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/optimal.txt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/optimal.txt deleted file mode 100644 index 97079847d..000000000 --- a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -9298 -12611 -13141 -6824 -12301 -9145 -11111 -11775 -11624 -10479 -11781 -11512 -11143 -7729 -11630 -9198 -10444 -13070 -10691 -10691 -10176 -10882 -10210 -12551 -7118 -9134 -12669 -8788 -10131 -11334 -11921 -10425 -9948 -11164 -8716 -12934 -10837 -8181 -11755 -9149 -9875 -11494 -9924 -11068 -8884 -13590 -9450 -12034 -8241 -10256 -13671 -10951 -10997 -9320 -10855 -8734 -11756 -11223 -10760 -9175 -12187 -12802 -10086 -10695 -11442 -10527 -7945 -8109 -7695 -12037 -10682 -8953 -12896 -10247 -10563 -12452 -9410 -9153 -9133 -9496 -7328 -9658 -11654 -10872 -14236 -10674 -12549 -11206 -10677 -13530 -10935 -9368 -10648 -9444 -9473 -12104 -10515 -7858 -9526 -9047 -10711 -14560 -8818 -9902 -11033 -9604 -10055 -9782 -7876 -10601 -9146 -10274 -11336 -10382 -11133 -11163 -11395 -10265 -9551 -10965 -7305 -13876 -10167 -10629 -9199 -11089 -9493 -8528 -7827 -11066 -10126 -10989 -8301 -13148 -13765 -9680 -10992 -12416 -12992 -8615 -10111 -10260 -9710 -10588 -10315 -11380 -9029 -12484 -10134 -9320 -7785 -9739 -8204 -11408 -11875 -11334 -9586 -6553 -8102 -13582 -9846 -11455 -11877 -9935 -9702 -12706 -11595 -9300 -12157 -13649 -10419 -10597 -12167 -9965 -10737 -12870 -9940 -11757 -9912 -9357 -10914 -10167 -9381 -10816 -10485 -11683 -12370 -12183 -7599 -8406 -9339 -11389 -11652 -13552 -8686 -9347 -8807 -9208 -11017 -9257 -10999 -8726 -8432 -11097 -10029 -10351 -11454 -10328 -8445 -8434 -9324 -10796 -10951 -8423 -11333 -10662 -10718 -11522 -11400 -10831 -10695 -8662 -8007 -11286 -10400 -10538 -10420 -9399 -12142 -9447 -8907 -12713 -9088 -10045 -9498 -8201 -11648 -12569 -10645 -11497 -12460 -11282 -9746 -12032 -8955 -9782 -8360 -11016 -10840 -7850 -11163 -10601 -10312 -10667 -9790 -10137 -7224 -11062 -10500 -9553 -9356 -12172 -11860 -9603 -11340 -8738 -10623 -9715 -9429 -12760 -9696 -12593 -9671 -10353 -12679 -11179 -9440 -10536 -10515 -8209 -6539 -9290 -12588 -11279 -13864 -10929 -12169 -10082 -11619 -9735 -10894 -13570 -11751 -10857 -9524 -8170 -7531 -10080 -11646 -10432 -10863 -10176 -13312 -10118 -9875 -11103 -8463 -13281 -9580 -10279 -8794 -8997 -8791 -11909 -12781 -7720 -12351 -8928 -9430 -9373 -10613 -10023 -10593 -9641 -8935 -12749 -8129 -9500 -12159 -10606 -12442 -7514 -9221 -12340 -9635 -11213 -10655 -11559 -12882 -10745 -9758 -10608 -8039 -12546 -10274 -8963 -8200 -14266 -9776 -9860 -12068 -9402 -9118 -10303 -14031 -10041 -9046 -11217 -7713 -11797 -10769 -10152 -7247 -13581 -9328 -9733 -9294 -9458 -11439 -8650 -11034 -11413 -10948 -10822 -10032 -14446 -7295 -14032 -9480 -10689 -11716 -10630 -10062 -10561 -11629 -9617 -9940 -9730 -10745 -7320 -10412 -9058 -8742 -13363 -14358 -10849 -12473 -11968 -8820 -9822 -11174 -7903 -10442 -11453 -11884 -12180 -10624 -10450 -9365 -9999 -10711 -9308 -8072 -10088 -10541 -12087 -10621 -9870 -10248 -10402 -10373 -7978 -10192 -12697 -9220 -6996 -11599 -12685 -11219 -12204 -8781 -9245 -9208 -10168 -8311 -10284 -13440 -8495 -9499 -10322 -9001 -8264 -9941 -8795 -9438 -10393 -10598 -14807 -10299 -11038 -11702 -10650 -10515 -13177 -8676 -8137 -10203 -12391 -11468 -9068 -9164 -12133 -7984 -7767 -8423 -13397 -11685 -11874 -10270 -10566 -9458 -8692 -11802 -10613 -9188 -11115 -10535 -10975 -10902 -10433 -9347 -10449 -11771 -7869 -8079 -13840 -11903 -11428 -10811 -10551 -12630 -11019 -10828 -9685 -10708 -12265 -12301 -11635 -8510 -8287 -10390 -10578 -9580 -11873 -12636 -10018 -10008 -10797 -8145 -10746 -11950 -11233 -9453 -8877 -10697 -9299 -10813 -6892 -10933 -10294 -10096 -11335 -10019 -8847 -10195 -13738 -12526 -11428 -11263 -7974 -10994 -10408 -12111 -8448 -11088 -11764 -7640 -10351 -11637 -12890 -7897 -12155 -15216 -11598 -10555 -12013 -9390 -12353 -10500 -11015 -11616 -10616 -10781 -11806 -9078 -11240 -10127 -11579 -10930 -11787 -10548 -10711 -10879 -9702 -12734 -9488 -12087 -10927 -9299 -9823 -9103 -9391 -11044 -11553 -9052 -10233 -12123 -8900 -8676 -8983 -13409 -11104 -10653 -10734 -11956 -11430 -9348 -10602 -12607 -8527 -9357 -9325 -8829 -12167 -10592 -8817 -12238 -12482 -9369 -9595 -11598 -8829 -10114 -10326 -10055 -9495 -11280 -9531 -8024 -12499 -11645 -12760 -12028 -9129 -8835 -10861 -10374 -9423 -10451 -8124 -12171 -10752 -10780 -9438 -12560 -8688 -9266 -11115 -9967 -9101 -9814 -10625 -8266 -6569 -11542 -9443 -9650 -11123 -9790 -10004 -9836 -9008 -7737 -9648 -9722 -11280 -9895 -10815 -9339 -13150 -11260 -9787 -11210 -10849 -9350 -8017 -11633 -10842 -11448 -10976 -8964 -10282 -9623 -11016 -9288 -10328 -10574 -12270 -9587 -8608 -12704 -10085 -10068 -11966 -9968 -10835 -9758 -9884 -9427 -11819 -11581 -10309 -12198 -11303 -9506 -10684 -10172 -8585 -10347 -10345 -7954 -8539 -11860 -11323 -11094 -11545 -9763 -11848 -9770 -10191 -9294 -9389 -8694 -10716 -13456 -10073 -9092 -11962 -14007 -11612 -10227 -10570 -9831 -11698 -10429 -9491 -9303 -9795 -8593 -9434 -11268 -10239 -10849 -9273 -10515 -10879 -9123 -9718 -8386 -11730 -9701 -14848 -11971 -10659 -8480 -10420 -11655 -11300 -9293 -11337 -12102 -9714 -9554 -13619 -8797 -14010 -11805 -9230 -11456 -10195 -9255 -9055 -8649 -12197 -12784 -8638 -11486 -8436 -9735 -9333 -9368 -13649 -11481 -12116 -11071 -12051 -9459 -7481 -8625 -10663 -8747 -10011 -9074 -10199 -11383 -10852 -15547 -9427 -8998 -10139 -6892 -10934 -9646 -11457 -11323 -8750 -11238 -14125 -9899 -11531 -12409 -7997 -12698 -11582 -7828 -11026 -9063 -10694 -11598 -7958 -10371 -11473 -10091 -11362 -11237 -10425 -9883 -8928 -12351 -11251 -9234 -7864 -10961 -8654 -10187 -10482 -10095 -9586 -10998 -9101 -8528 -11304 -11500 -9428 -10146 -8774 -9460 -10945 -12002 -8208 -7305 -10522 -9029 -14923 -10831 -9311 -9129 -9762 -11814 -11423 -12114 -10139 -11295 -12119 -10606 -9873 -9086 -12939 -9201 -7993 -11030 -9817 -11332 -11435 -10620 -7693 -10479 -9241 -12827 -12763 -12230 -11964 -8836 -8308 -10709 -10458 -12450 -11223 -8236 -11027 -10120 -11854 -9707 -9389 -14303 -10147 -9554 -11644 -8011 -10517 -10203 -10980 -11608 -13622 -10096 -12206 -12734 -10304 -9154 -10045 -10131 -10178 -8631 -8871 -8976 -10326 -11070 -13427 -10844 -9328 -12073 -9294 -9159 -10366 -10534 -12273 -11824 -11431 -10261 -8262 -8991 -10168 -12358 -8416 -10826 -9968 -11323 -9059 -11819 -10915 -7894 -11313 -10445 -12573 -11847 -11108 -11146 -9461 -8419 -11342 -10069 -11309 -9765 -11221 -9455 -13245 -11054 -16704 -9844 -11382 -9131 -8486 -10015 -7742 -11098 -11215 -11134 -8105 -10448 -10699 -14089 -6909 -7456 -10546 -10661 -8737 -6534 -12040 -11264 -8724 -9778 -16750 -9811 -9369 -7478 -12057 -12144 -10176 -9890 -8453 -8889 -11669 -8989 -10655 -11122 -7212 -7562 -13076 -8485 -12123 -7358 -11402 -12191 -11349 -8678 -10062 -12428 -12377 -9955 -10427 -9634 -12601 -11410 -9525 -11669 -8054 -8102 -7879 -9916 -11310 -9858 -8812 -10596 -10537 -11396 -9247 -8756 -8927 -10220 -10661 -8983 -11152 -10180 -9412 -11873 -11093 -8217 -11166 -11692 -13199 -12559 -7697 -7506 -8941 -9821 -8824 -9471 -12113 -14847 -10218 -10813 -9921 -11777 -13324 -13332 -9747 -10516 -11585 -9117 -9020 -7436 -7862 -10808 -9442 -11201 -11784 -10676 -8682 -11900 -15556 -9196 -9394 -12188 -11899 -11586 -10059 -9528 -7476 -12786 -12810 -9957 -9659 -11501 -10535 -10393 -10494 -10055 -10019 -12413 -10892 -9185 -11950 -9518 -10445 -11072 -10498 -12297 -10600 -9347 -8744 -13316 -11227 -8147 -9595 -10072 -9536 -11107 -7475 -9269 -9566 -10316 -8809 -11971 -11466 -7980 -11669 -9932 -11967 -8496 -11722 -12899 -13781 -8989 -10329 -9433 -7989 -9413 -12980 -12407 -13013 -11081 -11846 -7891 -8989 -8704 -11663 -7560 -10877 -7358 -10082 -8832 -12611 -6599 -10364 -7036 -9260 -9014 -9493 -8760 -10682 -10844 -12209 -11638 -13828 -10822 -12570 -11615 -8110 -9924 -10790 -13686 -13605 -12313 -9553 -12871 -10677 -11714 -11599 -11033 -9310 -10770 -9735 -9126 -8378 -11841 -12045 -9195 -8245 -9995 -9895 -8924 -10789 -10461 -9198 -13625 -11603 -8841 -10561 -9758 -14797 -11666 -12348 -10630 -7758 -10762 -8793 -10297 -9199 -11897 -11340 -9612 -9980 -11828 -8449 -7609 -10148 -10731 -10717 -12079 -10698 -11873 -11017 -8263 -9554 -9215 -9655 -12376 -10318 -9094 -10450 -9651 -10456 -11559 -9828 -10223 -10857 -13662 -10648 -9276 -9017 -9821 -10839 -11854 -8400 -11113 -9919 -9707 -11103 -9231 -10590 -11726 -9468 -11201 -10826 -11114 -9578 -11187 -11717 -12394 -10712 -8847 -11806 -10931 -11745 -10608 -9432 -10241 -11460 -12121 -11072 -12857 -9852 -7811 -8531 -12492 -8643 -8676 -9053 -13027 -8559 -10838 -10552 -12746 -12134 -10367 -8652 -10881 -9786 -9713 -10261 -9427 -10749 -9067 -8904 -12901 -9457 -7861 -10879 -10995 -10924 -8920 -10139 -12511 -9298 -8258 -11644 -12696 -10367 -8420 -10222 -12319 -11395 -11147 -12042 -9066 -10006 -8240 -9899 -9391 -9276 -10599 -10965 -11071 -11740 -10117 -12960 -13774 -9041 -7680 -8853 -15495 -10601 -8665 -9914 -9879 -12825 -11904 -12111 -11666 -7457 -9584 -8444 -12566 -10125 -10344 -10470 -10985 -9765 -9164 -12068 -10997 -8805 -10163 -12725 -9984 -9202 -7187 -10069 -9903 -8109 -9929 -6749 -11909 -11738 -9076 -11855 -9503 -9231 -11473 -10844 -8709 -10260 -13001 -13032 -9671 -8853 -11254 -11709 -8866 -9287 -11639 -12294 -10261 -11238 -10396 -9345 -10263 -12345 -7246 -12688 -10783 -9253 -9945 -6530 -10792 -9733 -10649 -14616 -9178 -9736 -13161 -12755 -9782 -7246 -8227 -11098 -8741 -12012 -10061 -9414 -11041 -9595 -8880 -8413 -8482 -14283 -8745 -10868 -10021 -10277 -9528 -12646 -9202 -10024 -11805 -9926 -14420 -11284 -8658 -9250 -12321 -10741 -11798 -10442 -8901 -11004 -11861 -9501 -8939 -9108 -11224 -12351 -9432 -9429 -12231 -8449 -8709 -9467 -9534 -10257 -14261 -10152 -10132 -8361 -10858 -14455 -10987 -8884 -10433 -8097 -10914 -9495 -11844 -8605 -11056 -11224 -12280 -11087 -9140 -8106 -11393 -11078 -12179 -10747 -11287 -11307 -9192 -10076 -12909 -11810 -10434 -8582 -10387 -10593 -9602 -9127 -9132 -9266 -11689 -10047 -8647 -13158 -10920 -9281 -10309 -10425 -8942 -10131 -12325 -9374 -12191 -13243 -10701 -10895 -9235 -10085 -9341 -10533 -11240 -12999 -8440 -9565 -12508 -10092 -11407 -8468 -10690 -10884 -11003 -8103 -12913 -7217 -9485 -8170 -11762 -11318 -10351 -10978 -9588 -11261 -11113 -8528 -9662 -12885 -12567 -10189 -10233 -12422 -10837 -12323 -12681 -11498 -11055 -9403 -12408 -12316 -11589 -13173 -11267 -7303 -10119 -9955 -11809 -9040 -11716 -8204 -10179 -15340 -9967 -10915 -11259 -11173 -9284 -10262 -9606 -9963 -11471 -9576 -13760 -11237 -10589 -10588 -9754 -10818 -11447 -8305 -8599 -12504 -8015 -8701 -10801 -11883 -9460 -10525 -9910 -7862 -12483 -12294 -8433 -10218 -8087 -9618 -11996 -9540 -7372 -10812 -10340 -9738 -9361 -8705 -9931 -10765 -10281 -8306 -12857 -8900 -12697 -10838 -10601 -11656 -10628 -9956 -9860 -10607 -9129 -10123 -10904 -11440 -9544 -12453 -9939 -7474 -11962 -9824 -8426 -8956 -8095 -10650 -8474 -9058 -6567 -12828 -7973 -11048 -9399 -11572 -11040 -11604 -12167 -11032 -9846 -11529 -8173 -10711 -9710 -11043 -14624 -10058 -9450 -10329 -9384 -10660 -12722 -10181 -10456 -10261 -12483 -10353 -11196 -11958 -8418 -10218 -9493 -12463 -11609 -8280 -10149 -12286 -11811 -9801 -10503 -11671 -8067 -7722 -7807 -9346 -10066 -8975 -12321 -9046 -12379 -12924 -8770 -8956 -7765 -12681 -9999 -6544 -9004 -11177 -6254 -8927 -8867 -8781 -12810 -14020 -10263 -9858 -9489 -11626 -9590 -9211 -8954 -9934 -9476 -8483 -9786 -8029 -9239 -11650 -10179 -10695 -9050 -12890 -10849 -12559 -9861 -8991 -8672 -12043 -9424 -8827 -12394 -12216 -11407 -13203 -10556 -10375 -8569 -11676 -8607 -10708 -12283 -10288 -11634 -8728 -8834 -10047 -9868 -9473 -8583 -11235 -8457 -8465 -11024 -10523 -12016 -10605 -11704 -8736 -9614 -8908 -9041 -8687 -9500 -9512 -12681 -7345 -8075 -9920 -9502 -11972 -10413 -8890 -9573 -13085 -9309 -13458 -11354 -13953 -11547 -6583 -10085 -11961 -10633 -10382 -10500 -9469 -9428 -10110 -9997 -9867 -13715 -11790 -9424 -11423 -11667 -10242 -11091 -12599 -9291 -8594 -9198 -9247 -11239 -13516 -8820 -10797 -10997 -9389 -11753 -12249 -8156 -8563 -9317 -11086 -9214 -9071 -9569 -10076 -10488 -10900 -9383 -9928 -10872 -9203 -9794 -12170 -8558 -8720 -12715 -11454 -9560 -9177 -10691 -12019 -10819 -10525 -8689 -10404 -9896 -10769 -10192 -10404 -7730 -8181 -9929 -10080 -12049 -9692 -10968 -9797 -11768 -11096 -9156 -8380 -10272 -14406 -11574 -11658 -11165 -12712 -8765 -10081 -8378 -9525 -11305 -11501 -8850 -9086 -9164 -8697 -8665 -9194 -9017 -8716 -10327 -9018 -8971 -8030 -10104 -11136 -10389 -10759 -8867 -9460 -10489 -15014 -11279 -12367 -12451 -10700 -10981 -11458 -10247 -11427 -11434 -10801 -9587 -10363 -9157 -10129 -11472 -12458 -10818 -10130 -9453 -14551 -9325 -10435 -11901 -10716 -8788 -12028 -9773 -11630 -10706 -12949 -11369 -8935 -9322 -12296 -9199 -10487 -12506 -13005 -9240 -10139 -11899 -10321 -9273 -7985 -12521 -11114 -11433 -12007 -7915 -10599 -8690 -10535 -11770 -9723 -10284 -8904 -10095 -12378 -10673 -10744 -9368 -12441 -11206 -10284 -11241 -6922 -10356 -8825 -9387 -9752 -10588 -12053 -13201 -11405 -11312 -10896 -11785 -10625 -9376 -11770 -11388 -11907 -10574 -12698 -8583 -11483 -11018 -10759 -10942 -10257 -12252 -13327 -10385 -9865 -9885 -10217 -10039 -9573 -9575 -8811 -11537 -10956 -12174 -10944 -10141 -10467 -11758 -8147 -9367 -11810 -11307 -8272 -9348 -12057 -9261 -10089 -13283 -9494 -9482 -9663 -9606 -10411 -11670 -13150 -10027 -7689 -10604 -9950 -9231 -12650 -11260 -8861 -12010 -9083 -9797 -9592 -9509 -13191 -12435 -10848 -9906 -10186 -10073 -10816 -9986 -12672 -12329 -10647 -9324 -9528 -10839 -12798 diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_0.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_0.pt deleted file mode 100644 index 1b07f3428b03a5024395f55cb65deb9b36c12b7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 zcmbum2|ShE_cwgZ^Hd@4-EZWr`F^riu_{CW&*cO*EmT z(kN3ZX+Shc$#eSM_y2kC?&tmgKcDw`_xbE|owKj~U3=}l)}Gd0+tFS`l*5sfjvKqhTFGz*;vbSR{s$Kgk4;`y}aC9d_BCk?T}vRL zynUQ^nn?3Rbahus2v9o&IX7%}l_G+t%XUAW zguSaTPjZnx$KJ$VIG878FKjOq%##jt|ILYvFHd$cPj2P!s{UqYqsN9FJb8CPS?;3l zf6+4LDY#46oA~k+|3f2)r(`b_#2fY(ez-4Bc`MpV1x|A<( z!<1oPAc+z8lE|BH-M1!hkPN_csMGdjS`Ee{nJCFDm-Jyvd7s27hy5`WF|5f6$o9 zGZN4c^W{zX4~-z6@oz3n{=%F3^2`?VruyyYO^ZoV6SYYET%KaD+Iccmbe z!?W1Wv;2=Jce?rP5NHUGYcI6pKk^cYfXD3Tf%`vFOn78J&+4Bkro0*Zc{Bf$;;d}Yc$2idf2~o_qQT1>%BsmW$8q9?lu~x_zm*0 zn4F)dN8P-&tkQL>$<@fQ5{H+kh!@aDmrTl&uTwfvNkv;3oxM0v-KYc$(tHSSYcitg6^q-A3$b&8y3^<4jSe4waVq=qKn||0!^zO=O&bY{xZIN!{;Glf8W}Qj=qY+x@4@Dp_J7!m-}S! zeg-vF8EKU-F@fw?kE5O`wJ4;aUB2%2MH+uazI>|5V$>)!Ew8PgWo5qVCmrS8Oo@fK z)xq}$7*~O)~PsfyB%u^`8+VPGY8#Rkq z^@&tbmQ3W0Xjc>d7El z{S6z~0+hx<<0iZ*yOA$k=7+N`7DJs(Cw?Lhkozv49jLtxd3V()dYN%c+7C00c5>9u zY!lr5bQ|0c>(fWmyqT+S>>$e`nt3eq9EFGd!dD4WbkEi}VpncSo~7T!Ld)w=^lCP| z=~g6VSL2vIMRig^FEc+H4nobmRiN?xEC0t!Lwu!Kz_0S)z>Fj7@X2x`4A*W3-J?G6 zjQfN&FKgRIG78sW7N!hNi9NnQsuZG6C-%CyG4_2!_yOrNaUrOmEZ zKE%$fS_;)p1Hg|`qMQXQVW{#O<~lY*a`IQ?7^?ESNp^YA#~h|B#{{z!^jM}%9V3#j zV{pa?^h>yjgPnDB-jcVK7YV4G5Lof;)CPZZzwrwY@upeL^@Pi;JeFVwk=hx4Z*T~FPg25gvnKY7^GSB$q;L4(y*L?Z^9B#98RJi3S!&Zc36d-k?mxc_ zrtaTyMTY__ZB!3#Q>Dqyu^H@~IrX?^&Iy=I?%DSre{ ziq=>PtABwW{W?}@-5o}rBaD6KhOpH88hcAYABJ2*m|a7T7_TXe64ym3BP&HR4mB`S z$H`HXmLk;HRfRYIlnf?)DRnsO?c*&%5syf|gT0`GTVDl(JC$trTw%g|)P~Uy8JKsskXy5=qV)dWN_P9bSMb*5 zEB|r71VmZZLZi%Qe(@<$`e=75KfOEm_%WnPRNG@-8WhGKhp^^S)R!-qN>{C058sq0MZ59E{ zn+I3eZRsIKN7-Pdo3rNr5vJiZx)_>d6I1&o&?${YsoloNz8XYirZ2$ zShYeHk|M3h#djX`D*r6AVyq!K|6@JVwWkVHPgKBAi5N5Gc?)|91DOe5*OP^%cVM&5 zcu1@%#=a$4tb|Slw$6JF$D)p-%!G|7_o@f`*@-wkV;w9XI~n$7$YZiz5uDrd1BWe2 z##i>zbZ56Hsr@7hTlZ?i#|mM*G3^VmzR~b0SQToQY2fQ6;&9b^C60Abrj47WsC(x# z_$BueogB(RXXYMO#po0)Ek6etvtwcZYG0hjHNbh{Q{kkJG^1~Bg_#<=*v(5@VEr9g zvLOB)Gj+KT^?xuQL<2aaYljxjw2%h3q6)bFNSG|zJ)U;md5yDg$kDV%$Khe$Yb^Vb z0Z-F}=%I{Vj(UiW9p7P`Nh7YB9|dt~tGTT=uR!atNVYb^ z7eY$ok^4;^mpPon$R!ytdYd;Wbel3Qi^tJ*)_klgOXbETkD?Fnr+`yN8eT0H!uXTN zAo<8AI50H;?z;zqx}zAm;nqCD|f9}FVCiBM(4g)6o!df3IXnUV603rB{i zhe(jJus#@j!kg>UD@Bquit+ho8C1~O1G+YMm=VV%319aRgs*MHNi`~Pcb7H9=eJ_5 ztv9=WERxX%N<=yD2EH~Z#7&GaxitC%gmu4%-26yz+ISZiPdm=k1*w9}t3d3OsD{+6 z6)=~{N1l`fBz<`S52qWFyPD(3DjERwb4QTR&-!qslN?P*NQ1`;7x83B9WEH2g!9&G zQ@obxjP z1_GXglII=p%36-k+bQshPC>fR1~AB;3zi2z;HJSo?EYQ}U-yP1e%^!o$$QpDv=6n$ ze!@!eC|oPeVXuyjhRF6q(9*lvBHTWa<#^=7fs{kgbWx0bI75--x=x^~$BWCd9!im^ zN6#_g))ZU=1^lhOje6UgxxdO3AhzOQsq++M;HelY@7EwdJ0*#l{urX+cmwK|oxn$O zVo;r}OUxY7iB#HV)N)Qj7aug&9m!q2bMU2w)!1L|fA#7eh ze(ZXRS;7`f@6TlJue%68-^ExcCWbQ6*M4BU!30`rbQI?AKF?-9 zTLvMv$MBilbJ$U3NO#&TW&FxS>GIxl5P8S~23j954$H&A&pVI_xVMRsz3;%S%FcuL z(n2^d`8HOiM#0ngonYly4-Z^SKy`R7leOY3irN%nVtF52bTrnKt*;sJ+RLF)vo2R#Q6BC8LjZH%(;oJy^>nYx-gGx_)N$ z_*B$bbQ-c}ePc?lg+Lhh6deEloZWEpF_`3u6ZIoPWcjtrcuOLc^-~LEh1M4#$8A)2fgfYksH<}qCVyehPxavzKB zLtsqX0cOIHb0~AX0K+QQ;K9t}3}5RDGe9D+jXsCbEu*=siW~9GBT;tQhSiWR{gl11 zsv4tSv@ik5{Y*;B1vqt~6B|3dVeXIP@HkD9cyy*<(u!pGwMPxJv^iwTqc*TSG?E^d zJc=LRBty0QR9N}zE#|H}!6qH$!l11Pp{dWI;k615mahTj7mqDs$5~EV!)0|hx(U^nFG~>AGKDn%9vltb*_Z(gZ9!A64 zSC~Qv4`gO`!vncu*s(yA?7nh~*>0c-53KSaeqk$2os-KS(fyvEqJa3kT`pot-2}2csb-kxTgfoHvR-Qfb(pQF}`a;F*|4%qnUCMoeQMtzAf(X%t;T%eG{T%#yrHs+b4sb&oK~J zQ0HcENQb$xZFtVZ2EQ3L~a|nH7w`QBi|OV7B=!_(GNYqT{{kKo(03NX`jpTS|>y7@~_yt>O7n|_y#}u z3S^z$&N_?#!;Z3|SbFQoj zOx64NmQ^!J$cC|``N~Uhk(MB8IW|NnwG6__N}%NQVtBjG6x@um!CJ%-R*1VY*UZ{* z#CLx<(^pAiyw*T&@HFOUr!M1=)y)*?BkZ}Q1-&K~u0gtpFESZ`O%ZyX)WA2qL& zJ85G8Zc)C@vMu*9eSrwElRdy_?k&|i&KviNpdJKCsaF@c9pfsm94+p=~XclEfp*y?Z2)}FCvR^|<$ z-zo_j`8fsK-&M2kKbXS}KSNB>`_Alo(u!Jd{F!pKZbE` z=97L5RgA@vE2BVpp*Vf=SsB6>7URUK0lc4c4J?hXFrP%ynK7T$Aad3!yxo$A&bu$O z{qIY$SndV1E6d`__r+-DH3*wrMQK%+2zmTg8MkIWVf>Oa@#2T+@M0hl)JNIj^2lN| zk|HLA z2+HBrWeDfUEjrhR+oGpUo*|J2f^c6gMXbQT5@*BS1VWLEvagC}d&3N2` zD{lm`-|Y@zXLA&^d8$%nNp<@DYYpBI>1{5@ z#Tsd#7?scZ2l&CY6AqXaJ`t7I$kFzhXEA8#J=$yB!;hAP6hPNov_3feHVn~?g z{7HgwKLy%#2l+0CcjDLYhA={G0CROp+3|~u;ro}Xpu9E#M#DvrQ4j~CS|z->J%Dw} zI?CjhJx8hWigfk#5a>|RWbe&$#=Q!5Ou)Pwcx<$wP77<{>5UFNv?Lks^K!7@)I+xL zMIu=F$s@eo13PpKnGgN7SZQ912ZyGj^`j(QCZmFH3cTT5Ll$$eEwwa)DlkGRX5cle zAKT6Bm`h8OFn{qe*czLG;ujQ%&- zs`{qf^HD6U8X*MHvwOjAy9_O#p9^o?OR+aV41UFY##wWX(Y-2?{A@T>Hb&?Y8(p^# zl?If^Xa8)N;P1(5UAc!B%5LA;|aPj_h?$JeuU;PAyX)Q%DC zu|-pvSDWOSql<^oKQ9=p79HU>Wr~o_5;f*N$%mIWEZEeLYWO}i8F_v3bg9`<=Rc76sKNa3C5uwUng*dcxKJ0!romvOp zgF_qkkPmSuaLG*u^M_`WfHx1|Z0l$;{@g9Jt1yOb2lA&os$?>st~T=rZfm0T;|!Q8 z?}Q&uf8y?|e+b@!y-3leGg#LvI2Ule2@c1SamUQp_%p8pdRqw78kq>~mARO*DF-Ez zYQV8jjat}fFe;29t$BYAIkLIvseF;kJu{Vg>tc_dyH;Xpcpgq!a248aiQ-p_WsC?< z4m8t`!g`}_{2CE~pJr&Hk@-i6<@G_7usYQJ+zX8ON4CIJlDO-g0O!TCL9ZjdO!9LN zZY?Q7pEzIqWWOKkOycqK?O^iq!cE{g?0|y@C}eybPD!b31ym zd?_&FXSk6aVPl9%+H+=uv_E)vN|3^$S>(e!F(%Ke6?NVpM!OA0q)^D3P1Ya7xNX0S zC#Roe!pe?7)_O-Q2$m=6>H4hwSXb7ezW|q+QrP-D24@G2Akw0NWY6_b@oV83HB^q0zC6)AbMGjeDnFhq;a1@ ztgZvm*1QfrqhwGdZ#v!;F(+Y?J4o&kBTR`kLH^5+EHxNI#`-vciCUGw#(o-??jC{` zUMeW;dj;#N?bvH_LPYj;6FD+@J?SbFfm&@z&<>F$+gD8>o7^kVFieD4>gJ%Q*$z)=@0qN-x!t{X^B)2dEZuUIF;}3L5WP<^bImF@`H#yAL?PX7WKEti4 z8x+_QJ21Jt-cl(;U<1^421$ix5dI;s$(ssn`JHm)ejX3TUE@Jmm=(!8e}=sMv4rFr zmNQka{eW`hNMOVR(2SqVT_re&EPvLDV~uNYdD}Yf`OIMYYoaOjR!D=95;8QmU<5>| zi^B_nt!PW^3=m3?pt(wi0ma&I{%sM^x+MZjZxDHOQ7WGOJLU8p+ z@SNL-C!>p@(tkeQSLd@OdwSUuF6S`UDHtdG+yxG5mat3J3@RT7K-bLmY@M$N)^A+^ zTSkbIGO=f%q;-XfD0l`3{KUusj}pl5KZZZMwBY0GLyVl@yy2{S8}s^28g9J2m)mQ( z27Ol6VCJh)u<6z*xM#Ei^yfc7bUn>J+c+1qZ?1re2Sf3xxjDSwd>ZoCUd91QAv#Rt z44&OL9_DpLFej#tggd)mu>L}e@QB0{2#@c>+d7?0cZLr*z3K+FCHtXfTr9Uu&K^FE z&P0jJ132liGzsJj(QjK6$>ljO@mfzfSUIJm$->vH)Wz?x-^u`;4`iZN>Hr3X=i|(w zCcp7-gL{)}vBiFlXoDY>hg6VRsI8R?oqePp;r?_0>45@du1)_yx{C-vE7F zf)g#SLFdjYcCBUKOs@>%6892z2!x9DCcyt1nsSDR}=bGZ~f zWgtu2c1EH8n+$yOtOf@QPGiN+WSo&>fEICa_{ujPmP+KY+Cx9Uw`&5w>{=l1nXwZ- zuQ-k-wLrq1B*=#oDL7U=4RSZ~S?s zrsJvM5qNiBCp>jJ3|rbBp>em2;4E21ux?UZuJaH&CXg>XM|`%@Y^vB*Ew#yP?sCAwq7Gi0H~e=D{l~ z{ALsi>4hWkQFtcAdTT2GT|ga(8JI zx^;_@1RD(^YBZW~GP>c5)F=KW^W)4bxi>I)@(!3f?#BfjFDQ-qgyW+o5HcYV*Jc`W zHyz7|V-;=8srHvJVL=404xNs{W9E@&>nqS?Wkv2UR;0^{f1!qE11rC`3#oECoEGfw zn2s&*I^#V?mPA6<-uKuvZ7U4Z6sE^}s!(deD_p%xmMr0ofGzsP7LwaCnb49CXc?Bo zmfSx9XQDj8bEiI9OMJzcJQcJJ=;u!;y#UR*qWp3TGyHORI3p@JQ!9KTMP1&@Qn8__ zz**Og^Jaen_tJT2vQL`y7caxcCSkf{*GV|4`T=y*s?lbQ0}R)zgaP+REFbR+LwT~~ zz4K{U_joMCS=oYQ{XHmZK1NiZ&L#z?GVu9eJIt{MaDJc5x1Fy-_L!dLDxA(?+GB6P zDq{n3Ir2Qts4)e-@X6%j>h0uG;#Zh4sLq6QZ^CQ49=P6d8TXcou(wwk_Wl%7bkarRWFn#r{rPEDd`D8-vyH_>ORXTuwdgl>E%rrG{b4h)4KVEDNud z_%e^zF(;r)fUU-l;+yO#lzMQ}DQCuVi1D{qxb4fX9POe0!7xA!7 z{V^k$W09*EfFGnn;bmtUu51g!!0cxX*TW3jish)*$|B~F?qVjw^a%G-iVT19Hx7yw z?Zy3}isX!vBvpNS6((25!>#LeY<{d4wn+@a3w?XkTj<7yEJ|SIL{`E6ND=DaI|%#Z zRZ%SYC9-8KJ8N|~475wo{zVg!i5!5a6j`V*pN76m^YOsL7^u{eglgXc7%|=%NX%uF z=`dprLY4_^oznEdCTSX64CjOoF6csy(-ni;I+ZaqLbF8n&>TDtC`GNs-)q#Ih|M`Dn$;t z4ClZ8aTcqp*Wi`W#o*>24sP?au*LiJ?VQPY@#9it}hklZ+OiH zw!dI9OA@faCmUv;m8ZvpDlo=Q4>zq6qqCQIGP_uFnl+j*US$&W$|iwrP_qh3TC*Uu zy_=coKABn<41;IyD$%@99)9k82f~GC`63?`X!xxCkYM?kai2CHG`n6hJ;e_}Zoyg1 z-&%r?4s3zVi)HBV^Mi@vv)Px=?HKiah)J;yP^xhTBT_jeXIu@tIQbZyw|IvWesFQq zvY#0J>>#>iEnsrii;)k*%kbV331Vjb5_bh1g`Qeb5+Pp)6Tga(r`MbDmuw^GWyEq1 z2Rua4OAdUchJBb-a~IF0tN?SpQn-G|1L{s`;Hm<5^ufRBr-v{ExQgChqha7Nz zg#iiA(RkzlmXCS~$#4&MhTh<&-S7jMPChs2c?dL#v;jD#fTQXOSb63)TtBc9bhr1j zE*>LTKg+ckzfgv@eQ^PG%7R>nJH(&OVjCwBob#{+7nWFJ zem)cPNQ!vBScadh+SzvBFuu(q5$Yq{%9^IWz;_ZCV7y2xIFf!wZ$=E(Z5W6AifMe- zGnM5ke`OCli{ka2QnVaa;rfSn^a^ZtWhrdJ8C~ow2!%_j2Vl;pi>UB@FGP*VW`?_d6lrvEqoi>C$xn6|!!IPhdRR85qj?jy9p?$})jlivcqj<=!y(^z_IpB}~w z>b|<~Iex2B!b5YtfE#iMPL6qtN@3@rN9+i+vZBP}+zN;|{0ebsE;JrL3oTB0xVh{u z(9lpk%}CQHIg?;)b~c0u)Pb(>B=W-Fj@WgJLPb*>raZaHs%dwCt3n$d)e6TWsvKg! z0kJXLhz!k|4o{Viz|2{_Q1>bveU6M}`y=(aktb6zk`*HMPvh`+yWP_JHShnzf6?s! zkN=|WQUmx@dKOcS`Q(G-TGs7u65A?uhv~Sj1?g!K*sw$3GqK>grNp#-(2(MWUv}*) zjs6vmZC~@DX5Ro*uw}R?PLk$Vh+~IW9NgVKnd!QaiaGKc^vdNZXbF*|&g(Kr?kNen zV)jw$=zX6%F6So7Et*63&NQdnXV2>({X8!eV@OItb_bB;k*^gJ^qeBF-9G zM(;Hx3Vh-KEDtDA+1w}0&MjR`{sF<6kftS`C^#Wl$7$kx6$$d}S_Q5*DJ4qzAJ`}f z8Jx1b4Aiborb;8_A$;dGW?qCgl}%N{*vPYU^d5KD@<0>$sb{%x(l6Tq#0& zz0|1crMY1GEe5(OB&nk9GWv7Odh{Fl14Uyp$QkuxKw1U%>TWHFDT~34ExWij``*C5&B@b9kgqiQitf*Z23oh_Ci23D|@erQC7``=zx(Jc>FcG3HRWc z31|4XcRfeVhl^;D=yQCNdl{!UUqSJE93rovFR;nK#Psp|G2rq`v`JO8E03>d9*5_1FS0YA z@8sT;co05AGj*!1k3ftSeeH(ta|d-RnfbMUp>Cy9QIjCW6@AyBB%cK7EkDh8{J@UWxkIt|o={H};?Y=zn691$U1Az#9J>`_DP_PwZ2% ze_>7jjs535@+Wq^!N0Jk|Hl4PNB+dd8U71v_HXPzW&S6&-{fD|ssG0QQ-TVAw6m+} z|AYNoM;z_N#V7xrX^e=VPJaihEt3=l5$zdol6f Oza<5q-}(Q_`@aBNqIiM; diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_1.pt deleted file mode 100644 index b0e416a673bbc1f8c0631c387a03b459154271cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 zcmbt*30#fc_iyt&QKlxPqC#juooDS+W-=y~DRZL4Ntq%|DwRq~G$I-_iD)>_+NXiY zkU~hM6iEmb85(YW@9%f->%I5?|9tMf`+W9!&e_lYuDzbU*0YDT*II5ZDkdZ(B_;H~ zB_*NZLYv&TIPciEZOYb79-EBzxVX-nr69ECkK`k=Wy@|?*KJ!ocIo)go zTj%W9;vvHmGO*zZ>pRE{k#^cL&1nC&9owBfcp_Uob`Oy?+TiK2!*#FB2KQ~7J$JZn z-Qcm!ZSQXP4f~8`c%u6H4w6Hty+buOZQsTd`wJp7&vo}EkClHF%J9S;goo-(_TVY~i^ehDFl*ssyy1W0l|6VWHoOu4ejMZfJkH2JC>Zlb zIZH0NDeb`<{TCa?fxIz8+zhdy`WG2B51zUWPvhTg82`nF<{v~%cw_%!L+jscX#Zwo z++TPd51y_KPw(GsnEZ#0@qbV-7nO+~yh%2^$^YiU zN^aT3h~U3@GSl%%6;41_YP?Yk7F&o_h0fF5&@4n!UN~Ol^FBL5gzyNB_=$} zBRs2rm3Z#mY_!~3Qp)evfj~DAA)()S`G2Xs3PL0Q(B3Ii=gk`a58eH($aWGs0^y5# zf`ZgwYW@5)+LtwB+?|x7tM|gOS$2?aom@uex`lGRwnX++0U0-?(Ea4B+_rPK=xPyjN5S=XRjLz?xmL8 zu31s!PV0H9wY?pFOSs0h>t*E7yZt-=cM>-JQ^M2c&6@guknkVF)&KU#Ti;la?K79Y zesPBUve6TySXdEuMig<0@ue&JuhRZ6K5*74jLb^Wgu3m@g7$6Er1F{!4N{S#7ZxPa z{pVfCi$f==faRfk|7G%HA8<9T{E1zZk$~T%Ll)jMAPdKi6WC_ybN$`ELxn>#m0YAk z3_>!AK1g#Ds>QgWMk;irg_vMV&^W=Ehcbfp?LySgV2NN)Yz=jP9ZI{toTO`Jh2e(i z+5D)Zt4N}%5;tJ_cgXWSOBL!KkQ~d4|LQkO%O|FHhTgj0`M>Ko=FfgJo;Pde|8>9p zrz6jf7Nte&rAUd>ExdSGiF)oyh1e~NaK(v9Ffy&2X|T^_=WjX9kA7RjUSYog6L}P! zUoXN2%U>wH@B+?#x&qXC-r$?TkIehNC(u(93M-{!A#zy;trf2 zV_JAU=@)MDU(NYiU_cLYjHp${AyB#7jThd#g1F>YFi%KD|w$=r3yJY@SGQQs5En$~+FGEtaUS{1n&SvBO)>nrf^q$HMj7Gk2ZCtkmC5<0^z@R#Ep zrgkpHZ-%E(V&4>8rQC$OI~9r3x~cGR^;$R`-431mqQO5zm-ao;!_QB)!gwzg#-MNj z?c|!7+)-Vi=IzaH=Cz^l(Hc0!90QFB2f)fD2F$N+fw*ar(3F;dJ3Z9kRWXaATILuv zNsJ!c=L6@WqQLE^IR>6AVsyBrY>a(5`{k4zUA#(|^j$v=%_@61LN=mUrPKtR>L2VH zG34)_u8;19v9R&mPPk*J$3AY8rStoz!xHTvn3lT&VwUEE(Uh9v!-rqP$*p|&6pJu% z`gNQ&UmL{6WaEarH!X5ov*DAaDv zWA>`vL8&iExIpA1wuJOU^Wl*k{yJfpQSAghskh+XCMCK%%mIE~83h_r<(ObAOa(7Q zNTq2NXePI^J&n_`bj=lJ#@q9FJiirU&nGZSO$SPbe;dZ8n3j>82LdRuP9#5n9ut^n zgp%Dy`-{tjL&!vJ3A%mP6|z%9mlclgW7v=7M0&wZc41`{^J2$nZg89x>)9#G-V+#u z%0gcvUQ>aiwq7FpwXczm^%bb)nn}8YB#8dYPG3hut<|8b(w*~PFGPHKbDNqb51=$i&^4xi74m(ha>#jM#(S@>9 z>w6jJS{obt(hs5LX zZ16Xz*3X9#J1?Tm+bqblcVQ=sO3{UJn#`J?LNIY&J092(j8iscqU^~xnAj*m^IL~O z=8IEUy)+UsLfhcpTTA%no`jz|)WJ4sEuO3nfcI8@*meE|mh8C!@iRne#()^jx%eJc zL^q)CVsTnl7td&$`Ljo90j#%HVFQ-rU{BK#e4Y{jh7u*9F5QPStUXK0I*MW8>w6@9 z;UqH0G?jSH45XOIqSeV$xY+j_ ze&5Z<^kq-MPs|6Ok5a{@>prsb-lCv2oCPll8MIy{K^!EafT?^9=UWx2pZ_4ZeldsH zI#H1Iq7_Q!Pk?7DzA?hxdH6j3Ce{{C$AVrRjM$Zp#ng`f;)_1qi7mla$@lQtfW~%u8zh zGugAAiDc#az+(CFk4W0*gMyZ@HewKV8P5gYAu*=AIlCefNu=Q|_$eY!_IxWPU8^_Y z+-MGZ*rt%RwgI@WK!_2!{EOAPQ%jbYmP2e}EQ!3(M9#Db!>!_z*l(I8kF4VQPCQ8VW^c%;l9w>4|w@yV1e zUbP%|jT=rQH@}0YWHG!;j)Gz>XQ((T#%#~_gu8Rb(L6atnw}!XoEp<(aoQsT=Jkz% zTQWJEO=?Q;4Ye~7<(5wtPitZIzP~O;58d2FAfQ- zB2YTo5Ovym;VoC4!;w4<4vo^_vm%~-GOZbcw z!W>U!Dq`Y`PwZYZvv<`)X&!@7??2)7)U~ioJr!L{y`f~mR`mWjnz{E>3zyD(57K2_ z(5z>L#>XA-@U2RCl6@BJZmU3?>_z6&t9Lj(HW1skWx%`bT`;1kA8w6JgbKU&{K@^- zAglZanp_EmQx+HT=BLZRItr0RRu93@F9aj+iPOC23MN_1}xvWkz9lZZPAd)rb{lrLQ#5hi2#^3KfsJ6Y@Lz=`Gw_->wpS% z<(x#9u@pVsQXw>D8{}GO!BpyDAv#~0WETZv!LHkwe!mjsFcR%`v>El|q3G$Dj=|n1 zksN%;{77wsXy1FR=?iT-UO|!0^lHbAd%6&$6^M9O4?g$o!L4?k5H8dQE+eh6dPXH% zbu<-P2CDJg(N0{N6pc=!K453dJ;<~c#Sxb-qGwJZ>$>hgPm(a*wziUZ1iMte(mmF$W}Q8jk=P^KXVic7nDKa zi5FP5xEu#3$Wf5=*w!@+uE}*{%cHeS=&VNEDp7zQSH+05 zRRpqG-dM0th_tvTBAF0@UuNvXqM^ApD7XM82lz1}GdsXP>MW}Mx(Rw6kFd`n3ge_o z@I!zMIXM{0tnnShw`&LCj*m9h&&-GOb#AC*`iQOlqJkNR5R=Okpk_%NvrPCKUS0VS zBetAHb&u=()sf=#hQ~87`rd;UYOkO`<1N&$Pc%1FQlxQ_3Z%9q2qh=JLU&UM5DJim zXWggKlPb`)LcQ=^!xK&B*1>}#PR!5V1xS+fp~Q-1*-hPeuUwScPa6$BrrW{q;1qUj zmR3>hytl0f9bHNpuPFy1@_jC3 z=&fhYeeJ-3#tDV%()WP0c{o#**av34y|{OMAQ}sq!H>6zSh7rkmeL4s}-(a7~El2Iy3t)sxE??}K z4s$(z0xcL?Q|^lSg86wrn9$?)*eY}lWe=Lcz%C)GI{GbIh5dj8v9VO5pbM1JmoRhY z72)?eRqWf9GF1Id1w7hu8A{Fy(NL3LY?7@O70PtxGgA>PBDHW@;TQH=LId8Y4um-71K5#Ohs&2m{j2phm5D;%X3`Ri;$%)!@HqW>l?OdDAMcGmSS&f20Sqz4r*mS z_%$GuqdI#6+}|ln9_;Ky=g&()?oI&{dgLTZG0&CwR|go`etSP=GqO1*B3#G`84d- zI|V6%G+6oQD6@0bc`Wxz0XyqNEKmt3E*ZB2j~qD)YvNx+!g~R_#3(V1Zz>oAe-Wye zo{Gu+Uf|KO4@DM^qQX`ZR4YyhIkFXCc9X#6XBTiJI}Ddil_J`&9Wdo*6ihVrg<<{s zOWwq#v%9}-C&voB;q+9NT$3V#m7A)`j^skDsm&tU``@B*S2_WqRp|Oij97Tu5Z9v6 z;v&yh*mFpNJL2d%a6H+Bhh}OaU!k11Zpwia!^=ebsyO%Mj>l;H)|dE8XTkmjUoqAq z5hk4&Lu~E_py-8lFn^>5=rAMTZt`sb*(T0)VRX3@3Vrx_8bVZimNa)HCxwKMTS_V& zEKu`60_u!^NV-4P;eICy(urvp=_!g*7ey((c%X#ru7}(iFG%0TO`KB5SM13SR_9MXT_E^*%ZOApsZehR3ij%Tl4S4uO zlI#A(8Go$#PL{>bcF?2IT`Yj4a~zHi1~`7nhn zPVX0dYXa`rbBbJ#jiGp?J&Zqcxd`{9Un6;)R86|O>X|gj6>Rmb59EG=9GRo~86Nu= zK<~bz7;?7@E>4^X>TjzUzoB_JP;C_T@ybM9?*a(jD@@n!3d5J-v3Nw~Ic(o6NnhEv z;MkbWsCoTn@wGdVoNa=)5TwqO>OQVr|3elqp4xQ}xN z&fo;m;q1Z@$&5iD!`8@~z}j179I3DdG}#+9WPfqP4P&+8#R?mkY+8f&!uNryz2r=j zNE2urFKRKXv6c0PA9ywSI96C^f}^1VQHYFSYvwNoo7D--vyBfx{$3u=H_62QL+QBS z=~KwLoe57~As+G+BKGnv5K|*Xr>y)6&eOJG&8$IYQ2RbsO3mTq=O1S$T`0ycC1XHO zaubBj>wqby6|AnMH%uHGgNM?`!PkpbjLHm6{u}93uxx$^QY+q~(>(`BtV#vN=pxuU zrUrDD=%Ryv4h97JGY7~@_TBaMtj1|&e8{PRG?NG%c}|x0>E1`H5t4M#(@7}GtHawb z-$UZ668O;A#a!`@fzaH_Av?|vY#N%Au81(S?v{_>t+yXzxw->&S6xNNoe;6<$}#q4wr_mQ2`ShG%R}!lvtHYvm$(dE z8vmR>v+g^JpB5oEUbX`bdJjrgfhaaCo7u2PjP%ZtB55`aIH8C_&%tJ#dUYSm2vRX` z+7&3;)WzQVc8h;m*N30w^Z=4>jDShFU@$WXYd1V)oA&rIdsALO@5WJ}#(fBN0TE2| zhIDd2L{2G(vcq%nuBH~7v+W{oey+)vkh_b) z`@X^(Z9h=C_7cS2UIPi?PWH_}4t}1X276TfhSpZ6pi6l;efc;Wzll5mrAAw@Q%z>d zA}Pv5U51{~F&Nn{K~H>!U2mG!}+f<#;qZ3a(B6Glp&!I&HYsHf?$ z%6jUQ+wg(^_)Z?vFZvbxb$@X}EWTr*`)TC&KV_o5s-g7IGu#rk7Hw`Ez#r$tXlEj_ zOMIkoseubf*JnR`A9|jplK!|O ze=%xX=i(uuGpv{FQg+R$YLLqEhsPm4@FMLrMl!GA+~yEW9;E`Kijwiyx*lljnubN~ z2#0eEQQgy#@d|SUx1sgRNcT*pa)lI0ulE2QaVvbDmW1+j4L|U95a|3kj2jEZU|4B2 z{5mW_0)8~2N$N`W!pZr#>p>-?=>R@ZNrIBY9wmcZN&4-~2D0$M(7Y`=pXj|gB9Qm1 zAl6kS5FgGG*E=8C=#og{osf>FmMhT3rB_Jh@>Gayk!Lg&g}LUp+X39$fPB2c%vMMy zO4U=brLBg@%=IUppQOl|OV6Nlg(GH@DU5CP0BSmv5W@*;A>Azw?>oN0fSk4DjQv$X z#&lio5{Kd37t`yZZO27cANq)`Ado~1dkSCOYhbNbAL=w;AnGgEGM2T`usEa-p5_`u z*@o>fGI4E*%RLd8URO#|^PYi)a4Oj`-c(SzwHrJ-HP1ERcA4VrE1h~2P}+3b?Ik(NKY@0SG~uJ~D~P`AM@$YB3W8n5x$E8Zx%OMelG=S=u|TAaC|GmI z=GjMxyJEh@#k+Qxc&VGLzAHgb*5!a^_8h+AgJm2YD>3RGssmjTNBB`zm-z0bL41vd zdVJfgPJ{Nj;qE*&ED&$MVnmI876P>dE!^|7Scy?D87 zA>?dXf!1|1pyKt3AzM}~u5~x0Beuws9U8;fvGv2T!S^$=11E5O&JGaKuVm+(=mo!f zck%0aJ?8OYFHD>%46B#QQ2E2Jnaokr90I`(-if ztBdi(XieNT-GkMz492oy-k3N$4dX1A(DS!OQ031a%;>#QpeuEs5x9(o0&WJsGDL~y z%ze#DH;R*G9X}w#M4CR#x&hiz~OBI^U{XT-zVJ-btXw@e0Lh@ zRB{BGDNQ+vqU3nMOKAHZ%$|@j~#gFj9MMmKtC>k2@m$eo6YMjn#WPJ7&a4TeJW?o zGG>G9#dn-Dz$0>1P(OS#Tv6--SvwOvc+!s9{5S-a!rLJ0 z=|re)4};0f!S)c*xxBk6U)!xiJt-J89V^-ukJB?7ZnV! zAgoStIa+o4!oikjAnN~>*?Tt(gbj!Gs@!}wvY;Op@@^LuJAKFPYC`m8tSJ3HHVkhl ziO>n-YLKsd9!b6f#4S-pv#%LUw7M_5Y&C_BwF@|#NA8Dj6NG8l{d%nFzko5ZZ<)vu zQ!%ypGZ?0O;iAXgtmTM7XlWFqDr1A-a-cF?x1WhiG;iR|SAMW=#9lC|pcvN=a3*;f zD>BfI%`tN1^Uc+0J82x|I*kBV(P&&_>QBb;HDLdvp4Nq$5t%rbX?MeXOwB+a*IFuerDw@Q;4bB>X`nVEw5 z#s*xyOj)i}%MaFe_Iv!QCd=I@@(MJjijm0@eK5IE3w@{8kfrPHq39G*Tq$=MPX6rR z%NWYg$1}V@)<=Z87fr!ElV!*{ulW$YG?X0^=f@f}g=6Po1=?plh#zxOIZ4BkvA+B+ z#c5}pu(}SU_ zxrcE~e8@a%UWcx-+CaZLqY+z#l9IyIX@d)Ak3&AVtQKeL&rSn{8#3f(k0Nnw-efWF zaTtdyFGphf^I`XN7VH`w`43)=hlke+F!`Jcik$ojWA5^S(k`K_0RO_)0yAIXBh_(w1n!#(s0$lxKuGe(#u7 zYh#(!-b!>JVMlZp;E8jyFl4zX+2z#B z2~TRrZyWkij8USKS3O3;q zsqbR44CB!L84qo?ti_QrnarK+Rk-|D9yZK<$6qBTOGj<^4x*i%FzB}dv!{oah^jnC zA%z+kZXVB`FSaDNHhPwv*sM=-_DIv&A?r!_!G&NPydLDMht9uE#i9316*Mio&hGR+ zh}G*@(!G8c3QZ`5)ssWf^^_G6Iq{wq9+yC_?DZusiiq+8c_J!Z!P%n`$+7twi&pDy zv5wbnFg?>vF{N6Z?eEU#L`q4QR7Hq!Ee7JqI%g?TpPi2tJ%`DpP=74*F(4JZI(Vu* z105o5ApBbs+N++&Id}5${W5i&%S}e#=c%awW;7fWktMe6zHny!a=t@uF|>)C#@APm zW5MKYXy#pmJ92B`_QMiXy8R6Ux_PYO&{<@A`#>?5yu%`oIP5xi2wE)baeIFVjb(=Pz^yR`tiheiJ|>)2|6AX2a}7P zpgKALzKW^P#;%LZ!DAYzmJ`T1_qG8RI+en`tx15Z_pxif4mI(thV6Eb*-=$? z$W#|F6)K_dF})3oKT8my1QA^5d>x)V7RMlJT+7-SGrnEzdwgX#_L7`vO>MEQd93*0C>} za&dGe2NuBx_QNk#8tY<>wG$6v-N)~2^h6Dq6wuFj94tWl`ypVmBZA3@7scwcx^#Nj zYv$ylCJeQU1@~cj=w6NABBbc8@EKoE^j4sYh!K)2C z+~1lH5mUrDVVNxM2zY|?E=+;6=0VhubVXMiU$|r6WRbZl13e@r(Hr^GL2G&!TQ~j` zl-&@aC1Zt#?9!s(X;z5Sy4pC%uY`iDQ{dYsS&Ff`)VU#?kvNjaOj47f2^)T4P4hT* z)8uoIFS{HjI9EWXaW~8wu@!sY?1N;tDy(!GM<>s|0_x)zK-{x7X3=azdg`kWwke;+ z2HSSD-*|;#k2j%s^%WVXw z_3T!34-qH7Qv3LRm+Nr+IcZqdbpiC^@*s2y;<&5QRBbQ^e@st?^)5>pXxPk*+o_CU zN5)g%XctDv_6vJ;qYXS*ahCo3CKI$&{gLm54y13z*Er9>(UKZj4!|$-c(w6PKfCgRC3�htl?dYsA1rFC8#fZiy zFha}^?rWOBjZtFcyW}Nye$+DDB2%zw@po~Qu1H5Hf{U&Qn@2%-DssW9&@3o%Phq4~uxe8*%fe6m2Eo>?tH zKVLY9HWIV(ePK4p`}Ts-{$S4Gk6GZiZ6_l==?i0D8H5KHzhWD8^V!u+qu84+zTn|2 zMV5FcVbj!MR9s9K1&o}rpnvW{&dxz}gPXJBsK;Nf(V49x8 z$=&(DVwjN^3^qH?z0GKdGmzj^d3MaF_vkOS;YDo$&f%lInsK332=t& zvzspL;)@)UMLi)`43u+%#l})Z&BcH}%*D6ZE%ga*dtQs_(#KhHf`dEvcHuy?ES==s z1`qiM;l;c{u;f?3`mp_&cjPV>ZuCUM!?x&Tb_kwUyD+;&MCj7FE-0H^jI;6uOrd@* z9&YYnDyoK#ee31P-h2M&TZ%BXUYcsI@Q1~96z};f(3tdk93$Gy39l~YT$

cealK zoym!;n(9J0bwPN@Px2b@m@shVpJT6Bt--x##Mq6t#V|YFfbni>0bPX&j6(1TIx;i| z&kb*8Q+%^wwTK(Gd>l<{wRYkpT>`Zg<*1tPd?9Z{I&h;t2ASj8?xc- zyyJ_n6l*~0mNAAdNMdJm4dD6647{3s6(uH!lkUjZ*v-5I`!PRIXM!IpEb?R`cXhFE z4g@mBD`sG8=~U1u>tsePUXIgBq^R|yE4Xvw3Se{Em<8ENL+2Tl{NOfuaxLyW^EEaC z*DMNv!ZCXP^21X-AAUh;f{@Vf{NMTE{lkCJmSND+dypQC#CS_`xcVU^u zMM$vtfnG~X!LsWT8MR{prp_y8oceVE%;Je#m^}HMYXq4pb)Z~nL6z^EKtc6HIAQe> zjt0#@&v(+~x8LW)1HZohKlm@2{{Q$ddhYMS{=zpD~yjz4e3xLdOHyrmcw^KYTqQ5$gZ*Z`|%SGShxh0iLr% z`fD< zGX^VBx-%H3X$!z?HlV3(2bB9fgriZX@cc_t40$ai5Y`wbNKCN@gA`-Se0CPmKq z>!D180dq6xI2+h89o6i>@7a0I)pH_(=FS9W^Rx#v z6BB{y6{2(d6i_qfnfcKiRXBdN3aiWRVDW)^esNtoT;IM3t_yY2NS?aD#CSfd+x?t# z_DBFXJSZB*+|XfcG@r84;i7_$!jXcshV!5nxSzS1>%pAY90haD4REDL6*X$FMVp(2 zj9C3y9IoC<=bf&Em)()zIcUdMORLMtafl zH7#>r#K639aP4?8Xl$=S3#Jkq0;L4XN_lWyeGQuLmuAcRo9U0B2HanbeACcg{I)k5 z3bmz~t67L98E-*)o-m|ddx*csm$LbGa_vL0BER#0H!iFH=^t%2Z`SDl(m%R2`8K_~ zfDzm_mKN*_kP(!;=F{J8mGVX1Rfhbqf9L_1M|f4iE< z{L5oLY5S_7a0sE_dAYUl@5}#;>G^xSgwpRDf24m#`1}+7cVB#kKag~&mA|8>O#LVJ z@BZk2V$Ti59Q}cv_D}5J=g>c~&&B_NHU1~|@AJr?*o~9_fi?Lj_U}6KC-#idKd`3% z#Qt68e`3EI{{w6GPi)QKB&hgDKW{bpU)X=^$Z~55iAn#iq$xV|O#e>5Lz{l5|6E&t q2S^R2M?)ljry<<$uqvVJX1~9Mgnr*%ZY?hH`?u84=Xd?T>i!R(Qk-7^ diff --git a/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n150_evenly_spread/k5/trained_ddqn/best_seed_2.pt deleted file mode 100644 index 11727241235251ff2b030b86031d4aa968030751..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_1.pt deleted file mode 100644 index e4877f8ea1aa01f366dbdcfc765f61847e305f2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13463 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 vuGaiY|1O(Y diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k3/trained_ddqn/best_seed_2.pt deleted file mode 100644 index b2b0dd4433349cefb7596c381688cb1c274ee50e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13463 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 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/optimal.txt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/optimal.txt deleted file mode 100644 index 9bb24167f..000000000 --- a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -14435 -20603 -18129 -21902 -20459 -18160 -16380 -20180 -19800 -18775 -18463 -22081 -19525 -17488 -18462 -15685 -16960 -17187 -16589 -22283 -16819 -19620 -20858 -15480 -20103 -15639 -17458 -18526 -20579 -13878 -20608 -18293 -18512 -16735 -20188 -22340 -17854 -16431 -18874 -17852 -13723 -19153 -19149 -16865 -22762 -18983 -26382 -19297 -18839 -19229 -17608 -17557 -17648 -13933 -16815 -17642 -18516 -15430 -20236 -16073 -18212 -25141 -17902 -21152 -21540 -20232 -20527 -16705 -20368 -18371 -17715 -15526 -18589 -20903 -22007 -18549 -16609 -16621 -14159 -20330 -17977 -15583 -20231 -18363 -21059 -20694 -14181 -19893 -15903 -17730 -16834 -18025 -20669 -19709 -17170 -19629 -17422 -14420 -13874 -20308 -17541 -19184 -18988 -18861 -19395 -18117 -18707 -18527 -17737 -21110 -17130 -18592 -19053 -15490 -17370 -19650 -24542 -20863 -20420 -15885 -22010 -17768 -23718 -21123 -21495 -22279 -19387 -21069 -16964 -17467 -21937 -22642 -19146 -19334 -15352 -17543 -19210 -16388 -18165 -23131 -18046 -19917 -19329 -18890 -15932 -19891 -19541 -18212 -21561 -14315 -18978 -21099 -21674 -16735 -19522 -17357 -17389 -22010 -20147 -21682 -19957 -18458 -24179 -22837 -19099 -20911 -21915 -22293 -20680 -19649 -18350 -21525 -22045 -16987 -16970 -15873 -16486 -16885 -18781 -23590 -21162 -18860 -22332 -21469 -16278 -20016 -22210 -19155 -20164 -17284 -20827 -20695 -18430 -17147 -15557 -17415 -21543 -18431 -18757 -16655 -25280 -19077 -16389 -20443 -21116 -19653 -23347 -20701 -24535 -20121 -18692 -15054 -19634 -18589 -17572 -17671 -18168 -15017 -20133 -18132 -25498 -18797 -23401 -16422 -17200 -20483 -18088 -17034 -19007 -18436 -20545 -19003 -20024 -26055 -16003 -17957 -24221 -18797 -22068 -21062 -16190 -20636 -19443 -19595 -21453 -19923 -17173 -20154 -19006 -15358 -18045 -15649 -19310 -16326 -15517 -21560 -15811 -20989 -20195 -18263 -17310 -15690 -16031 -22552 -19623 -15900 -13701 -16982 -24999 -19111 -15203 -17530 -21314 -17692 -20471 -18995 -21575 -22152 -17431 -19577 -18407 -17211 -20628 -16391 -14357 -20027 -17800 -17321 -18071 -15566 -15177 -20292 -15433 -17894 -17367 -16784 -15383 -21877 -16607 -20017 -17589 -21592 -26108 -17744 -25944 -19129 -14506 -16764 -19309 -20761 -17486 -19487 -18111 -17316 -20011 -22374 -17180 -16714 -20213 -19031 -17723 -17872 -15692 -22587 -19325 -21270 -19259 -16759 -18380 -17793 -24531 -18800 -17796 -22945 -19168 -16087 -17380 -17317 -20574 -19899 -17607 -18337 -21927 -17841 -19327 -16312 -17146 -17036 -18330 -18967 -18011 -17702 -17974 -17603 -16515 -17387 -19551 -17299 -22615 -19747 -20423 -21431 -19558 -17353 -19837 -18996 -17166 -15625 -17025 -17261 -17736 -17738 -17149 -16343 -16818 -14798 -18105 -19820 -23293 -19221 -21944 -21374 -15230 -18594 -18913 -17271 -18709 -17352 -17763 -18057 -19808 -18500 -22722 -21810 -20386 -17855 -18731 -20622 -15891 -25682 -16367 -18259 -14902 -18839 -19928 -17928 -17389 -17420 -21739 -17867 -15993 -19409 -24524 -24864 -19428 -18149 -19222 -21802 -24910 -17247 -18103 -21449 -17059 -23952 -15595 -19701 -16984 -19996 -19597 -23863 -20743 -18780 -14656 -22132 -20957 -19064 -14086 -21593 -18322 -19087 -16512 -21110 -15827 -18860 -23547 -18739 -16156 -18928 -16428 -19883 -19079 -16010 -18067 -18934 -19399 -17673 -20072 -18991 -17966 -19769 -18592 -18810 -15701 -16186 -15705 -21933 -17813 -21498 -16635 -17848 -16817 -18523 -18159 -18559 -18705 -20676 -21296 -19851 -18181 -18536 -14812 -16162 -18802 -20684 -19705 -20414 -16535 -19337 -20943 -14894 -18408 -23983 -21840 -16311 -20061 -16635 -18818 -15430 -19077 -17428 -22361 -15388 -20644 -15855 -19289 -17392 -19970 -20642 -21399 -18067 -18194 -19354 -20462 -18392 -20976 -18609 -17735 -17823 -19188 -21952 -18875 -18924 -18964 -18369 -16469 -17491 -17616 -22360 -16455 -17897 -18198 -19342 -18452 -31800 -15470 -18239 -19150 -16904 -19314 -19041 -20477 -21385 -12656 -14339 -20611 -16371 -25112 -16587 -19122 -20960 -19754 -17332 -18902 -19639 -17132 -20277 -21703 -15812 -17665 -15895 -19632 -19435 -16867 -17095 -15558 -24223 -20324 -19898 -16230 -14733 -20296 -17551 -23210 -17895 -18057 -22653 -16754 -22738 -20846 -18616 -15120 -18266 -18331 -22230 -20319 -17308 -19672 -21005 -16613 -19845 -21163 -16154 -19800 -16112 -20143 -18981 -16582 -19298 -18154 -16432 -21685 -18057 -17867 -16305 -22798 -21828 -22316 -23818 -15800 -19980 -17896 -16735 -22928 -24027 -15913 -20791 -14391 -20972 -18506 -20767 -22533 -17522 -25280 -14760 -18953 -23368 -20341 -17717 -20814 -14329 -20991 -17749 -19762 -20050 -18568 -17556 -16989 -18190 -20226 -19598 -17455 -21792 -16367 -17998 -18596 -15886 -14304 -19428 -18127 -22838 -19774 -20285 -14903 -19382 -18157 -20862 -16176 -18335 -17386 -15399 -21132 -18385 -20530 -19133 -19176 -17375 -20293 -18447 -19793 -26620 -14726 -17457 -20385 -17949 -22579 -19251 -20402 -19466 -19457 -18436 -19208 -19452 -16131 -15212 -17603 -15440 -17157 -19804 -15980 -23851 -19519 -22491 -21266 -17017 -15244 -19437 -18360 -23140 -14163 -21659 -19813 -19574 -19678 -18390 -16340 -19500 -17643 -15247 -19540 -19881 -16817 -19721 -20966 -16329 -17802 -18977 -14785 -16723 -19244 -15694 -19054 -20416 -16905 -15767 -18982 -21250 -17434 -17234 -19612 -19957 -18834 -22136 -19293 -19064 -20548 -18597 -19241 -16643 -12353 -18305 -14152 -22854 -20800 -20975 -21793 -19457 -19930 -17680 -18236 -22115 -18836 -22648 -16845 -19283 -18312 -17374 -22794 -17158 -18850 -17362 -21356 -18473 -18095 -17429 -19762 -17666 -20985 -16774 -17368 -20815 -19429 -19994 -19601 -19245 -15265 -16082 -16664 -21997 -16514 -21462 -16716 -19192 -20782 -19385 -20528 -18512 -16086 -18436 -20954 -17974 -19447 -19659 -14171 -21384 -20331 -18817 -19940 -16966 -16069 -21841 -21717 -16738 -16048 -21854 -15271 -18521 -17608 -20922 -17105 -22716 -17660 -22036 -18045 -19195 -21417 -22928 -25530 -18762 -14804 -16108 -17527 -16309 -16113 -20771 -24093 -18455 -21569 -17795 -17314 -21923 -19598 -22770 -18400 -13671 -19562 -16612 -21849 -18264 -21872 -18458 -15328 -18504 -19761 -14921 -19110 -18403 -14613 -20321 -22597 -19968 -19579 -20842 -16188 -17508 -17765 -18397 -19222 -21129 -22854 -20951 -23649 -22569 -18898 -17925 -18917 -24110 -17567 -18796 -18632 -24554 -23200 -17923 -18882 -20928 -13024 -20488 -22511 -20746 -17622 -15707 -20458 -20152 -13425 -22204 -20163 -20298 -17596 -16418 -18624 -16140 -14874 -19095 -17451 -14777 -19979 -17432 -18617 -18667 -15587 -18647 -21311 -23253 -21626 -16909 -15292 -19504 -19027 -20733 -18119 -22892 -20435 -18901 -21613 -20260 -18998 -17433 -19401 -19071 -17420 -22695 -20158 -21342 -14909 -18188 -17804 -21370 -19535 -22351 -21600 -21786 -20647 -24056 -22961 -20733 -19994 -17040 -23144 -15644 -17989 -14569 -17286 -17297 -21196 -15777 -18439 -23256 -19501 -18923 -21455 -19718 -20356 -18109 -21098 -17562 -20494 -13008 -15410 -20423 -16582 -20317 -20554 -25189 -16026 -16042 -21379 -17971 -18161 -20803 -26208 -17423 -20835 -18413 -17274 -17015 -21286 -18983 -19387 -19842 -14901 -21279 -18793 -19869 -17407 -21214 -17755 -13851 -17607 -19074 -17389 -18556 -16932 -18181 -22348 -20774 -16672 -18303 -20257 -15791 -19461 -22348 -17004 -20737 -22618 -15250 -17237 -15613 -19019 -19236 -16172 -14399 -19515 -20426 -18007 -15436 -18524 -19324 -20763 -22755 -22187 -16409 -18718 -19685 -19428 -17804 -18282 -17479 -16539 -18130 -15721 -14867 -19322 -19089 -19539 -19807 -18377 -18491 -15552 -20244 -18880 -22060 -18255 -18991 -19274 -15482 -17190 -18803 -18351 -19306 -19275 -22939 -19509 -19956 -18387 -19191 -17542 -21490 -20432 -19968 -17399 -19404 -15754 -15821 -16488 -24662 -22152 -14464 -19780 -23857 -20858 -16992 -16648 -20254 -18181 -22445 -19861 -15357 -19803 -20399 -16338 -16932 -15159 -14982 -20610 -17644 -16035 -20549 -13569 -18573 -14827 -23273 -16791 -17974 -21014 -17323 -18126 -17899 -19513 -21382 -16348 -19134 -20280 -21673 -19409 -21839 -13358 -18858 -16501 -17900 -18580 -16778 -21333 -19125 -16646 -18252 -20853 -19623 -20575 -17703 -17673 -19502 -18849 -22182 -20090 -16406 -21141 -14108 -23129 -19755 -15680 -13686 -15680 -21298 -21679 -14455 -18121 -19238 -16966 -16659 -19128 -20877 -16810 -22184 -21338 -23265 -20348 -17244 -18019 -18573 -19274 -21101 -19905 -17999 -23124 -22514 -17964 -20564 -20086 -17001 -20331 -20815 -14389 -18844 -18055 -17427 -18565 -18317 -18871 -19451 -18897 -19554 -18810 -18146 -17859 -17329 -23382 -21098 -17699 -17604 -18741 -21961 -23694 -18607 -19202 -18256 -19550 -18245 -15100 -28508 -15254 -22251 -16633 -16514 -19963 -21127 -15626 -17315 -18338 -23298 -14836 -18376 -20735 -17727 -22674 -19980 -20137 -22152 -19818 -18303 -20484 -17446 -19716 -19098 -18277 -18858 -20402 -16362 -20259 -13110 -20827 -20806 -20732 -20914 -17557 -18564 -17387 -19132 -23522 -20888 -17859 -21040 -18313 -17018 -16814 -20244 -17830 -18735 -18583 -17280 -16593 -19433 -18560 -21983 -19155 -21775 -17795 -20085 -16037 -19504 -15927 -17716 -16611 -20244 -19485 -17498 -20545 -20796 -17058 -22002 -20826 -19601 -22486 -18611 -16702 -16937 -17090 -21950 -20597 -20598 -22061 -20195 -18756 -14072 -19713 -19081 -19597 -15394 -22394 -21452 -24042 -18197 -18993 -16256 -19311 -17121 -15997 -16207 -23438 -20070 -16004 -14344 -21499 -18236 -14907 -21627 -18444 -17067 -20182 -19673 -19934 -20830 -20530 -20972 -17839 -21500 -20828 -20037 -18466 -18432 -20684 -18621 -20316 -20451 -20922 -22443 -21848 -16989 -15115 -23299 -21647 -15509 -21972 -19890 -20968 -21658 -19932 -18607 -15535 -19667 -17043 -19692 -19711 -18615 -13431 -23276 -18805 -16522 -16659 -20585 -17880 -19487 -18539 -21979 -20909 -21206 -18411 -21272 -17520 -20219 -19459 -21487 -15492 -19010 -15704 -19302 -16817 -19873 -16654 -18591 -21469 -14820 -21674 -21116 -18257 -21719 -17155 -14886 -14543 -17822 -16972 -17179 -17663 -18895 -15757 -23719 -13820 -18461 -19849 -20814 -19033 -18026 -16912 -20017 -14782 -20851 -22521 -19431 -22815 -15169 -15399 -21593 -15733 -18500 -21835 -15688 -21782 -19947 -18866 -19505 -20449 -16858 -18119 -18102 -24172 -14034 -17781 -18288 -22270 -19442 -21199 -21981 -22065 -18320 -16642 -18414 -23019 -21627 -18406 -19543 -18171 -21914 -19285 -20395 -19279 -15813 -21952 -14855 -17897 -19465 -24304 -15778 -19115 -18157 -19488 -23245 -16459 -23468 -19387 -23253 -16480 -18930 -17381 -24603 -19805 -19289 -19866 -18554 -22804 -18898 -20387 -17605 -14059 -20195 -19762 -17845 -17066 -18995 -20383 -18888 -15600 -20794 -19395 -22912 -20160 -20550 -17455 -20169 -18607 -14925 -16711 -17303 -18471 -24385 -19721 -17203 -14812 -17820 -21513 -18699 -17034 -15415 -17585 -16106 -17096 -18417 -17383 -23791 -18376 -17696 -14840 -19765 -19164 -18772 -20213 -17766 -19834 -15250 -19165 -18284 -16045 -20017 -25127 -17558 -15939 -16170 -24983 -21917 -17217 -19912 -20191 -17138 -14861 -16818 -20714 -15228 -14820 -16402 -17299 -19980 -17647 -19426 -18287 -24306 -15831 -13437 -17225 -21882 -17189 -17614 -16937 -16742 -15459 -13997 -18675 -22525 -19774 -19074 -21639 -21386 -18959 -19505 -14183 -18771 -23910 -23334 -20068 -18372 -19797 -19813 -22230 -19443 -17535 -19261 -20392 -18472 -16535 -19098 -20867 -19376 -21924 -22223 -20466 -15258 -15498 -22636 -21764 -21757 -18389 -18343 -22368 -22595 -22305 -21887 -16221 -26352 -18588 -17863 -16514 -19356 -16104 -18128 -18688 -21854 -22357 -16488 -16954 -20069 -20406 -21639 -18671 -23519 -19229 -18662 -21380 -19257 -17814 -18133 -18602 -14929 -19654 -16290 -19653 -15903 -19605 -17356 -18330 -18463 -18515 -21031 -16520 -17173 -17631 -16638 -20117 -18411 -18507 -20241 -16479 -19468 -15411 -17879 -19469 -17473 -18867 -13546 -19090 -21630 -22820 -21252 -23397 -18167 -14836 -16208 -15755 -15926 -19769 -18778 -17083 -18419 -18673 -19970 -19655 -18940 -22941 -21933 -22643 -16757 -22426 -15985 -18796 -18279 -17432 -15405 -19233 -21107 -17280 -20513 -19773 -17065 -18832 -22593 -18014 -16927 -22151 -18509 -23064 -24757 -17133 -16279 -19448 -17576 -18317 -18831 -18641 -21583 -15741 -17601 -15397 -16958 -17870 -18679 -17558 -20243 -25052 -18631 -17166 -20719 -19246 -19595 -20018 -17921 -15297 -20802 -18988 -19756 -20020 -15145 -17676 -16791 -15823 -20078 -19774 -19873 -15208 -17220 -19387 -17190 -18153 -18436 -15628 -19584 -20427 -25634 -22278 -17985 -22103 -17838 -13762 -17974 -22515 -17150 -16008 -20617 -13867 -20361 -18666 -21039 -20126 -20789 -22190 -23093 -19447 -17323 -12660 -19431 -21019 -20258 -21973 -16580 -20105 -16144 -18914 -20578 -21674 -20101 -20218 -18453 -17379 -18557 -21416 -18937 -21343 -16625 -19365 -19528 -17186 -17785 -22190 -15052 -16895 -18099 -19522 -18347 -17573 -21545 -18052 -20636 -18254 -20892 -18279 -16493 -20338 -21246 -17583 -16899 -20808 -22128 -16914 -19624 -18287 -21556 -16817 -22777 -23627 -17784 -22293 -17110 -20175 -20996 -18188 -18761 -17635 -19105 -18861 -16856 -19514 -21818 -16610 -20089 -17578 -18426 -17582 -17176 -19800 -20337 -17794 -16240 -18169 -17514 -21982 -18069 -19206 -15575 -19449 -20322 -23279 -18465 -18643 -21214 -19057 -25534 -21351 -21117 -19589 -18253 -20032 -21770 -20072 -18230 -17217 -17886 -15062 -22295 -19610 -17843 -18765 -18484 -20329 -18646 -18832 -16114 -21324 -21036 -25279 -22207 -17479 -19225 -26429 -21386 -22508 -17918 -20691 -16825 -21141 -15339 -14829 -17876 -16835 -21034 -23656 -17436 -18368 -17336 -18957 -20167 -22833 -20235 -20558 -18804 -17126 -21173 -18456 -19621 -22010 -19045 -17534 -16452 -19927 -15854 -22748 -17238 -17350 -15000 -21275 -21838 -18359 -18644 -21592 -19159 -21048 -15117 -18853 -17395 -17182 -19011 -18939 -18709 -25676 -17236 -22635 -17693 -20328 -20872 -19367 -20279 -24362 -16388 -15687 -23055 -22328 -16965 -20192 -19307 -14220 -17594 -20006 -16808 -22706 -24168 -18204 -18344 -21003 -22020 -16129 -20520 -18055 -15941 -19121 -20983 -15169 -15725 -19947 -19145 -20159 -18358 -20535 -25054 -19161 -19444 -18516 -19924 -19838 -19819 -17695 -20105 -20837 -17026 -16667 -16718 -17699 -16566 -17054 -21271 -16874 -18762 -19252 -17052 -19389 -19107 -22259 -17826 -16946 -17105 -16539 -19051 -19053 -15919 -18968 -18573 -22044 -21556 -18288 -13740 -21120 -20672 -18208 -17367 -18106 -22171 -21502 -17981 -19399 -17471 -15726 -17725 -18022 -23258 -22172 -18922 -19240 -18591 -17050 -22109 -18543 -21805 -21061 -21455 -18651 -20695 -20321 -16936 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_0.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_0.pt deleted file mode 100644 index cb865fb978003d4769a5070da8ce480f2e6a951d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k4/trained_ddqn/best_seed_2.pt deleted file mode 100644 index 7c800f099017fd7863e94b1b1976c0bc0a1304c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 L`TZ*YyX^k~cXLKx diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/optimal.txt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/optimal.txt deleted file mode 100644 index 2bcff5b9c..000000000 --- a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -16679 -16794 -18448 -21880 -17651 -22039 -14919 -18071 -18755 -16951 -13569 -14650 -16084 -19164 -25312 -15627 -22213 -18594 -15380 -15623 -19555 -17195 -20780 -21963 -17660 -17985 -18663 -18665 -16554 -16993 -24534 -18954 -16459 -20928 -19501 -17999 -18447 -14386 -18171 -18296 -14929 -20492 -20493 -19605 -18214 -15641 -21502 -21312 -16887 -16875 -18188 -15974 -15516 -20224 -19862 -18514 -18011 -16515 -16581 -20472 -21792 -15372 -17617 -22172 -18327 -19314 -15398 -18915 -19783 -20107 -15904 -15244 -20796 -17652 -20352 -12858 -14572 -18991 -19517 -16354 -17108 -16239 -17059 -17700 -21783 -21416 -20695 -19100 -21528 -19940 -17829 -17653 -16924 -19465 -15536 -21490 -19631 -16750 -15371 -16879 -18956 -22082 -19957 -17443 -18785 -22170 -22200 -19762 -21488 -17688 -20283 -16561 -16500 -18848 -18073 -17024 -17984 -19472 -19190 -16141 -20053 -14693 -20576 -20100 -19352 -18982 -21959 -17083 -16394 -20688 -20845 -19334 -19737 -16264 -17517 -15779 -16209 -22123 -16649 -17333 -16854 -17770 -18639 -20459 -16167 -20020 -19451 -21894 -21813 -17227 -20974 -19008 -21000 -21037 -16647 -14119 -23211 -17172 -19597 -21119 -20559 -19592 -17985 -19376 -15809 -20031 -22008 -18249 -21149 -17015 -21535 -17169 -23265 -20124 -19672 -18889 -18419 -15941 -21703 -17863 -18080 -19992 -16525 -15739 -14358 -16584 -16985 -16263 -22355 -15325 -13691 -19263 -18653 -19652 -16748 -17267 -18643 -21082 -22540 -18748 -20342 -18532 -21110 -21613 -22350 -18522 -14690 -21808 -13554 -20624 -20711 -21073 -15883 -17088 -16286 -20964 -18551 -16101 -16738 -16532 -19203 -20337 -17804 -20353 -15868 -20286 -15699 -20208 -18295 -18826 -19281 -19738 -18123 -20993 -20103 -13734 -17264 -18074 -18216 -21705 -20428 -25252 -16721 -17321 -19548 -21528 -19083 -20654 -16165 -18350 -22403 -17605 -16709 -23989 -18050 -16781 -15932 -21051 -17688 -19635 -19871 -17459 -21292 -16224 -18346 -20606 -27283 -22698 -16367 -22016 -19558 -19497 -20753 -17356 -21372 -18197 -17860 -16954 -17817 -13979 -17899 -17165 -18944 -18643 -19305 -21195 -21174 -19220 -20064 -16715 -17800 -17312 -20889 -19822 -15301 -19176 -19788 -19819 -15658 -21138 -19891 -23088 -21624 -18230 -15768 -18308 -17534 -21086 -18254 -16695 -18732 -18817 -21281 -20089 -19861 -17646 -18836 -20188 -17323 -19176 -17898 -19783 -17874 -20313 -20700 -17575 -18557 -22341 -20724 -15149 -14451 -20271 -20524 -20282 -19458 -16964 -17450 -17635 -15372 -17631 -16299 -21618 -20191 -16538 -22993 -16182 -19618 -19169 -20265 -16140 -17912 -19244 -18853 -20195 -21186 -17374 -22183 -17534 -20862 -16602 -18495 -18739 -20058 -18979 -21797 -18096 -18418 -18754 -18556 -18088 -20084 -15263 -21851 -19771 -19455 -19078 -19001 -19951 -16703 -21822 -15645 -19180 -17656 -17705 -20930 -21280 -21133 -16838 -15767 -16727 -18094 -15184 -16602 -18046 -20505 -18299 -19135 -16686 -17014 -19691 -20817 -16245 -16593 -19444 -22660 -19923 -18245 -14502 -19563 -14693 -18629 -21926 -17154 -18774 -17121 -15062 -21838 -14982 -17550 -19105 -20206 -17695 -19785 -19297 -22037 -19785 -19801 -17336 -18274 -17649 -21073 -13862 -20194 -20692 -17254 -22873 -21091 -18806 -16587 -20802 -17782 -21870 -13120 -18276 -20147 -21083 -17169 -20925 -19109 -18826 -16854 -15688 -21504 -17629 -17155 -21481 -16236 -20076 -18387 -23951 -18447 -19030 -15982 -23689 -18019 -18345 -18953 -14540 -14229 -20313 -16421 -13222 -15994 -19861 -20326 -20333 -21047 -16280 -19223 -15926 -22132 -15428 -22126 -16742 -19812 -17999 -20404 -18370 -13733 -18589 -18497 -19639 -16408 -16735 -20872 -17467 -22598 -15087 -20230 -20837 -18206 -19214 -20400 -19284 -19332 -18978 -20800 -12898 -18317 -16200 -17363 -20061 -17481 -16441 -21034 -16938 -16628 -16402 -19050 -23262 -17881 -18648 -16245 -26256 -21427 -17427 -19924 -21496 -17108 -19248 -19547 -21794 -20767 -20113 -16337 -18693 -15928 -19786 -18149 -18822 -19354 -20430 -20521 -16379 -22719 -26871 -23769 -20831 -21056 -18343 -17977 -17800 -15896 -21442 -17713 -17486 -22529 -17075 -17910 -19076 -20715 -13152 -18312 -19556 -15363 -19323 -16831 -15638 -21516 -22363 -16443 -17017 -19427 -18363 -19548 -15715 -17867 -24463 -18019 -21615 -20972 -19018 -19663 -18844 -16870 -16261 -22520 -23566 -18210 -18649 -17901 -19392 -21088 -21229 -17541 -25332 -22432 -20232 -19363 -16445 -19056 -16456 -15767 -18309 -17198 -17212 -18227 -16399 -18793 -19724 -20413 -16322 -14024 -21648 -23320 -18959 -19830 -18481 -20951 -18707 -18817 -22056 -16624 -18888 -14759 -20647 -16205 -16972 -17626 -17911 -20684 -23188 -17756 -24640 -19585 -14803 -20427 -11454 -18750 -19008 -16766 -20181 -17159 -21537 -19456 -19606 -17988 -23047 -17356 -20674 -18285 -20963 -12423 -22613 -21636 -18111 -19290 -17503 -16162 -18015 -15384 -18772 -25102 -21086 -19689 -19721 -17145 -23369 -21501 -14295 -18282 -18811 -21034 -16486 -14335 -18325 -24167 -16550 -22481 -17531 -21045 -17535 -18511 -20177 -16914 -16962 -17914 -16758 -20339 -18901 -15010 -17818 -20040 -17351 -13794 -15997 -22996 -16289 -20010 -18441 -15536 -19061 -16104 -19532 -17947 -17944 -17375 -18376 -17359 -17941 -20210 -18677 -17183 -18722 -19842 -16752 -21054 -18409 -14230 -16093 -17245 -20119 -15847 -19003 -22833 -22783 -23180 -20553 -21541 -17137 -18560 -19209 -21082 -15092 -21175 -17575 -17704 -20272 -19113 -21333 -17982 -19324 -16746 -15862 -16368 -18703 -19878 -19903 -20425 -14454 -17243 -19203 -17207 -18291 -23251 -16025 -20521 -19105 -17217 -17171 -22320 -19777 -18125 -19027 -14360 -21256 -18192 -20141 -14589 -17383 -22123 -15630 -17777 -20127 -17757 -19562 -20326 -18114 -15004 -17092 -19556 -20096 -16903 -19538 -22888 -18918 -18250 -17767 -16716 -17809 -20885 -19192 -16798 -15218 -21599 -17814 -22901 -22669 -21881 -15830 -20806 -20819 -18394 -22738 -20453 -16244 -18572 -19325 -22735 -16900 -20836 -17623 -19304 -21702 -18445 -19952 -20122 -15710 -20314 -17024 -15196 -15868 -16234 -17718 -15868 -15669 -18309 -14735 -15969 -17671 -23455 -19697 -18501 -20301 -18667 -20454 -23206 -18008 -24484 -19474 -21643 -25490 -20163 -16878 -20298 -20831 -19768 -16760 -22511 -15252 -18719 -23673 -22523 -19834 -19480 -16587 -23790 -19320 -16730 -19885 -22428 -20175 -19563 -17891 -17531 -19441 -18950 -17177 -19879 -19824 -16514 -20234 -15701 -24952 -19478 -20056 -19348 -18747 -24674 -20994 -17907 -21942 -18278 -18428 -20683 -18088 -20590 -20382 -17137 -19285 -18563 -16462 -18597 -19459 -16739 -20336 -18829 -20944 -21604 -17989 -21069 -19929 -26866 -22962 -18785 -20937 -19257 -22071 -18196 -25729 -18957 -18653 -14361 -20176 -15206 -16986 -16066 -19587 -16587 -20832 -18638 -19217 -20445 -20212 -15903 -18249 -16976 -16977 -21207 -17627 -19106 -18277 -18348 -13771 -18335 -20329 -20842 -18314 -19107 -21822 -17497 -17620 -19993 -20868 -19020 -20275 -19090 -16319 -19016 -20103 -17141 -13642 -17737 -19837 -15358 -16144 -19599 -20639 -23196 -20181 -20281 -18594 -20172 -20583 -18316 -16548 -17236 -16866 -16712 -18372 -19062 -16060 -22439 -18195 -16177 -21499 -19844 -20584 -18094 -20449 -20591 -22138 -21646 -21226 -19675 -13606 -17890 -21755 -18978 -20124 -17628 -23042 -18614 -20002 -16803 -19506 -18044 -19065 -17423 -15251 -16311 -20311 -22341 -17768 -21575 -18852 -22478 -18459 -17721 -22534 -22381 -19965 -20020 -18141 -19790 -18355 -16342 -18618 -19027 -20841 -18712 -21621 -21900 -19745 -16147 -16773 -18466 -17383 -21014 -21255 -15941 -19767 -17447 -16933 -21944 -19172 -15900 -20617 -20446 -18718 -15792 -20197 -15417 -20839 -19934 -20867 -16856 -13845 -24174 -17761 -16357 -17519 -19534 -22883 -18947 -19727 -20603 -19711 -22393 -15036 -17753 -20833 -22887 -19159 -20369 -16518 -17696 -18510 -17709 -19149 -19453 -16936 -19834 -16582 -16118 -18245 -17105 -17808 -20327 -20424 -20381 -19874 -20331 -21733 -19553 -14513 -20710 -19814 -16725 -20967 -20842 -18539 -17234 -16285 -19356 -19731 -20751 -16879 -17398 -17442 -22599 -20042 -14469 -17327 -17902 -21986 -19325 -20523 -20644 -16340 -17615 -21560 -17272 -18320 -17081 -18949 -17099 -20833 -17576 -24003 -17331 -15455 -20794 -16240 -18137 -22565 -20093 -21528 -18469 -17658 -18417 -17422 -16902 -18359 -20278 -16731 -19269 -17659 -20304 -20242 -18632 -13979 -20004 -17775 -19217 -24154 -20084 -17620 -24094 -18621 -18968 -22777 -20243 -20726 -24404 -18458 -23498 -18081 -22071 -15366 -17182 -16215 -19318 -17373 -18600 -17278 -16135 -19284 -21157 -17079 -16617 -14628 -17666 -23141 -20444 -18677 -17181 -18944 -17531 -21289 -20231 -19036 -18756 -17425 -16051 -15473 -20190 -24801 -20591 -19225 -17612 -18483 -22259 -21710 -22496 -19850 -19118 -17623 -16899 -21604 -18223 -16823 -21171 -18916 -22320 -17701 -22422 -15204 -15514 -21005 -14940 -18276 -18476 -21893 -18121 -17601 -18269 -18309 -19260 -18097 -20369 -18886 -16145 -16846 -16837 -22483 -17478 -16347 -16425 -16820 -12671 -17221 -18731 -19821 -15206 -17438 -13215 -22372 -20534 -19083 -24381 -19062 -16723 -18924 -17719 -21442 -16905 -18855 -20323 -20363 -20286 -24227 -22633 -15431 -16369 -15787 -16141 -20209 -19602 -20333 -19202 -18640 -20247 -18888 -16288 -19976 -15220 -18804 -22873 -20510 -17018 -16363 -16847 -16732 -17354 -19510 -19113 -21251 -16027 -20061 -16793 -19287 -18346 -15947 -17872 -20537 -15204 -17733 -17453 -20329 -18910 -21941 -23214 -19451 -17443 -21945 -16528 -15540 -18675 -19753 -16450 -18915 -14997 -18962 -21103 -17397 -15332 -17172 -20986 -18920 -16702 -14534 -24459 -16936 -19159 -17441 -17890 -20141 -18816 -18372 -16320 -17213 -18415 -17180 -15803 -16071 -16827 -20592 -18601 -22058 -18720 -21542 -17132 -19176 -21514 -17970 -15022 -19220 -17252 -16793 -19276 -21410 -18711 -19367 -16855 -25657 -16040 -18334 -19399 -16892 -17930 -18096 -20473 -21433 -17154 -19529 -18987 -21427 -19458 -20192 -15453 -19757 -21987 -21512 -19945 -19826 -23980 -23112 -22273 -18465 -15817 -19208 -17705 -23222 -18997 -15615 -20538 -21754 -19447 -22860 -21657 -17769 -17117 -20695 -18889 -18238 -14849 -23525 -17869 -16537 -21368 -15450 -18857 -18170 -19421 -18923 -18738 -15269 -17335 -15936 -19547 -16760 -21613 -19403 -16778 -18921 -19794 -16333 -24029 -16117 -21362 -19849 -16683 -20913 -17806 -16818 -18713 -16223 -18319 -19045 -16148 -22211 -19463 -18637 -21792 -20887 -14530 -17098 -14646 -18772 -20122 -14151 -20652 -17196 -19854 -22321 -22391 -17348 -15274 -17102 -15844 -19198 -25035 -18970 -19343 -17894 -17261 -14105 -19083 -17767 -17058 -20387 -14426 -18366 -21560 -17215 -21466 -17127 -14635 -20210 -17869 -15894 -19190 -13724 -17340 -18580 -22026 -17264 -17568 -20337 -17774 -21405 -15969 -18630 -20464 -20616 -19709 -23702 -22247 -16091 -19013 -16347 -20208 -14234 -21054 -15541 -16750 -17661 -15001 -18995 -21420 -22279 -22026 -18616 -16383 -16722 -17959 -17889 -21601 -13801 -19269 -14387 -16859 -12663 -17043 -20402 -18392 -16847 -19356 -20433 -24590 -20091 -18133 -19142 -15336 -22688 -22160 -18213 -19576 -15444 -18887 -21587 -16326 -21576 -18298 -19354 -18982 -21160 -14794 -18099 -23265 -14012 -16239 -18009 -16715 -19472 -22832 -18479 -17838 -18173 -19854 -17587 -19659 -18878 -16513 -17078 -18504 -22237 -16939 -15238 -21021 -18476 -21101 -16860 -18424 -24147 -19209 -18042 -20517 -19708 -20194 -21649 -17672 -24420 -17324 -16551 -18484 -15451 -18346 -19575 -20119 -16659 -15128 -16490 -14042 -18260 -20879 -20271 -20012 -15532 -21019 -22459 -18201 -16162 -20790 -23908 -19007 -17801 -20370 -20252 -19106 -16738 -18725 -18634 -16599 -19381 -18981 -21872 -17104 -16234 -18192 -20502 -17937 -17909 -17773 -18130 -19031 -20644 -19298 -16200 -16429 -18167 -24201 -20282 -16435 -18594 -19187 -16065 -18111 -16268 -21446 -16779 -18540 -17119 -23480 -18502 -19747 -21377 -20751 -18604 -17935 -18557 -17903 -16424 -18425 -23713 -15368 -17354 -18116 -18825 -22344 -17781 -17093 -17993 -17586 -21133 -17000 -18843 -16642 -15529 -19568 -14114 -22694 -20560 -17700 -23137 -20738 -17467 -16895 -16278 -19559 -22336 -19566 -17530 -14687 -15503 -16365 -18991 -20710 -18632 -19347 -20064 -12895 -17908 -20499 -20232 -18532 -18894 -14958 -19778 -14777 -18632 -21658 -22747 -19172 -16852 -16682 -15707 -17624 -25477 -18438 -21099 -19159 -18560 -24555 -16503 -19368 -21750 -13935 -16901 -20132 -15960 -19615 -17469 -18509 -19240 -18762 -17774 -18176 -18624 -17216 -20681 -19754 -16869 -20465 -16785 -22210 -18893 -23388 -20442 -19553 -17061 -21621 -21538 -15406 -18797 -19660 -18624 -17347 -16286 -21750 -19050 -18814 -20648 -16630 -20479 -16697 -14345 -21930 -16325 -24172 -16444 -20610 -16221 -15417 -19202 -21336 -19381 -17328 -20504 -17960 -15825 -18105 -17465 -19524 -19800 -21495 -19104 -17883 -20593 -20993 -21763 -18509 -18308 -16468 -20615 -16098 -21733 -15426 -15208 -19354 -21043 -19978 -19420 -15849 -18365 -16951 -15293 -18169 -18792 -12908 -19248 -18559 -16650 -16229 -21123 -23888 -17351 -18588 -19095 -14820 -20305 -19101 -23144 -20521 -17669 -15497 -19334 -14784 -15168 -18038 -17835 -19059 -19540 -16734 -19132 -19243 -17260 -20620 -19603 -19982 -18933 -19517 -19830 -18461 -19708 -16562 -16673 -16362 -15278 -17055 -22601 -20679 -23484 -16174 -19559 -19223 -18387 -21343 -18510 -16705 -15324 -18109 -18204 -22341 -18171 -15761 -20611 -22297 -17081 -16708 -16597 -19457 -19324 -17398 -19049 -18730 -20074 -23014 -17118 -22867 -16641 -16708 -17573 -13479 -19377 -20116 -20942 -13638 -20113 -17688 -20853 -18358 -17738 -16930 -20729 -17968 -18050 -15188 -19371 -24926 -20079 -15094 -18067 -17565 -18741 -20405 -13587 -18740 -19233 -20281 -19997 -15136 -17006 -18441 -21244 -21287 -19142 -17289 -16932 -16790 -19228 -14778 -17861 -18397 -17601 -16161 -17778 -19534 -19504 -16070 -21766 -14759 -19577 -17631 -18692 -21239 -17196 -23499 -18022 -21281 -17398 -15851 -20719 -20189 -16935 -16433 -20840 -25691 -19193 -22197 -20551 -20946 -15531 -14637 -16195 -16812 -17975 -19112 -19197 -17087 -19168 -21382 -19100 -19188 -23627 -20286 -14536 -17569 -20977 -19664 -16440 -17748 -15781 -16671 -20399 -15069 -15838 -22193 -19315 -22071 -23851 -18458 -17633 -17913 -16248 -20010 -15347 -21755 -19578 -17328 -19105 -16658 -14776 -24389 -20068 -16764 -20155 -23332 -19261 -17212 -22702 -19257 -18639 -16950 -20813 -15162 -19337 -16919 -20543 -20682 -21338 -18171 -15594 -19679 -14721 -18932 -17341 -16517 -21361 -17270 -16256 -20409 -18227 -21305 -18691 -17965 -19033 -21304 -16578 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_0.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_0.pt deleted file mode 100644 index aa407d4a51a27c3a92a496369a6710ea13f17fa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_1.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_1.pt deleted file mode 100644 index bbd6803e30eadc4c13999785b6a3567b3b5b6a39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 diff --git a/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_2.pt b/examples/benchmarks/theory/experiments/results/n200_evenly_spread/k5/trained_ddqn/best_seed_2.pt deleted file mode 100644 index f82b5983d5217b753b3383ee453cd143807d911e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 CYpgf` diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/dqn.txt deleted file mode 100644 index 380a975e7..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1437 -979 -669 -941 -1008 -1088 -1332 -1192 -928 -1198 -1791 -891 -929 -1599 -561 -997 -877 -926 -870 -1627 -1186 -1321 -1433 -976 -1160 -1375 -1123 -1359 -807 -846 -1036 -1132 -1234 -1470 -1370 -812 -1249 -1075 -916 -1383 -1128 -904 -1599 -1458 -1214 -1412 -587 -711 -1029 -650 -1169 -1042 -1312 -1250 -1125 -1270 -908 -852 -1199 -1574 -822 -1143 -967 -899 -1597 -985 -838 -987 -976 -570 -769 -763 -1512 -632 -1251 -1204 -500 -793 -912 -1253 -1466 -1442 -1479 -1386 -962 -727 -968 -1324 -1309 -827 -1172 -1059 -1287 -818 -1138 -1058 -1510 -1044 -993 -1284 -1617 -753 -1029 -1181 -823 -912 -941 -790 -1479 -1020 -922 -1482 -738 -1101 -1121 -855 -786 -1155 -846 -963 -1294 -963 -1507 -1286 -728 -1448 -1250 -1093 -1140 -1177 -1361 -689 -805 -1061 -1285 -618 -924 -1118 -1100 -965 -1127 -758 -1482 -609 -668 -753 -1237 -887 -896 -927 -1198 -1525 -1058 -1206 -760 -748 -774 -1260 -773 -1051 -1233 -1049 -915 -866 -1544 -1014 -549 -1591 -616 -838 -622 -1228 -770 -1011 -645 -993 -1189 -1180 -924 -1471 -1151 -1154 -999 -648 -791 -1180 -1202 -1128 -1020 -653 -1205 -1131 -1201 -775 -1136 -925 -1036 -795 -839 -1269 -1158 -847 -1030 -974 -1272 -1226 -957 -1107 -923 -844 -789 -1062 -1190 -748 -1036 -1126 -1201 -1303 -564 -1305 -1481 -932 -1287 -1371 -1065 -1497 -1078 -856 -836 -1635 -421 -1222 -962 -1095 -803 -1050 -1192 -1576 -1080 -784 -1382 -1618 -950 -927 -757 -1058 -799 -1085 -641 -884 -1446 -725 -1593 -805 -754 -1129 -809 -1058 -1194 -864 -776 -1211 -1183 -857 -890 -1258 -1064 -965 -1118 -976 -996 -1499 -786 -722 -924 -1313 -1270 -835 -1410 -614 -1207 -1160 -1160 -1502 -831 -1112 -1093 -1187 -661 -858 -617 -1125 -686 -986 -1181 -1199 -723 -1179 -1192 -1441 -833 -1515 -1493 -1173 -1141 -1512 -1599 -1537 -853 -1011 -757 -1153 -1030 -1137 -571 -1363 -689 -769 -1057 -1214 -863 -998 -751 -673 -1059 -789 -1265 -563 -1263 -716 -851 -1222 -1062 -1210 -1318 -1164 -974 -1288 -1280 -728 -1213 -1022 -1291 -1647 -1224 -747 -882 -805 -951 -998 -987 -1232 -1165 -1110 -986 -1278 -926 -834 -544 -667 -804 -1248 -1262 -837 -732 -1087 -1118 -1598 -1161 -834 -954 -1336 -1090 -1023 -460 -918 -1331 -789 -1320 -640 -767 -945 -1083 -912 -1124 -977 -1047 -764 -761 -1372 -1191 -626 -1680 -1286 -1066 -1062 -976 -816 -1302 -1015 -1129 -793 -1228 -1479 -1062 -465 -1017 -1132 -1084 -1351 -1166 -1086 -583 -1028 -807 -1261 -1396 -1786 -1350 -1317 -832 -840 -604 -1686 -1064 -1234 -713 -951 -957 -1052 -1174 -839 -1310 -817 -1131 -662 -1449 -887 -1024 -763 -967 -933 -1001 -930 -862 -883 -957 -1312 -1563 -713 -942 -1735 -1074 -1189 -853 -747 -1194 -832 -987 -998 -1071 -1036 -1603 -663 -733 -673 -1671 -1025 -754 -859 -780 -1204 -753 -1223 -1262 -1014 -1317 -1197 -1621 -1444 -740 -900 -642 -1141 -847 -930 -1068 -1062 -653 -1040 -1127 -443 -1044 -1141 -1041 -1109 -822 -1512 -1041 -913 -932 -1481 -1297 -822 -840 -944 -917 -1258 -1161 -867 -943 -1682 -963 -821 -1169 -1233 -1135 -1016 -1033 -922 -1098 -648 -799 -1446 -1292 -804 -822 -749 -922 -976 -988 -1833 -680 -1023 -1405 -1474 -1037 -1161 -777 -1159 -1331 -1271 -1172 -1115 -1069 -987 -862 -1143 -835 -1185 -1350 -795 -964 -1029 -1464 -827 -1229 -1133 -935 -914 -985 -1083 -767 -1404 -892 -1362 -695 -848 -1367 -1375 -1084 -1401 -876 -1585 -1262 -1026 -1006 -1124 -1044 -668 -838 -955 -1007 -1155 -1018 -1149 -1568 -1240 -1233 -860 -944 -836 -1138 -1058 -1183 -846 -1139 -1210 -908 -1107 -1015 -1082 -1062 -1066 -805 -1431 -839 -1328 -954 -1050 -1286 -877 -1066 -1100 -841 -1290 -1226 -1029 -1343 -829 -980 -919 -1058 -627 -904 -1006 -1131 -761 -1405 -773 -553 -975 -1370 -1264 -1034 -912 -1000 -1538 -646 -799 -1005 -1672 -1661 -818 -834 -1327 -791 -794 -1396 -1575 -932 -1756 -954 -1155 -1163 -938 -811 -722 -611 -1316 -561 -936 -950 -827 -1226 -1081 -1395 -957 -869 -981 -1104 -979 -1170 -961 -1363 -904 -984 -946 -1116 -960 -996 -1158 -1210 -696 -833 -1014 -1104 -1541 -738 -732 -1373 -1006 -1197 -973 -556 -751 -738 -1423 -697 -1086 -799 -1304 -1061 -1054 -1048 -1201 -1027 -841 -1148 -711 -782 -783 -896 -1056 -1035 -1291 -940 -1131 -1109 -1012 -679 -1323 -1088 -749 -1331 -1479 -749 -862 -846 -923 -969 -871 -1436 -1211 -919 -2073 -927 -1526 -1265 -982 -693 -1355 -1119 -865 -717 -670 -1241 -856 -911 -1138 -993 -1700 -844 -1019 -944 -1281 -1274 -1001 -946 -1186 -1292 -994 -1120 -1457 -841 -847 -1281 -890 -935 -823 -658 -1398 -1406 -1343 -958 -1031 -1638 -1036 -1129 -950 -776 -1487 -819 -1560 -703 -666 -560 -888 -822 -790 -1448 -543 -1096 -1250 -826 -621 -1632 -1011 -918 -1486 -926 -910 -1162 -1171 -972 -1122 -1637 -880 -540 -787 -800 -960 -1024 -1195 -834 -1538 -2095 -1369 -677 -1525 -355 -794 -1098 -1452 -840 -913 -882 -969 -1484 -1373 -1542 -1436 -711 -1026 -1044 -1689 -797 -1364 -1037 -1108 -990 -1034 -1035 -925 -1311 -838 -800 -1415 -1136 -734 -992 -1082 -1036 -742 -1298 -943 -1004 -959 -968 -999 -887 -877 -942 -1087 -910 -626 -685 -1325 -974 -1425 -936 -1344 -790 -576 -596 -755 -949 -1053 -1172 -1120 -375 -955 -1468 -738 -931 -946 -810 -1153 -875 -753 -1045 -966 -1672 -1429 -943 -529 -788 -1394 -1342 -1611 -705 -924 -724 -1169 -1075 -859 -837 -1035 -771 -1025 -1520 -1139 -1544 -926 -899 -842 -1023 -1572 -1131 -947 -496 -1061 -764 -992 -674 -956 -599 -1175 -1027 -1471 -700 -1574 -536 -1002 -849 -1761 -1070 -973 -807 -921 -827 -620 -1437 -1411 -746 -1154 -1010 -772 -810 -1410 -1183 -1283 -1301 -784 -936 -1200 -878 -1147 -1405 -1284 -906 -1497 -1022 -839 -805 -1083 -964 -694 -1464 -890 -1181 -809 -889 -1504 -697 -1115 -1333 -933 -979 -1019 -1511 -1398 -783 -1082 -812 -982 -802 -1155 -1062 -955 -963 -703 -875 -1217 -932 -408 -1410 -1127 -957 -860 -1649 -977 -847 -1486 -1013 -916 -808 -1348 -1078 -988 -747 -772 -1444 -1188 -799 -1245 -1019 -569 -792 -1316 -1059 -792 -558 -709 -937 -1201 -807 -854 -1074 -755 -1077 -946 -1017 -930 -879 -1060 -1051 -994 -810 -1176 -1571 -788 -642 -1093 -1213 -1049 -959 -2233 -1102 -697 -1093 -1403 -766 -1141 -1377 -859 -722 -648 -1124 -928 -907 -1459 -1081 -1648 -1266 -790 -1217 -801 -1073 -1170 -854 -1242 -1409 -864 -1539 -1128 -727 -1347 -1342 -951 -743 -1285 -1095 -1026 -872 -738 -943 -1286 -1103 -1003 -1212 -704 -1133 -611 -881 -1153 -1758 -1015 -645 -795 -999 -874 -1365 -1128 -1198 -1246 -1192 -1193 -1105 -1222 -1642 -1232 -753 -1445 -1247 -1146 -1115 -1388 -879 -900 -1254 -980 -962 -1078 -1089 -763 -880 -556 -972 -840 -948 -600 -862 -799 -942 -1100 -728 -990 -994 -1228 -1389 -1338 -1008 -1822 -1461 -831 -897 -1004 -982 -889 -869 -1250 -1592 -752 -1058 -1164 -1472 -1029 -720 -1680 -1524 -1255 -1213 -857 -1154 -915 -1079 -1327 -884 -822 -1113 -788 -1217 -1186 -1194 -878 -1378 -974 -963 -983 -1235 -1159 -1197 -1344 -1061 -818 -831 -1213 -986 -570 -795 -1069 -1034 -1001 -885 -1084 -1088 -1433 -1020 -1123 -1378 -953 -1105 -737 -1136 -832 -375 -1039 -954 -1683 -1195 -1306 -954 -1263 -1563 -973 -1062 -902 -1775 -858 -1001 -1121 -734 -838 -617 -769 -869 -865 -1011 -883 -899 -977 -791 -1150 -1642 -986 -926 -1040 -979 -897 -1171 -1066 -1397 -569 -1279 -1609 -1093 -937 -1171 -635 -590 -868 -584 -838 -1814 -1390 -972 -913 -835 -976 -717 -1231 -901 -1111 -916 -829 -1436 -867 -1080 -743 -943 -891 -1058 -1391 -817 -1529 -1467 -1190 -656 -1084 -756 -692 -1506 -844 -858 -1087 -680 -1399 -1375 -1158 -1487 -1430 -991 -564 -1321 -982 -1179 -837 -746 -977 -1351 -792 -1108 -1404 -1159 -705 -982 -881 -1345 -832 -1244 -881 -866 -591 -1463 -988 -935 -1288 -1377 -770 -1245 -1054 -984 -922 -1121 -1215 -1042 -1216 -666 -843 -871 -1606 -747 -626 -451 -1045 -1338 -1361 -1812 -846 -1523 -1091 -1386 -1401 -945 -1172 -1346 -1482 -1104 -805 -714 -1332 -1275 -651 -1187 -948 -991 -1325 -1295 -1263 -1030 -1322 -1254 -882 -1068 -801 -660 -1679 -862 -929 -1207 -801 -1403 -849 -865 -958 -918 -1156 -648 -870 -1326 -1325 -1280 -1314 -1003 -753 -941 -1122 -1259 -1240 -1128 -929 -743 -1056 -1239 -997 -921 -707 -1175 -770 -1176 -1194 -947 -939 -882 -1027 -1460 -1004 -925 -907 -775 -956 -2212 -867 -541 -1771 -785 -915 -1334 -621 -429 -1136 -884 -516 -896 -1149 -978 -1013 -929 -1336 -689 -874 -873 -667 -1057 -790 -669 -983 -1559 -835 -782 -1088 -1116 -670 -1073 -876 -1055 -1240 -1137 -1346 -1392 -696 -738 -845 -780 -989 -1495 -697 -1037 -1021 -683 -925 -1338 -548 -1604 -1455 -1338 -663 -567 -957 -1053 -1144 -806 -1446 -1254 -1049 -867 -1342 -513 -835 -1367 -946 -1107 -1021 -1194 -862 -827 -1327 -1032 -762 -1057 -1102 -1338 -1075 -879 -1323 -914 -1457 -900 -1180 -1603 -1267 -597 -1333 -1065 -1464 -1310 -623 -1360 -2043 -976 -972 -749 -1069 -986 -915 -614 -589 -1047 -1132 -1082 -1276 -841 -863 -946 -1076 -1053 -904 -1126 -916 -1114 -1031 -1680 -983 -1023 -1026 -667 -1180 -1027 -1262 -1030 -1059 -991 -646 -825 -731 -1312 -775 -852 -1305 -722 -598 -820 -927 -1370 -1020 -1645 -1041 -1030 -544 -1031 -992 -783 -1050 -748 -1306 -970 -1182 -912 -1179 -1742 -545 -1006 -1232 -1083 -775 -1471 -827 -1032 -842 -632 -891 -876 -1029 -1217 -926 -1075 -839 -763 -924 -996 -761 -898 -1056 -1054 -887 -904 -976 -1378 -1133 -1229 -868 -1089 -942 -877 -743 -738 -686 -776 -593 -924 -895 -1097 -1243 -718 -1261 -874 -1050 -801 -884 -1198 -1259 -592 -751 -946 -574 -957 -936 -877 -874 -862 -1102 -965 -1657 -911 -877 -642 -1126 -1373 -1025 -681 -1175 -1425 -658 -1560 -957 -807 -823 -1037 -1003 -738 -1176 -1390 -838 -1192 -1302 -881 -985 -1780 -1185 -931 -1078 -508 -1179 -1380 -938 -1080 -506 -1326 -570 -596 -1313 -1115 -1123 -1656 -753 -1452 -1522 -780 -973 -936 -1356 -1258 -1320 -1835 -1425 -1157 -1309 -1119 -671 -861 -1107 -851 -1030 -1064 -1169 -1173 -1340 -761 -1236 -1461 -1507 -1075 -1028 -735 -1387 -356 -662 -992 -954 -1042 -873 -778 -1570 -1361 -1047 -788 -1235 -934 -1177 -1313 -771 -568 -1043 -968 -664 -1067 -1101 -1234 -814 -1242 -1039 -905 -460 -998 -798 -1576 -750 -1137 -1602 -674 -1307 -915 -715 -409 -1104 -762 -1404 -580 -1080 -719 -1284 -1084 -793 -1077 -1107 -815 -875 -952 -1670 -1224 -1233 -961 -913 -1156 -1189 -896 -975 -648 -1107 -1230 -901 -681 -1256 -1109 -876 -900 -1017 -1042 -688 -822 -796 -1048 -1465 -676 -1524 -916 -897 -1358 -1563 -1015 -642 -969 -1247 -931 -869 -1219 -1024 -1161 -887 -919 -1288 -672 -1280 -900 -904 -1564 -968 -1261 -573 -677 -1448 -1589 -1240 -932 -803 -978 -1372 -732 -1002 -1328 -781 -1201 -637 -1042 -922 -1344 -1025 -873 -605 -1029 -629 -744 -941 -980 -727 -891 -1027 -925 -606 -742 -1565 -510 -979 -943 -1385 -1323 -1051 -806 -879 -961 -1489 -992 -1116 -620 -1266 -1152 -1524 -1333 -841 -824 -1150 -1088 -1553 -1153 -1271 -1256 -769 -1125 -1228 -1133 -903 -738 -1053 -618 -912 -992 -1072 -1038 -1039 -1102 -1099 -1527 -1089 -675 -1102 -988 -990 -935 -1165 -1096 -921 -698 -801 -1139 -850 -695 -1059 -812 -1233 -1059 -1171 -1155 -1065 -1102 -941 -808 -620 -839 -1685 -1273 -713 -960 -872 -1077 -1236 -1154 -1187 -1244 -656 -1441 -932 -1119 -901 -815 -1213 -1007 -991 -1268 -1556 -1405 -1036 -1057 -938 -1095 -997 -1062 -1166 -1403 -1098 -1089 -1074 -964 -889 -946 -927 -620 -1123 -1301 -1097 -837 -725 -740 -674 -1278 -1028 -1002 -809 -1316 -647 -977 -1044 -903 -654 -1286 -1083 -1096 -749 -1460 -1134 -775 -713 -867 -1529 -950 -946 -1069 -1574 -816 -1043 -834 -1184 -727 -1940 -789 -1165 -931 -1846 -1261 -1149 -912 -1188 -1377 -849 -1218 -960 -1605 -1156 -1212 -613 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/optimal.txt deleted file mode 100644 index 04e898db8..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1552 -1273 -1312 -1535 -1278 -801 -1744 -1192 -1362 -747 -1014 -1068 -1059 -1145 -1968 -1489 -558 -727 -1107 -1211 -479 -1228 -1388 -1136 -760 -1085 -1068 -1214 -1509 -881 -1332 -1059 -670 -1085 -846 -1551 -1102 -1534 -1420 -605 -707 -1629 -758 -806 -803 -1412 -1103 -1187 -971 -1316 -1408 -752 -1153 -1394 -776 -1085 -736 -1134 -990 -679 -953 -880 -1009 -1311 -847 -865 -1045 -529 -735 -523 -744 -976 -928 -935 -673 -1452 -1223 -1017 -1396 -1413 -928 -1115 -1343 -890 -962 -1302 -1321 -1790 -1192 -1116 -1173 -829 -1122 -834 -1018 -991 -881 -1062 -859 -727 -1220 -648 -959 -1042 -792 -981 -565 -1057 -997 -959 -724 -1084 -1264 -1102 -852 -1144 -1339 -969 -783 -777 -745 -825 -707 -1116 -728 -1107 -788 -805 -1406 -1047 -938 -686 -1023 -911 -889 -941 -1159 -874 -798 -906 -1123 -649 -1257 -718 -909 -1185 -677 -1110 -880 -967 -1233 -1157 -993 -1088 -1135 -1136 -485 -1453 -1206 -1211 -1053 -821 -1917 -890 -1168 -839 -874 -1271 -1064 -1122 -583 -1183 -907 -1391 -812 -861 -1354 -1140 -1179 -1209 -587 -447 -954 -718 -1090 -977 -1416 -1007 -1175 -689 -1760 -1109 -1199 -853 -1366 -925 -738 -1104 -1115 -1439 -701 -920 -565 -1261 -783 -1208 -885 -1317 -956 -1071 -1365 -1307 -1071 -1683 -604 -729 -707 -982 -850 -816 -1446 -958 -1293 -846 -857 -1058 -1196 -892 -1069 -842 -817 -1265 -988 -629 -1171 -1184 -955 -621 -707 -654 -1002 -1348 -909 -1026 -863 -1192 -1265 -854 -998 -743 -1166 -642 -1454 -1246 -980 -817 -705 -662 -594 -824 -1139 -1004 -835 -809 -1176 -1058 -1323 -623 -1088 -759 -659 -1499 -1130 -912 -1080 -855 -1589 -701 -1211 -1062 -1617 -939 -937 -919 -511 -1234 -1463 -1187 -1364 -1024 -617 -1103 -642 -566 -1253 -917 -1328 -899 -1507 -1023 -1214 -1515 -615 -680 -1579 -1256 -1069 -829 -925 -949 -747 -1166 -877 -856 -445 -673 -985 -1160 -1081 -1431 -1241 -1287 -751 -878 -1047 -1387 -889 -1572 -870 -667 -1297 -1461 -1252 -1120 -762 -1217 -858 -866 -879 -1267 -740 -816 -831 -724 -1169 -562 -672 -1305 -1404 -1166 -1070 -784 -685 -644 -808 -735 -573 -822 -1172 -986 -1031 -843 -1018 -1220 -1430 -1379 -839 -826 -614 -1146 -1054 -942 -1090 -676 -816 -772 -1177 -702 -1027 -962 -670 -1229 -816 -1267 -934 -1395 -709 -764 -1200 -1146 -1130 -942 -1021 -680 -1558 -1031 -955 -1116 -863 -905 -829 -1215 -1077 -611 -906 -1162 -932 -906 -796 -977 -909 -826 -583 -670 -1059 -898 -830 -1187 -683 -1317 -1331 -1015 -952 -884 -912 -1425 -1187 -982 -868 -879 -1477 -825 -930 -905 -724 -662 -992 -851 -1024 -1152 -988 -861 -881 -1319 -647 -640 -1238 -982 -1300 -1337 -995 -1011 -1279 -1119 -863 -1170 -1159 -952 -707 -1096 -704 -1091 -1273 -967 -1247 -1192 -1044 -888 -1339 -1474 -1105 -1202 -1303 -1123 -1377 -1516 -1002 -854 -834 -1173 -1488 -975 -868 -800 -1226 -1513 -916 -1782 -640 -1184 -1056 -1104 -1345 -586 -1083 -1048 -956 -1794 -923 -824 -902 -1046 -1409 -1285 -1243 -818 -1515 -898 -792 -934 -980 -975 -1335 -986 -1555 -1092 -1554 -1045 -831 -1602 -1007 -802 -1250 -1383 -759 -996 -1243 -781 -1080 -1273 -994 -733 -1142 -728 -868 -759 -1156 -1280 -1209 -731 -1221 -1642 -826 -1414 -938 -372 -1478 -1300 -1147 -998 -958 -1491 -1386 -1433 -1018 -1194 -899 -1124 -790 -1056 -1256 -1404 -1050 -1166 -1109 -1015 -984 -1067 -892 -924 -778 -1073 -723 -1503 -804 -1193 -1213 -947 -976 -798 -1298 -655 -947 -962 -570 -798 -906 -901 -1399 -627 -1789 -1666 -1118 -1604 -1170 -805 -443 -1001 -1413 -1306 -1020 -1169 -1104 -1334 -985 -635 -1160 -1281 -986 -755 -1069 -933 -1506 -1230 -790 -1675 -1008 -1058 -660 -864 -1062 -1469 -1190 -1342 -1020 -1273 -1204 -1163 -1003 -886 -1191 -1064 -828 -943 -877 -930 -1050 -1020 -1061 -923 -966 -1388 -1050 -944 -1439 -1144 -1551 -1425 -1189 -1154 -423 -459 -1315 -639 -1330 -1034 -1113 -1043 -946 -748 -899 -1203 -1199 -887 -1111 -1380 -1112 -1087 -910 -830 -800 -1352 -756 -917 -588 -1066 -944 -1840 -1191 -1207 -798 -1429 -1303 -1197 -605 -909 -698 -1135 -738 -1152 -905 -1167 -956 -944 -1084 -927 -970 -993 -918 -791 -1466 -949 -831 -805 -1133 -1162 -875 -819 -1172 -711 -985 -633 -1325 -879 -740 -945 -1010 -763 -1288 -824 -1164 -928 -1464 -1261 -1014 -1516 -749 -1284 -646 -736 -1028 -530 -892 -870 -1228 -1355 -774 -1514 -925 -1186 -1376 -1361 -1177 -820 -974 -1092 -1332 -1006 -1015 -1159 -1321 -1101 -618 -664 -913 -1108 -1336 -838 -1308 -411 -747 -1157 -1048 -1290 -1371 -1405 -1163 -735 -803 -691 -1638 -1147 -976 -1206 -628 -1334 -582 -1093 -1052 -1303 -1206 -940 -932 -1570 -735 -886 -913 -907 -762 -613 -1121 -712 -1459 -923 -1009 -980 -950 -592 -1619 -1305 -569 -876 -1450 -563 -1415 -692 -1280 -1090 -530 -1277 -473 -1362 -1294 -1462 -1065 -1492 -1078 -863 -1118 -855 -355 -895 -877 -1190 -1154 -896 -966 -527 -1399 -807 -1092 -974 -1168 -541 -1318 -828 -955 -972 -953 -1066 -1128 -1169 -1126 -1021 -866 -1296 -1358 -991 -1080 -1323 -877 -576 -1079 -654 -623 -1175 -971 -979 -1067 -587 -887 -934 -1134 -941 -877 -903 -924 -983 -974 -1020 -1222 -1517 -930 -792 -938 -1169 -1723 -1238 -1389 -1100 -375 -875 -1236 -1075 -1172 -660 -1870 -582 -1899 -1144 -1098 -1215 -1261 -655 -749 -957 -910 -1371 -1012 -1121 -1389 -1120 -1048 -760 -1204 -1584 -762 -597 -1581 -822 -1163 -1338 -1184 -958 -846 -907 -1054 -744 -1284 -1469 -1569 -1129 -580 -1387 -958 -669 -825 -1518 -1027 -916 -781 -1110 -909 -1486 -849 -760 -874 -1233 -1325 -1041 -1081 -1201 -921 -1042 -988 -1051 -1846 -1281 -879 -806 -834 -1485 -809 -796 -1055 -1099 -779 -590 -833 -846 -720 -1053 -1195 -797 -1031 -1323 -1186 -605 -735 -469 -862 -991 -757 -1160 -881 -1448 -1177 -824 -892 -1031 -959 -1206 -735 -1307 -925 -1140 -1082 -749 -938 -1094 -1299 -1331 -1187 -453 -831 -1251 -787 -1131 -1056 -621 -1205 -717 -1271 -1000 -1293 -986 -1253 -1116 -1756 -1100 -1248 -1072 -1211 -1064 -822 -1200 -1200 -834 -1224 -1003 -1006 -1258 -1229 -952 -1282 -438 -816 -977 -1512 -884 -826 -1359 -1293 -1026 -1289 -1397 -1081 -1006 -810 -765 -755 -897 -1096 -1399 -1158 -1122 -539 -978 -790 -919 -1156 -1011 -1028 -1482 -1152 -950 -937 -1344 -867 -1044 -647 -748 -912 -1482 -1132 -733 -995 -1163 -1200 -934 -1143 -956 -760 -816 -1302 -951 -634 -1070 -853 -528 -916 -1192 -1099 -966 -932 -1860 -1118 -920 -1055 -1229 -1182 -1442 -751 -484 -1340 -975 -1177 -867 -521 -1310 -602 -774 -1005 -1006 -1256 -1184 -1182 -699 -1288 -909 -997 -1378 -852 -1219 -1246 -1343 -808 -1476 -927 -899 -1173 -842 -784 -1004 -857 -989 -1428 -728 -1208 -958 -782 -1001 -736 -1107 -1119 -960 -1564 -1066 -957 -923 -1400 -700 -1074 -1168 -771 -1162 -1271 -1017 -951 -959 -629 -887 -1148 -887 -1431 -1076 -1682 -1035 -1144 -952 -1312 -1018 -968 -910 -1312 -1374 -781 -1553 -912 -1291 -1105 -788 -1199 -1224 -1153 -756 -973 -830 -887 -953 -1386 -381 -904 -1624 -1178 -903 -1198 -946 -992 -1062 -1155 -1761 -1400 -691 -886 -1611 -1352 -684 -887 -1428 -1088 -1110 -687 -767 -1498 -1063 -1282 -1018 -1442 -1683 -1269 -1320 -924 -1089 -755 -1039 -1188 -775 -988 -926 -1117 -1720 -803 -1057 -795 -739 -1200 -885 -1258 -826 -815 -943 -1453 -802 -1039 -936 -880 -1964 -912 -897 -1192 -1066 -631 -1158 -1230 -1593 -799 -1125 -950 -1267 -823 -846 -1096 -1025 -1120 -1328 -1050 -1029 -642 -984 -1223 -1119 -572 -936 -941 -1031 -1098 -1175 -1236 -1111 -906 -1231 -884 -781 -817 -841 -1058 -876 -1088 -1293 -756 -796 -813 -1091 -858 -1417 -1184 -869 -739 -1432 -930 -1611 -806 -1615 -1365 -916 -1115 -1187 -718 -1089 -1198 -1110 -1060 -1115 -1435 -1052 -1255 -684 -900 -854 -834 -723 -847 -963 -1423 -655 -1080 -1149 -1040 -892 -1212 -998 -1659 -1100 -1289 -1205 -568 -1647 -1014 -1054 -1486 -955 -1040 -1333 -802 -1045 -759 -1318 -1173 -730 -1050 -1472 -888 -826 -726 -1180 -556 -1202 -1659 -906 -1161 -1355 -1012 -813 -861 -1045 -852 -593 -620 -794 -869 -939 -1181 -714 -922 -1576 -1045 -1067 -1096 -1347 -1007 -611 -961 -978 -1039 -1506 -1533 -1062 -1058 -795 -1838 -907 -965 -1493 -1073 -1115 -1139 -747 -932 -968 -1226 -1039 -743 -1204 -1386 -1241 -817 -707 -1175 -1225 -880 -893 -687 -1094 -1047 -1065 -1094 -680 -931 -1326 -720 -885 -571 -1017 -1521 -1270 -879 -965 -1072 -1299 -910 -958 -1353 -1212 -620 -800 -1199 -1482 -913 -865 -1033 -724 -1214 -1439 -855 -1163 -1115 -650 -1369 -835 -877 -792 -629 -1187 -1225 -1257 -970 -816 -1268 -911 -1131 -1392 -1087 -894 -495 -976 -779 -895 -799 -724 -892 -641 -982 -956 -1407 -877 -1790 -680 -1446 -1342 -406 -914 -1436 -485 -1214 -1098 -925 -1119 -1323 -808 -837 -1433 -1280 -1288 -1013 -1637 -1140 -1050 -906 -779 -1071 -1355 -790 -1107 -1371 -1491 -1150 -1120 -890 -970 -726 -777 -1015 -1603 -899 -1075 -1181 -979 -978 -1436 -583 -991 -956 -646 -1365 -1038 -945 -1197 -760 -1243 -901 -1023 -1576 -1110 -542 -769 -1252 -967 -608 -937 -848 -703 -1183 -1052 -781 -986 -689 -994 -1106 -1033 -866 -1199 -930 -914 -1501 -1224 -1098 -1161 -1277 -752 -505 -1037 -820 -702 -1011 -765 -807 -1096 -1025 -911 -902 -1056 -1076 -855 -780 -1171 -768 -808 -1148 -1318 -959 -954 -1106 -823 -835 -1091 -1091 -1133 -1741 -1200 -918 -1119 -961 -702 -622 -1086 -677 -910 -835 -887 -1051 -831 -1084 -1812 -1758 -1094 -1178 -1286 -941 -814 -1327 -1129 -848 -882 -1177 -647 -1520 -1414 -776 -991 -804 -1015 -1271 -1461 -1563 -1150 -473 -800 -799 -624 -946 -1200 -1759 -1046 -958 -712 -957 -1096 -798 -800 -1136 -1001 -1478 -1086 -752 -1150 -1171 -1203 -582 -612 -925 -905 -1203 -998 -922 -1067 -691 -1450 -841 -1258 -796 -1266 -1228 -1014 -844 -1153 -1046 -656 -1060 -911 -1583 -820 -669 -1242 -1141 -1241 -682 -934 -1075 -1012 -553 -1242 -1236 -1270 -906 -1055 -1356 -1383 -1099 -1142 -1178 -893 -837 -1439 -1564 -1698 -1156 -941 -1472 -671 -822 -1107 -851 -1109 -947 -1395 -1064 -1139 -526 -1012 -1119 -1018 -1697 -1393 -1000 -1387 -729 -683 -1281 -1239 -564 -746 -1598 -841 -976 -1634 -1252 -801 -818 -1275 -708 -926 -812 -782 -1151 -1418 -1109 -827 -1256 -971 -652 -1013 -1373 -1047 -929 -375 -1576 -750 -1032 -1090 -1026 -660 -1680 -1169 -990 -870 -1383 -1155 -1287 -1196 -852 -750 -723 -999 -1088 -1679 -914 -588 -1077 -701 -805 -767 -899 -897 -1126 -1535 -1040 -1005 -1609 -858 -973 -1182 -819 -817 -1064 -973 -1421 -890 -1175 -1526 -1098 -1613 -774 -1273 -610 -1484 -800 -1239 -1125 -1135 -1138 -1201 -648 -915 -1021 -785 -879 -986 -931 -1532 -1042 -1195 -1490 -1042 -973 -816 -783 -1198 -1041 -1878 -1086 -1045 -836 -973 -579 -1313 -964 -834 -941 -1302 -1285 -664 -624 -1024 -777 -1135 -738 -1153 -817 -1489 -1730 -926 -841 -1016 -771 -727 -997 -1191 -893 -1056 -1111 -706 -1619 -1166 -1113 -506 -775 -884 -1070 -814 -861 -685 -888 -1362 -1438 -1057 -1023 -1373 -858 -747 -950 -1427 -1406 -1388 -1046 -1520 -1039 -1096 -1719 -628 -1274 -762 -1080 -997 -687 -1216 -1624 -1072 -886 -678 -1298 -1239 -1105 -1176 -1294 -869 -908 -819 -1135 -1344 -1377 -762 -976 -1192 -1023 -1143 -1215 -1576 -893 -1130 -1004 -921 -695 -450 -1297 -1061 -1367 -1473 -875 -1220 -1462 -1137 -974 -609 -957 -996 -838 -1187 -891 -932 -1548 -1325 -1096 -1247 -1461 -783 -1304 -1259 -968 -949 -721 -903 -956 -1122 -997 -1215 -1062 -879 -1518 -889 -1116 -603 -964 -676 -801 -767 -529 -1124 -1377 -906 -1035 -576 -1330 -895 -929 -706 -1031 -1213 -941 -1319 -1079 -1157 -1146 -809 -1112 -806 -1066 -941 -753 -1555 -1728 -711 -773 -1684 -1127 -797 -549 -1391 -835 -1372 -1087 -1184 -1078 -1138 -882 -1264 -1111 -849 -1202 -1349 -736 -447 -923 -823 -1098 -1162 -575 -832 -719 -1004 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/random.txt deleted file mode 100644 index 5f64548ce..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -8512 -6344 -7788 -8042 -6075 -10743 -12657 -9014 -9849 -7830 -9782 -7619 -7009 -6014 -9885 -7997 -10202 -7788 -6386 -5687 -9007 -9011 -5783 -10279 -6791 -9276 -5665 -8628 -6601 -8562 -6078 -6260 -13748 -7034 -12770 -11496 -9593 -4886 -8181 -6642 -7839 -6140 -5497 -8647 -7667 -10185 -9337 -5229 -8117 -8475 -6703 -7402 -10343 -13547 -8459 -6463 -5918 -10705 -4838 -11622 -7252 -11165 -6556 -7836 -6977 -9939 -9560 -8850 -7421 -5481 -11862 -10224 -9124 -5402 -10726 -10469 -6232 -7491 -9556 -10198 -8530 -7229 -7893 -8180 -10603 -8384 -9114 -5837 -6241 -11209 -10184 -9926 -7903 -8361 -10184 -6665 -8449 -10617 -7243 -10600 -7528 -4526 -9402 -9768 -8927 -12786 -10066 -9659 -5054 -7892 -9743 -5546 -9285 -8467 -10057 -12463 -7836 -10448 -10168 -4162 -6798 -8407 -6711 -9761 -3213 -8616 -11780 -9462 -9642 -7276 -8204 -6966 -6165 -9765 -6542 -6979 -9527 -7917 -7864 -7397 -11914 -4047 -10310 -7019 -11402 -7618 -5242 -7122 -7919 -14349 -6873 -10656 -7989 -8014 -11652 -8891 -4579 -6054 -7325 -11322 -8815 -8731 -10297 -6972 -6148 -7021 -4717 -7433 -12318 -7444 -7837 -5335 -9458 -6331 -5864 -5129 -6721 -9322 -10132 -7846 -12319 -9128 -5894 -7119 -10313 -10274 -8318 -6808 -12952 -5892 -7911 -10668 -5123 -4714 -9290 -7194 -7879 -9153 -7761 -8908 -6957 -7521 -8462 -5293 -9747 -7752 -7513 -11764 -11780 -13787 -5130 -6700 -8106 -8239 -8107 -7246 -11404 -9012 -7247 -7303 -5453 -6819 -8425 -7148 -8147 -5504 -6744 -11280 -8995 -5987 -4893 -6821 -8414 -5588 -8739 -8559 -10164 -5295 -4764 -6727 -8091 -8991 -7891 -11160 -11647 -7348 -3799 -8673 -9638 -8585 -9313 -6494 -8135 -8652 -4291 -8087 -4391 -3838 -6892 -7675 -6570 -5278 -6373 -13681 -9015 -8547 -8744 -11646 -7388 -5937 -7480 -11745 -10631 -8142 -9925 -17135 -7861 -10231 -4927 -14823 -9712 -12512 -8216 -6943 -12399 -10094 -3871 -5864 -8135 -8254 -7134 -10004 -6028 -10505 -10905 -9401 -6616 -10575 -5016 -4348 -9989 -6524 -9580 -8284 -10193 -10712 -8889 -8797 -5599 -7029 -9210 -8616 -12980 -7958 -6518 -7811 -11192 -12340 -6334 -6089 -7145 -9973 -11221 -11459 -6569 -13318 -8542 -4347 -7885 -7350 -7608 -7864 -8104 -8804 -8744 -6543 -8268 -5091 -11765 -9983 -7186 -6494 -4404 -11710 -9031 -8013 -8079 -13458 -8019 -5176 -5651 -9475 -7931 -8214 -7974 -13918 -7305 -8959 -11243 -9290 -9054 -12809 -6967 -6089 -11763 -8331 -5840 -10722 -7842 -7563 -9418 -11542 -8494 -8183 -12754 -7675 -11310 -9461 -9238 -7616 -5938 -9120 -6229 -8806 -8616 -6948 -7035 -5496 -6012 -6771 -7752 -9248 -4752 -5243 -7477 -6995 -10783 -7379 -4958 -11916 -14960 -8895 -13530 -8444 -9431 -6345 -9733 -10036 -12676 -10129 -7640 -10258 -7387 -10675 -7773 -6460 -8064 -10963 -9715 -11861 -14410 -6572 -6856 -8381 -12322 -7548 -3565 -8079 -7127 -9911 -14419 -4179 -9306 -6805 -5259 -9046 -5960 -6652 -7514 -9696 -6726 -7149 -5012 -10023 -8555 -7726 -10453 -10477 -12197 -13055 -10034 -7262 -7822 -8259 -8701 -8850 -8291 -6150 -10176 -8419 -8787 -9511 -6542 -10843 -7409 -11798 -6197 -11270 -7110 -12467 -10458 -18016 -5192 -6207 -8763 -10562 -6740 -5606 -5299 -7973 -7099 -6090 -11643 -5703 -10976 -7902 -10076 -6672 -7071 -11837 -7658 -11189 -10424 -4243 -5388 -9352 -5915 -9857 -10427 -9895 -8852 -5856 -8542 -8905 -5510 -3252 -7407 -5831 -8739 -9358 -8957 -8029 -13170 -8028 -9897 -6963 -8974 -12882 -12826 -8959 -7666 -9061 -6492 -7284 -6563 -8450 -11714 -7101 -5779 -12248 -11201 -8684 -4188 -5614 -5620 -7453 -9082 -6854 -6651 -6944 -7435 -9796 -7080 -8466 -6866 -8252 -12883 -9006 -8568 -7392 -3757 -13878 -10354 -9720 -12439 -9250 -6739 -7978 -9743 -9649 -9610 -7408 -4778 -6620 -12750 -8687 -9026 -3259 -11779 -8467 -9809 -7267 -8755 -10002 -8527 -9298 -6446 -10235 -7165 -12394 -14522 -5924 -7959 -9814 -5289 -6155 -9330 -4591 -10257 -5937 -6796 -10876 -7611 -8964 -9167 -4580 -9906 -8781 -11831 -7139 -9593 -5972 -8603 -7834 -6544 -7387 -10644 -12709 -6533 -13672 -8730 -9752 -7623 -7769 -10061 -6413 -13900 -11747 -7115 -11638 -8783 -8272 -6585 -11685 -5650 -8629 -6036 -7579 -6436 -10574 -5285 -14595 -8056 -7971 -8652 -12038 -9180 -9033 -10708 -8506 -7802 -9963 -11822 -13205 -12666 -8683 -7305 -8543 -11526 -11116 -8251 -10788 -10280 -6869 -9878 -5917 -5323 -8594 -7565 -5835 -7134 -8153 -4060 -8705 -14140 -5290 -7993 -6462 -10215 -6843 -7629 -7847 -8700 -10753 -11225 -9675 -17139 -11405 -11258 -5689 -8349 -7948 -7232 -7267 -11933 -9044 -7372 -7763 -9205 -13670 -9710 -7480 -6230 -12528 -9439 -11309 -6189 -10854 -9908 -8580 -10542 -9741 -6540 -11260 -7631 -6489 -10077 -12346 -7697 -7098 -12039 -9318 -9630 -9057 -6332 -7751 -8621 -7094 -5875 -12564 -10167 -5520 -8690 -8955 -5828 -9607 -7840 -9142 -6799 -9007 -8636 -14601 -12548 -9822 -8800 -8234 -11737 -12587 -10693 -6284 -6548 -13733 -7740 -7682 -11369 -6886 -10427 -11132 -9584 -8020 -6878 -11865 -5509 -7556 -9126 -11790 -5541 -7260 -9813 -7447 -9480 -6233 -10625 -7177 -7154 -11903 -7977 -10856 -6123 -10272 -6591 -3904 -9619 -7519 -6693 -7806 -6448 -10661 -8715 -7734 -7216 -9276 -11987 -9718 -6458 -6246 -7078 -7688 -9835 -8903 -8916 -11343 -10109 -7452 -7200 -8138 -12145 -7482 -7873 -9098 -8046 -5891 -10981 -7411 -9361 -11343 -10823 -8617 -9082 -6746 -4425 -7532 -12873 -7101 -9044 -6556 -9711 -6329 -12656 -6780 -12857 -10370 -9315 -9660 -8722 -9790 -8750 -6305 -6512 -10531 -6727 -4309 -9839 -5906 -6348 -5851 -10076 -6658 -4275 -10246 -9452 -8641 -6536 -7357 -7881 -10719 -9279 -8291 -11415 -8787 -10164 -16183 -9079 -7350 -10343 -10915 -5700 -14560 -10063 -6842 -11882 -13466 -6562 -8933 -6693 -13077 -9562 -4719 -7052 -6260 -6897 -8711 -7567 -9109 -11620 -9183 -9840 -7449 -12483 -6817 -6045 -12005 -7199 -9177 -10051 -11609 -8874 -4489 -9769 -6452 -8006 -8049 -5804 -6610 -7980 -9064 -9663 -9526 -6447 -9188 -9096 -9874 -5606 -10879 -6763 -10815 -9580 -9164 -7059 -7953 -10631 -12751 -9061 -10957 -5822 -10922 -6981 -9832 -5908 -7715 -8510 -9378 -11723 -7226 -8256 -5998 -13197 -8478 -12761 -13988 -10789 -4563 -8934 -8070 -9637 -10008 -8589 -10268 -10116 -15727 -10422 -10162 -9667 -8703 -7472 -9339 -3590 -15011 -5758 -12817 -10385 -6433 -6653 -11808 -5544 -16600 -9859 -12596 -9518 -12616 -5446 -9934 -4382 -8210 -7423 -7325 -11465 -9254 -8078 -7809 -8546 -6271 -10848 -8772 -9584 -6628 -8489 -6811 -7661 -7715 -12858 -8951 -9651 -9592 -8041 -9849 -9201 -9414 -6045 -5303 -15480 -10565 -7169 -6682 -10523 -7653 -17319 -7610 -10120 -14369 -5662 -9207 -10442 -9875 -10420 -8477 -14185 -9239 -10057 -4034 -7436 -11879 -7974 -8214 -8042 -9888 -8511 -6883 -8708 -8149 -8347 -6748 -6178 -6805 -8912 -11218 -5697 -8615 -7980 -8584 -7255 -9826 -10276 -14919 -6855 -6989 -8307 -6355 -9300 -8141 -3018 -5787 -10215 -6638 -13640 -7234 -6223 -10957 -12104 -8106 -8795 -5128 -3972 -10101 -5396 -8533 -7790 -9002 -10467 -7331 -4027 -5806 -12581 -8525 -11069 -12212 -11400 -5767 -10304 -5442 -6778 -6788 -9021 -12541 -10793 -7225 -14628 -8972 -6621 -5558 -6224 -8450 -7324 -6076 -7532 -9731 -13457 -8043 -12236 -4952 -6933 -7657 -9132 -8559 -8154 -7735 -6713 -8178 -9614 -7952 -11935 -6587 -12889 -6424 -13250 -10243 -8591 -10689 -9131 -6842 -6987 -8965 -8838 -7158 -5857 -7391 -13199 -5830 -9888 -9100 -12604 -6474 -8657 -10749 -11584 -7311 -15546 -4340 -6541 -12607 -12326 -5004 -7919 -13646 -7587 -11163 -15300 -7194 -6121 -4151 -9695 -7081 -11684 -10137 -8349 -9596 -6399 -5977 -5835 -8737 -7607 -10110 -6170 -7862 -5831 -7437 -7031 -8982 -10969 -8227 -8653 -9603 -9011 -4524 -10115 -14626 -6380 -9598 -3050 -8395 -10223 -9172 -9863 -5240 -6073 -8727 -9265 -9099 -7675 -5118 -9240 -8108 -9869 -8164 -10305 -9530 -14520 -8744 -6931 -9843 -6735 -8873 -4996 -9759 -7905 -10004 -5421 -9559 -10544 -7125 -9564 -7708 -6915 -5657 -9982 -12524 -10566 -14032 -11004 -6665 -7807 -10670 -6604 -7993 -6511 -9030 -8008 -7913 -7578 -4219 -9113 -8382 -6623 -9442 -7529 -7184 -14379 -7339 -7313 -7689 -6027 -7953 -9265 -12829 -6546 -9374 -13657 -13722 -8097 -8709 -5015 -7747 -6516 -6424 -6079 -10738 -8883 -6934 -8533 -8093 -7387 -13972 -6198 -4611 -5944 -13122 -7636 -5625 -7752 -11162 -10167 -10184 -5072 -7785 -5423 -13370 -8241 -9293 -5283 -9780 -7060 -10688 -9885 -7262 -11628 -12409 -10070 -10711 -10997 -7201 -12824 -11470 -6179 -5386 -3873 -9690 -5987 -7982 -9470 -11966 -11276 -7732 -6832 -5852 -8607 -13219 -11052 -9509 -14987 -6113 -6138 -7314 -6240 -5611 -5806 -7519 -5560 -11066 -9691 -11064 -9507 -9628 -5457 -11992 -4955 -5801 -5490 -11211 -14192 -6925 -5938 -10146 -12708 -9610 -7670 -8336 -8942 -12742 -11209 -11141 -7356 -4593 -11143 -9828 -11596 -10918 -9309 -12083 -7798 -7440 -11508 -9773 -6531 -8495 -9351 -4874 -6916 -5695 -6686 -6939 -6808 -6524 -6966 -8430 -10390 -7469 -6807 -9733 -13607 -10270 -7019 -8022 -8196 -9467 -6786 -11241 -7570 -7695 -8388 -7680 -6806 -8901 -9078 -8817 -8834 -9610 -13563 -8490 -5477 -6856 -6803 -14244 -6109 -9799 -5592 -8700 -13795 -8533 -10230 -10239 -9798 -5017 -8032 -10314 -9771 -8337 -5300 -7021 -7831 -8302 -8118 -8977 -4114 -8281 -6913 -5272 -8560 -9214 -10730 -7865 -7914 -6096 -7089 -14138 -6451 -8105 -7391 -10590 -8619 -8811 -8825 -5417 -15253 -8666 -9462 -4885 -8547 -10479 -10701 -6579 -6704 -10049 -12019 -5569 -9666 -8581 -9623 -8036 -8090 -8982 -11328 -7974 -13227 -7476 -14470 -11688 -5827 -7490 -12281 -9262 -8264 -6804 -4551 -7642 -7493 -14932 -6656 -13021 -10251 -5291 -8608 -12784 -5910 -5860 -9576 -11497 -13371 -8015 -8921 -12412 -10331 -7500 -6225 -7897 -5344 -7611 -8218 -9699 -8421 -13418 -7160 -10119 -9190 -11507 -10856 -7535 -6851 -4893 -6197 -6206 -7127 -10820 -9249 -8329 -8117 -5959 -9398 -11435 -6569 -10589 -9198 -10955 -6173 -6330 -6949 -11014 -12186 -6349 -7567 -10890 -12810 -11926 -7683 -9076 -11079 -9713 -9150 -9335 -5732 -8598 -5673 -9144 -10851 -12915 -14021 -11064 -7253 -6829 -6158 -8666 -3977 -12671 -7535 -6667 -11873 -10826 -8929 -5673 -9644 -7919 -10330 -9510 -6023 -6781 -3853 -6578 -8049 -3346 -8370 -7214 -5840 -7387 -16503 -6332 -15856 -10145 -12512 -11285 -5908 -8831 -11429 -7169 -4403 -6328 -5864 -11061 -7405 -8735 -5569 -7883 -5972 -10040 -8125 -12044 -8963 -10032 -7621 -8476 -5820 -5943 -8785 -11499 -10319 -9530 -7817 -9840 -10055 -7594 -8681 -7946 -8334 -8334 -10209 -4833 -5169 -10007 -10567 -10947 -9956 -7284 -3795 -5482 -4700 -7011 -6912 -6278 -9668 -9093 -7804 -10648 -5628 -7676 -6849 -7882 -11000 -6094 -11836 -7878 -13447 -9530 -5075 -8750 -7164 -8071 -12100 -10199 -10534 -7523 -7706 -8254 -9178 -9140 -6679 -5323 -6112 -6360 -6766 -5768 -6792 -5134 -12005 -5639 -12655 -9821 -9421 -7011 -19943 -4903 -7715 -8405 -9644 -8959 -5503 -15025 -12604 -9925 -2269 -6413 -9205 -8048 -7377 -13010 -9117 -8501 -5834 -6891 -5373 -7792 -9882 -8323 -5841 -8787 -8606 -11077 -8359 -13527 -7864 -10890 -9315 -5703 -11557 -3976 -7947 -2592 -10016 -6450 -7954 -7017 -6424 -5531 -8889 -8105 -7407 -8848 -5789 -8478 -10246 -10340 -8047 -7142 -9069 -8788 -5281 -6839 -3954 -7776 -9645 -5000 -10052 -7505 -10851 -11323 -9168 -5883 -10704 -8718 -7382 -6063 -7423 -8325 -10144 -7393 -7538 -12826 -7348 -6898 -9655 -10203 -14139 -8178 -5078 -10718 -10339 -5326 -10228 -9880 -4795 -8846 -9407 -5327 -8958 -9287 -3623 -8478 -8870 -7435 -5970 -10602 -5916 -6284 -6360 -6734 -11600 -9032 -7500 -9633 -5588 -9330 -11341 -7945 -3661 -3635 -8500 -7876 -7871 -6840 -5164 -4325 -5354 -2164 -4540 -7321 -10274 -3768 -8671 -11751 -10141 -4958 -11795 -5486 -8255 -5219 -9918 -6648 -9789 -8298 -5100 -9601 -9800 -3073 -9634 -8953 -8501 -7097 -7245 -9970 -9556 -8987 -6321 -5418 -8585 -9262 -3794 -9755 -6587 -13312 -3605 -6814 -8426 -8113 -8284 -10283 -8647 -7272 -8932 -5816 -6619 -9486 -12526 -6529 -10013 -5552 -11138 -12273 -6907 -10366 -11269 -8142 -6410 -5749 -8116 -12956 -6027 -12617 -4387 -5816 -10424 -8330 -8915 -6832 -6397 -8011 -11180 -7585 -5490 -12242 -6619 -8513 -8083 -9877 -9942 -7413 -9824 -9116 -4873 -10060 -10203 -9198 -7309 -8665 -9843 -7594 -6363 -7760 -8602 -9758 -6698 -8344 -7359 -8575 -10128 -5462 -10640 -5017 -10117 -7941 -12890 -11459 -7822 -8044 -7315 -9655 -5289 -8176 -7112 -6414 -5818 -7180 -7123 -5864 -5898 -10857 -5572 -6918 -6001 -4981 -9830 -11436 -14791 -10945 -6471 -9667 -11127 -8855 -3276 -8162 -9783 -5636 -8665 -8245 -4662 -5639 -6776 -6455 -10316 -9183 -6247 -10785 -7616 -8104 -7194 -12407 -12448 -3857 -7762 -10760 -6870 -4770 -6298 -10250 -4968 -7920 -11287 -5719 -6952 -14746 -5694 -9639 -9411 -8478 -9727 -10841 -11851 -12771 -11309 -9688 -4594 -8622 -6544 -11929 -10753 -9925 -5971 -8124 -11930 -11260 -7978 -13249 -9349 -5520 -6195 -8863 -7804 -8473 -9451 -6318 -5451 -8661 -5106 -8694 -9886 -6721 -5861 -5046 -6403 -8808 -9268 -5791 -6726 -9766 -7333 -12942 -6378 -6223 -10775 -10488 -8125 -7251 -10235 -7104 -12095 -7528 -3702 -10698 -8137 -12396 -7103 -9284 -7089 -8032 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/best.pt deleted file mode 100644 index 231ac6eed39600fa59903e4f38e5db167c0382f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14871 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

!`nehY?O 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 AO8@`> diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/config.yml deleted file mode 100644 index 81626f0ff..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k10/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 6, 11, 16, 21, 26, 31, 36, 41, 46] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/dqn.txt deleted file mode 100644 index bb8eb862c..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1137 -1035 -1145 -1157 -1039 -1137 -1171 -814 -1126 -1354 -924 -914 -857 -516 -1293 -1177 -898 -933 -840 -937 -1091 -894 -784 -716 -863 -1628 -1325 -1122 -1413 -1088 -828 -830 -654 -1261 -1069 -841 -795 -1240 -938 -1135 -840 -803 -1397 -1173 -1147 -916 -1151 -738 -902 -1313 -1354 -1207 -802 -1253 -1283 -1052 -1170 -804 -492 -770 -883 -1049 -1165 -1093 -864 -956 -919 -486 -1172 -1442 -946 -1257 -884 -782 -1100 -926 -921 -930 -667 -1283 -977 -916 -644 -977 -923 -947 -828 -852 -827 -751 -486 -979 -508 -265 -761 -1236 -790 -1144 -1303 -1283 -909 -688 -1249 -1344 -1269 -714 -1466 -731 -988 -1457 -948 -667 -569 -1032 -987 -1391 -794 -738 -714 -930 -1180 -834 -1122 -833 -1124 -979 -624 -1789 -994 -873 -1450 -1152 -650 -1127 -713 -1110 -1372 -632 -1225 -651 -716 -1000 -748 -1276 -1211 -989 -1028 -1017 -856 -1351 -768 -1097 -1158 -1149 -814 -770 -898 -1405 -699 -806 -1147 -1159 -915 -550 -1114 -1196 -969 -969 -999 -816 -1238 -943 -1269 -837 -960 -858 -981 -963 -985 -1139 -893 -893 -894 -880 -963 -1174 -1227 -1050 -729 -968 -959 -1291 -898 -938 -1033 -905 -765 -1618 -1037 -1551 -1357 -752 -873 -1248 -804 -692 -1036 -955 -1348 -879 -1023 -1217 -833 -707 -955 -1137 -794 -1633 -994 -959 -1268 -1016 -891 -630 -1072 -867 -1546 -1334 -882 -1137 -852 -774 -815 -1102 -1044 -1031 -850 -1305 -1088 -1065 -859 -1181 -1303 -861 -1267 -886 -679 -1145 -911 -1065 -888 -828 -573 -1120 -1443 -1209 -538 -1813 -1136 -612 -833 -1061 -1067 -1198 -861 -937 -612 -965 -668 -869 -1167 -1066 -1023 -617 -926 -1098 -627 -1449 -864 -532 -1157 -1220 -1143 -1492 -1195 -857 -862 -1529 -1059 -615 -1411 -754 -853 -1057 -701 -1117 -931 -984 -1025 -1136 -874 -1288 -1101 -940 -1453 -897 -1033 -811 -784 -1175 -867 -1165 -1240 -1171 -1301 -1035 -820 -1278 -845 -1022 -946 -841 -898 -1067 -818 -1237 -1324 -1136 -1002 -812 -1412 -867 -832 -1082 -795 -1028 -1346 -1176 -760 -1011 -925 -999 -817 -1155 -868 -935 -1298 -990 -625 -855 -1273 -1086 -1058 -1103 -624 -1162 -1293 -1110 -1003 -1073 -726 -746 -787 -987 -1221 -845 -1031 -849 -1295 -801 -949 -982 -1233 -1163 -785 -1099 -502 -620 -985 -701 -1323 -1530 -1053 -1507 -1239 -1180 -1228 -1053 -546 -518 -439 -1301 -1886 -907 -873 -1363 -1491 -1191 -968 -799 -670 -948 -947 -818 -619 -1416 -1054 -1105 -1257 -1459 -809 -1257 -950 -1414 -1624 -851 -1023 -673 -1426 -1045 -1404 -928 -735 -1408 -562 -1340 -1121 -1229 -974 -1575 -1232 -972 -1174 -612 -1138 -872 -705 -513 -2187 -1021 -895 -1325 -1456 -1143 -1161 -655 -1023 -981 -950 -1127 -984 -1003 -1051 -943 -904 -1051 -824 -1303 -1242 -773 -877 -1243 -811 -494 -1351 -631 -1105 -863 -1216 -798 -1267 -1005 -718 -1004 -907 -1007 -937 -1247 -1328 -1404 -775 -477 -728 -1159 -1311 -1488 -1694 -1431 -1469 -768 -1153 -1286 -1290 -378 -928 -963 -1309 -947 -990 -722 -735 -1549 -1299 -723 -1036 -821 -1163 -1202 -808 -1134 -1008 -1241 -1102 -1038 -817 -1306 -1147 -745 -1189 -862 -815 -1011 -921 -1195 -841 -1335 -994 -1174 -1184 -1058 -1005 -681 -639 -956 -896 -1245 -787 -939 -879 -1101 -821 -1024 -1207 -1211 -1148 -768 -546 -1753 -1618 -859 -1054 -1028 -1181 -957 -1163 -1308 -1010 -410 -1251 -1056 -1603 -516 -964 -1590 -1429 -898 -1146 -702 -1353 -1101 -1525 -664 -836 -1191 -623 -1112 -1029 -746 -1215 -878 -651 -677 -849 -1151 -738 -1506 -841 -1560 -1199 -1511 -1315 -886 -1374 -941 -1809 -1214 -602 -1180 -918 -1573 -1002 -952 -838 -1185 -1029 -920 -1432 -955 -1457 -1090 -888 -1272 -1193 -906 -1008 -1327 -1629 -1181 -780 -1213 -1219 -1092 -1152 -1177 -1097 -618 -685 -1208 -669 -1290 -1310 -1021 -1275 -842 -908 -831 -1217 -1512 -877 -1011 -932 -1003 -1060 -1187 -953 -1086 -745 -831 -1206 -1162 -877 -1053 -793 -750 -1169 -978 -1131 -1211 -1480 -629 -883 -893 -1198 -1195 -738 -833 -1173 -1536 -869 -891 -710 -1559 -966 -1099 -1225 -692 -1080 -1260 -1020 -976 -991 -1431 -1136 -838 -924 -1195 -944 -710 -877 -771 -1007 -1083 -1315 -1157 -1302 -1086 -757 -1243 -730 -1052 -1101 -886 -813 -1080 -1349 -898 -1446 -686 -752 -685 -983 -639 -1100 -935 -1234 -905 -750 -1064 -959 -1383 -1179 -1094 -842 -637 -1498 -862 -859 -575 -1034 -718 -1573 -764 -1128 -1089 -1076 -922 -906 -942 -1421 -696 -710 -687 -933 -959 -968 -1206 -851 -882 -942 -1440 -920 -608 -1129 -925 -749 -531 -993 -1421 -1236 -1491 -750 -1123 -622 -1078 -898 -1405 -754 -1075 -1007 -588 -1314 -1387 -948 -884 -563 -987 -1048 -1016 -869 -996 -826 -995 -1133 -773 -967 -991 -1221 -1160 -936 -1165 -1006 -1269 -1112 -483 -1165 -1005 -1258 -983 -748 -1075 -787 -620 -997 -818 -1086 -864 -617 -1032 -1440 -947 -1016 -705 -1009 -1305 -815 -1079 -820 -824 -726 -568 -986 -1245 -1041 -979 -732 -602 -991 -947 -939 -732 -971 -1240 -1042 -1074 -1035 -1197 -743 -1135 -890 -1202 -1377 -809 -1413 -941 -1028 -1369 -1130 -845 -1148 -940 -1423 -941 -1330 -1376 -952 -1393 -944 -960 -1074 -1381 -1253 -939 -810 -476 -948 -1010 -927 -1049 -988 -786 -1060 -1058 -1102 -1409 -1050 -720 -914 -1568 -1073 -831 -1125 -1417 -904 -971 -759 -1525 -732 -1011 -712 -1174 -1018 -1066 -1188 -1178 -1315 -1301 -931 -990 -705 -707 -876 -1193 -1171 -913 -1402 -1157 -729 -1195 -1080 -879 -1799 -1458 -1019 -1065 -885 -1000 -900 -659 -1337 -1443 -1249 -1041 -797 -924 -1568 -998 -1578 -978 -1166 -861 -757 -939 -1233 -650 -1250 -833 -627 -1414 -859 -739 -1193 -739 -845 -788 -994 -1285 -920 -1081 -1271 -895 -956 -1095 -858 -1175 -994 -1022 -1130 -1246 -872 -975 -1061 -830 -671 -971 -774 -939 -1338 -888 -1418 -903 -648 -601 -920 -1008 -847 -697 -974 -774 -878 -903 -978 -1060 -958 -1074 -1098 -720 -1058 -743 -1099 -841 -1362 -1007 -869 -730 -822 -812 -930 -1074 -1235 -645 -1348 -381 -466 -991 -921 -1140 -791 -904 -794 -1282 -807 -1002 -731 -1071 -762 -1185 -749 -971 -736 -840 -920 -719 -1174 -837 -907 -820 -1236 -808 -944 -1156 -674 -833 -969 -1017 -1177 -1121 -1185 -886 -773 -1002 -834 -729 -1119 -966 -1105 -862 -1089 -1055 -1072 -1135 -1345 -1663 -875 -887 -1299 -1097 -1396 -1161 -631 -778 -1040 -822 -890 -1046 -986 -1102 -1150 -1158 -1456 -1302 -1003 -1412 -571 -502 -766 -619 -1378 -1529 -949 -988 -961 -894 -563 -688 -962 -978 -1329 -1275 -1139 -796 -1082 -662 -1151 -1066 -1001 -808 -645 -1286 -1147 -1159 -956 -1028 -1346 -893 -822 -1013 -1028 -953 -980 -1099 -1006 -1105 -1535 -862 -864 -977 -864 -1094 -1129 -809 -781 -685 -684 -1116 -927 -1046 -968 -551 -1005 -629 -1548 -1165 -775 -1060 -1401 -870 -825 -565 -980 -950 -1039 -1104 -875 -778 -1183 -926 -655 -1240 -829 -1094 -664 -972 -805 -895 -996 -1150 -945 -1316 -1247 -540 -847 -1211 -1383 -925 -697 -1023 -1770 -901 -1161 -1109 -892 -1479 -917 -943 -825 -980 -938 -1379 -1231 -1594 -1169 -983 -1294 -1324 -646 -1270 -838 -696 -575 -1248 -771 -625 -1243 -1269 -687 -784 -1143 -1161 -1422 -747 -914 -915 -702 -1182 -1110 -753 -990 -1168 -1106 -877 -1188 -616 -847 -1032 -886 -651 -864 -1107 -1208 -926 -853 -917 -1297 -810 -737 -676 -1234 -652 -1014 -1392 -1257 -1137 -839 -1061 -878 -1378 -1043 -1750 -1061 -996 -966 -1074 -1423 -1204 -1317 -903 -1193 -610 -1052 -897 -824 -912 -670 -770 -1664 -977 -661 -1069 -1540 -1137 -650 -780 -1006 -909 -1235 -1192 -989 -1188 -1120 -781 -973 -858 -1083 -939 -705 -1273 -1244 -950 -999 -737 -1256 -1033 -921 -722 -1186 -982 -1967 -1088 -1164 -1361 -1039 -890 -679 -1291 -1145 -962 -965 -1346 -1348 -1028 -1200 -962 -787 -877 -936 -1048 -1105 -899 -1311 -855 -870 -1002 -1348 -971 -788 -1547 -1128 -1170 -861 -603 -1085 -1033 -725 -915 -823 -463 -701 -701 -1470 -891 -1085 -1605 -705 -1229 -1102 -794 -1300 -1034 -920 -1223 -1203 -834 -1126 -775 -1245 -651 -1447 -1484 -905 -977 -1012 -1811 -688 -983 -1169 -1418 -1618 -1069 -919 -1424 -783 -796 -883 -631 -1127 -1022 -1296 -590 -649 -1171 -958 -810 -962 -1889 -1170 -1243 -1153 -940 -923 -1338 -788 -665 -614 -875 -1059 -725 -766 -812 -790 -817 -909 -541 -1185 -1046 -550 -1005 -824 -1324 -972 -1019 -1129 -1196 -739 -946 -931 -502 -987 -1230 -546 -916 -794 -920 -792 -992 -911 -1046 -1406 -1034 -818 -696 -735 -822 -702 -622 -1250 -994 -823 -686 -1274 -728 -1269 -1074 -938 -809 -1006 -778 -895 -902 -844 -744 -587 -1186 -717 -985 -799 -696 -1011 -792 -970 -1001 -1031 -805 -948 -610 -1714 -841 -1005 -1101 -1087 -982 -959 -854 -920 -1392 -1379 -1154 -928 -1199 -1132 -497 -532 -772 -725 -1071 -688 -1069 -1933 -764 -977 -1045 -1481 -1106 -1007 -658 -1200 -1054 -1087 -1073 -989 -1078 -1060 -1418 -876 -846 -846 -599 -1590 -1097 -649 -849 -889 -1012 -603 -713 -907 -1167 -1324 -874 -893 -762 -1161 -874 -643 -529 -1006 -767 -959 -1102 -769 -1179 -1094 -766 -1543 -670 -1216 -1292 -1303 -1122 -506 -1317 -1145 -1070 -979 -1034 -1218 -622 -726 -1287 -1128 -664 -1240 -792 -511 -1465 -1641 -1228 -990 -901 -1228 -1032 -1065 -592 -740 -784 -954 -952 -1193 -794 -1267 -878 -737 -1336 -906 -1795 -878 -1264 -672 -1155 -723 -1102 -1343 -1488 -1009 -674 -970 -976 -1697 -1093 -943 -659 -1019 -722 -1458 -1112 -893 -1149 -1292 -894 -1214 -1145 -1429 -931 -1320 -1525 -861 -718 -912 -1052 -1215 -1509 -1593 -845 -948 -1146 -1206 -701 -501 -728 -1243 -1055 -996 -912 -1051 -947 -896 -851 -1279 -1063 -1242 -777 -817 -1173 -931 -1003 -896 -1184 -1320 -965 -964 -1298 -660 -787 -850 -368 -1699 -1265 -651 -1516 -1234 -1024 -809 -805 -949 -1213 -976 -1392 -1696 -743 -736 -1600 -942 -433 -1494 -1228 -1038 -1080 -1252 -523 -1132 -804 -1070 -658 -865 -816 -835 -850 -1096 -739 -1056 -1203 -893 -1338 -1383 -1258 -1630 -730 -1405 -1285 -781 -835 -830 -825 -1461 -1665 -748 -834 -778 -905 -955 -1077 -1171 -987 -1053 -796 -1157 -1087 -1125 -1470 -889 -642 -900 -718 -634 -890 -1162 -1292 -957 -1223 -773 -837 -839 -1038 -630 -1274 -551 -729 -939 -584 -800 -980 -1010 -1196 -953 -920 -934 -1134 -798 -1023 -891 -1003 -955 -1467 -1072 -1310 -750 -1079 -932 -582 -1266 -1155 -816 -987 -1013 -1285 -927 -1201 -1243 -786 -1139 -1174 -1577 -895 -1259 -1031 -1222 -1553 -946 -670 -1093 -661 -903 -1081 -1445 -749 -1140 -1133 -1163 -696 -781 -1033 -498 -1335 -712 -1385 -880 -781 -734 -1247 -803 -625 -859 -1072 -700 -765 -1240 -1298 -720 -1151 -897 -1396 -938 -1143 -1212 -849 -305 -993 -1211 -565 -1167 -1046 -1230 -847 -1140 -1321 -1048 -1448 -1152 -753 -881 -793 -1367 -1295 -593 -960 -1401 -1763 -703 -603 -781 -870 -1360 -748 -1102 -543 -1311 -1079 -888 -1254 -1243 -1053 -1084 -965 -937 -1344 -1600 -1293 -997 -1105 -549 -1251 -1386 -823 -1227 -1339 -1641 -1004 -895 -1019 -1053 -1249 -1110 -968 -1505 -1022 -1042 -734 -680 -1226 -644 -865 -691 -756 -956 -1445 -728 -1000 -628 -883 -1065 -1344 -1305 -964 -1636 -959 -1151 -908 -1310 -1051 -1051 -698 -709 -1005 -1349 -1133 -941 -774 -1384 -1164 -485 -1041 -1132 -819 -657 -1135 -808 -1304 -745 -899 -805 -830 -982 -1414 -1057 -1030 -519 -770 -1303 -1011 -985 -1100 -1376 -849 -1004 -1127 -413 -1016 -1191 -847 -890 -538 -1194 -1242 -1766 -1007 -1452 -1232 -1471 -1155 -892 -995 -777 -1299 -666 -901 -1006 -706 -1071 -611 -1204 -1109 -828 -877 -1046 -700 -1399 -1400 -1077 -915 -1123 -885 -1255 -1087 -1267 -963 -692 -965 -771 -1467 -1170 -800 -1579 -725 -925 -1163 -798 -603 -1117 -613 -948 -803 -880 -841 -739 -902 -1040 -1124 -632 -1133 -1337 -815 -639 -604 -1014 -1040 -1119 -1248 -692 -1057 -1168 -1047 -1486 -606 -1067 -903 -1000 -1131 -1260 -1129 -1098 -1049 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/optimal.txt deleted file mode 100644 index dcb68a196..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1057 -1038 -918 -1523 -1258 -716 -1028 -799 -815 -649 -785 -852 -923 -1170 -698 -720 -804 -973 -1000 -1014 -729 -852 -727 -863 -1191 -1002 -952 -733 -551 -896 -711 -1076 -836 -603 -908 -1109 -1147 -1112 -967 -1049 -809 -938 -1299 -808 -1318 -771 -664 -1205 -854 -1021 -956 -1215 -1031 -840 -1352 -1019 -969 -1257 -604 -1316 -931 -1253 -835 -742 -1064 -1205 -1298 -1007 -1026 -1096 -1317 -476 -824 -1290 -610 -1240 -1001 -1023 -1165 -987 -1127 -1129 -1028 -1050 -634 -843 -927 -1077 -754 -674 -875 -1667 -1057 -1315 -1483 -825 -1352 -1008 -1172 -981 -694 -556 -1005 -916 -1188 -1428 -908 -907 -859 -770 -1033 -1133 -721 -905 -1072 -980 -1115 -1014 -844 -1162 -767 -566 -800 -1260 -647 -757 -1850 -904 -1003 -1166 -951 -987 -1197 -723 -932 -644 -1495 -1143 -764 -669 -1065 -1048 -1378 -1152 -1229 -1735 -1086 -1150 -733 -1622 -997 -1087 -1176 -1106 -935 -1102 -804 -889 -562 -851 -1258 -938 -943 -1253 -1076 -729 -838 -1388 -1109 -753 -557 -690 -1212 -945 -1000 -1382 -1276 -701 -925 -1276 -543 -959 -594 -1641 -1040 -505 -1186 -1006 -894 -959 -635 -1122 -1619 -489 -1229 -726 -558 -1083 -1008 -972 -773 -634 -1365 -991 -694 -1101 -731 -998 -588 -712 -1291 -639 -712 -1030 -1168 -1295 -1154 -1017 -1248 -731 -973 -867 -1412 -1305 -910 -1035 -1601 -1591 -1099 -861 -914 -707 -1763 -1047 -731 -754 -799 -671 -809 -756 -957 -1079 -558 -1073 -1156 -626 -793 -879 -1008 -1170 -846 -984 -1219 -1128 -1100 -728 -1153 -1278 -620 -950 -773 -1333 -892 -1241 -850 -1138 -683 -1000 -1249 -726 -1093 -1350 -1226 -687 -944 -721 -1141 -985 -698 -889 -759 -1236 -1198 -1844 -784 -983 -1016 -899 -1304 -628 -1411 -1128 -1077 -979 -982 -1250 -870 -758 -1158 -619 -551 -1099 -934 -1030 -1107 -427 -817 -1006 -1104 -1212 -1285 -844 -810 -1189 -1415 -1010 -1461 -561 -988 -889 -832 -692 -898 -1399 -1392 -1042 -716 -1318 -1044 -1056 -770 -1342 -1256 -1100 -779 -656 -1449 -893 -1361 -1189 -953 -1204 -1080 -795 -1203 -482 -1218 -872 -1172 -840 -1232 -783 -1050 -1203 -853 -956 -1430 -809 -994 -1055 -1053 -1050 -842 -695 -963 -1225 -1277 -1013 -1243 -1224 -807 -460 -1132 -673 -1027 -1020 -741 -1277 -1137 -847 -1224 -733 -1342 -767 -1156 -1154 -775 -1161 -691 -1155 -1104 -905 -852 -1052 -1051 -993 -1008 -1015 -1106 -718 -1185 -944 -917 -661 -763 -1735 -921 -736 -1186 -996 -692 -1165 -1230 -891 -1144 -861 -1344 -1057 -1306 -1222 -911 -1054 -936 -979 -835 -870 -949 -732 -884 -1119 -1337 -807 -952 -735 -498 -1542 -783 -682 -482 -837 -912 -1158 -1022 -726 -1269 -725 -708 -926 -1175 -950 -982 -1677 -709 -721 -811 -567 -759 -722 -784 -869 -846 -1048 -678 -964 -971 -818 -769 -1486 -924 -943 -976 -1020 -807 -1016 -1073 -771 -1083 -540 -1059 -820 -704 -943 -1186 -1000 -1026 -807 -1143 -820 -1002 -760 -955 -1157 -1152 -1046 -926 -711 -1084 -1387 -1141 -898 -1357 -1193 -1163 -1572 -1040 -1091 -1236 -1037 -1006 -678 -997 -981 -1246 -1143 -857 -962 -1261 -890 -1656 -1641 -1131 -1191 -1133 -958 -1042 -1044 -1076 -1068 -897 -1227 -1293 -1082 -1182 -1555 -893 -671 -889 -809 -1327 -1236 -1115 -1385 -872 -1544 -639 -1225 -1103 -1023 -1198 -873 -673 -712 -1107 -851 -774 -821 -1147 -1206 -1471 -1671 -923 -1225 -1485 -1327 -1417 -816 -943 -1129 -1308 -1022 -1304 -1027 -1061 -702 -563 -1248 -1012 -932 -839 -1447 -1002 -1120 -914 -1112 -733 -704 -622 -986 -1016 -1619 -586 -956 -975 -694 -1111 -939 -838 -1214 -1021 -1373 -1023 -735 -980 -1672 -1609 -1184 -1279 -1202 -1059 -1327 -1204 -1051 -1346 -445 -575 -807 -659 -813 -1384 -1373 -1080 -1467 -1280 -980 -1529 -1436 -1091 -1058 -1218 -1000 -928 -1247 -1092 -774 -760 -490 -1340 -1115 -1120 -1246 -935 -1125 -1171 -1099 -1257 -786 -1302 -989 -828 -812 -713 -1314 -1124 -832 -1204 -1340 -1026 -1661 -759 -649 -913 -469 -900 -761 -830 -1189 -749 -990 -733 -1005 -931 -809 -964 -1044 -744 -346 -1081 -955 -723 -1273 -680 -771 -1338 -1045 -593 -757 -712 -678 -798 -568 -961 -686 -1307 -985 -954 -739 -1013 -905 -451 -948 -1287 -830 -957 -1359 -470 -1121 -1030 -1003 -858 -1166 -709 -1037 -1287 -951 -889 -1105 -1110 -1027 -883 -1291 -898 -792 -713 -1142 -1198 -735 -776 -860 -1141 -853 -934 -1327 -820 -1157 -692 -524 -802 -995 -984 -1185 -690 -928 -992 -1086 -976 -778 -827 -792 -909 -1538 -1186 -850 -1313 -652 -605 -846 -1161 -1041 -874 -898 -1141 -1024 -1303 -1217 -1521 -1169 -1339 -928 -875 -966 -528 -1173 -1541 -1150 -1383 -1065 -594 -920 -538 -843 -913 -1085 -873 -664 -1708 -711 -912 -705 -1041 -920 -1624 -1056 -959 -953 -946 -581 -1364 -1162 -1196 -1220 -617 -620 -967 -712 -1121 -1157 -916 -1068 -698 -1696 -670 -993 -1066 -1692 -1012 -1228 -1248 -1509 -993 -1078 -906 -813 -1072 -950 -706 -394 -1326 -1152 -1016 -1055 -1150 -1057 -1530 -1610 -915 -685 -1512 -1390 -826 -884 -1200 -1258 -1222 -1255 -1192 -541 -939 -864 -1277 -1623 -563 -664 -1474 -686 -876 -576 -877 -716 -896 -688 -1826 -832 -695 -683 -753 -1487 -1206 -1373 -1178 -596 -863 -1428 -792 -1147 -1176 -971 -767 -1196 -864 -1092 -874 -299 -1322 -1095 -852 -1067 -415 -1383 -1298 -1189 -1138 -1409 -1224 -1658 -1159 -1430 -1300 -886 -847 -983 -1015 -918 -904 -1033 -776 -893 -836 -753 -883 -853 -1322 -1192 -1335 -777 -1046 -994 -1220 -1128 -727 -1198 -973 -1198 -797 -728 -586 -1079 -1013 -799 -875 -657 -1424 -901 -937 -925 -1400 -752 -873 -1376 -1151 -723 -1092 -928 -1274 -910 -1422 -782 -824 -813 -768 -1047 -1345 -1533 -319 -973 -423 -1045 -755 -762 -1143 -1152 -833 -920 -671 -911 -667 -1468 -1192 -810 -653 -1303 -725 -1158 -1102 -845 -1475 -1542 -857 -1151 -1048 -1107 -1132 -947 -537 -1619 -1225 -1580 -699 -1098 -1080 -989 -1155 -890 -475 -741 -1031 -793 -902 -846 -1347 -872 -1044 -745 -926 -886 -966 -1011 -567 -693 -1214 -1205 -1256 -892 -912 -1147 -1019 -703 -828 -1191 -996 -1092 -852 -429 -1390 -923 -1398 -1188 -1154 -764 -1138 -623 -694 -529 -542 -988 -860 -898 -1042 -717 -648 -725 -1259 -960 -1289 -1694 -569 -621 -1401 -905 -579 -728 -694 -1492 -1118 -1206 -1176 -1076 -1181 -1218 -800 -971 -1328 -1155 -1207 -890 -764 -544 -1038 -735 -924 -1255 -546 -830 -767 -1234 -875 -1381 -1688 -936 -745 -1335 -1311 -817 -1172 -1264 -1289 -1126 -862 -1159 -975 -1175 -1310 -975 -960 -1445 -583 -481 -1254 -1008 -1258 -1223 -1005 -1087 -806 -1110 -1099 -1225 -807 -548 -1279 -1150 -792 -608 -1092 -510 -758 -1124 -1021 -1117 -1250 -1208 -1231 -900 -1413 -1270 -968 -677 -1127 -1114 -1045 -927 -1372 -852 -891 -1196 -707 -858 -931 -393 -1336 -528 -918 -957 -1008 -867 -863 -987 -1244 -1133 -508 -1016 -1052 -1104 -703 -953 -693 -720 -862 -418 -1101 -1082 -638 -424 -414 -809 -1025 -926 -1072 -442 -1294 -1483 -592 -1557 -802 -594 -1176 -1007 -910 -986 -907 -1036 -1134 -1452 -1121 -620 -862 -731 -1215 -876 -932 -1035 -998 -838 -1067 -1008 -579 -1119 -1234 -904 -839 -960 -719 -910 -637 -1014 -834 -1280 -1584 -976 -672 -1024 -872 -762 -724 -627 -739 -1897 -1207 -1061 -1425 -922 -1302 -1229 -801 -1144 -1146 -1028 -866 -1272 -953 -1179 -1310 -1390 -724 -1585 -958 -1001 -1139 -1162 -1052 -935 -1196 -1369 -849 -1092 -677 -1475 -1148 -1086 -1268 -1167 -969 -918 -1700 -1025 -1198 -1332 -493 -1038 -943 -1415 -713 -986 -989 -630 -1120 -1241 -1011 -1067 -1139 -1167 -465 -1111 -1108 -848 -1075 -558 -1009 -852 -1141 -1168 -641 -851 -862 -697 -723 -1132 -850 -1405 -1223 -1403 -1019 -964 -1030 -868 -1462 -1344 -923 -769 -1045 -616 -1135 -798 -1064 -779 -1361 -890 -1097 -910 -1384 -817 -801 -1077 -979 -663 -992 -678 -1223 -903 -1130 -767 -870 -1536 -1373 -714 -664 -844 -475 -991 -943 -1234 -1064 -699 -867 -857 -1066 -960 -1130 -1293 -1036 -1218 -1144 -1138 -600 -1172 -1135 -1303 -1026 -937 -1340 -1070 -548 -1055 -809 -1070 -887 -863 -1107 -1069 -1045 -931 -755 -1217 -869 -743 -745 -934 -757 -1512 -1048 -1002 -820 -1047 -843 -461 -1355 -1474 -531 -908 -969 -606 -1644 -807 -1294 -670 -851 -750 -883 -741 -933 -784 -747 -871 -1261 -1248 -879 -997 -618 -686 -747 -939 -867 -987 -717 -992 -1214 -868 -677 -1054 -696 -899 -1217 -1100 -849 -1172 -809 -1205 -1045 -821 -920 -1033 -1088 -775 -1130 -731 -1095 -911 -1816 -1199 -1109 -1330 -1649 -1117 -1380 -1066 -853 -975 -927 -1357 -1125 -1014 -972 -1186 -806 -1312 -761 -1008 -463 -1056 -1120 -808 -905 -712 -827 -916 -729 -699 -1100 -1224 -683 -1138 -653 -800 -911 -619 -1384 -1659 -1226 -752 -945 -717 -1310 -883 -1172 -1278 -890 -463 -882 -1307 -917 -750 -1092 -819 -918 -888 -941 -623 -1319 -1324 -1277 -923 -900 -1060 -1868 -569 -1331 -823 -888 -720 -1054 -649 -918 -847 -803 -728 -938 -1264 -1105 -623 -610 -560 -1363 -1277 -1196 -575 -949 -683 -1112 -1724 -507 -1403 -1143 -784 -1054 -805 -684 -1057 -910 -794 -954 -772 -1205 -1724 -688 -671 -1558 -348 -981 -630 -721 -828 -1417 -1129 -1120 -793 -1443 -863 -1261 -836 -917 -1050 -626 -480 -1581 -1201 -1055 -875 -1333 -739 -756 -1120 -900 -1222 -831 -1093 -1091 -872 -822 -976 -1039 -1180 -895 -1002 -1087 -1440 -879 -732 -1103 -1007 -786 -1004 -1085 -1256 -1036 -1300 -1161 -1285 -1152 -1036 -1370 -1004 -760 -746 -962 -396 -736 -1343 -1221 -599 -872 -1143 -1049 -1429 -1031 -839 -1075 -1063 -1381 -576 -818 -1477 -699 -902 -613 -1270 -645 -824 -854 -715 -1177 -1119 -1345 -1682 -1222 -1136 -892 -985 -592 -1526 -956 -1313 -1063 -955 -902 -1128 -994 -757 -865 -1061 -644 -1098 -1877 -1025 -787 -1589 -897 -768 -1321 -1416 -861 -1035 -1257 -878 -1031 -722 -655 -718 -883 -691 -926 -814 -849 -1330 -766 -779 -890 -951 -1315 -524 -813 -965 -696 -1347 -889 -739 -823 -1040 -873 -740 -839 -859 -526 -1111 -1307 -1266 -847 -1059 -1201 -1252 -821 -1044 -793 -731 -863 -1025 -908 -792 -1204 -1457 -728 -568 -900 -1008 -715 -848 -911 -1086 -1230 -1423 -648 -783 -1232 -1244 -842 -909 -615 -729 -1075 -1062 -880 -1446 -535 -1299 -1260 -1078 -734 -1315 -1197 -1237 -634 -1274 -1284 -947 -1153 -977 -1077 -871 -810 -747 -816 -793 -1504 -1079 -1316 -1148 -889 -799 -832 -1004 -1018 -1042 -1173 -1424 -688 -766 -899 -1268 -874 -996 -609 -889 -891 -1566 -1194 -931 -988 -1137 -1255 -1120 -1532 -641 -818 -927 -1418 -1007 -808 -1566 -706 -499 -1056 -1007 -1420 -774 -876 -1070 -1806 -1468 -855 -911 -1165 -1014 -1045 -990 -981 -758 -681 -822 -1352 -1298 -584 -897 -742 -1287 -1143 -1052 -1510 -949 -832 -760 -724 -737 -654 -810 -1360 -469 -928 -1881 -962 -1137 -787 -1067 -1100 -795 -687 -1002 -735 -622 -1255 -1077 -1078 -903 -1358 -716 -1426 -1002 -1269 -736 -1198 -776 -1060 -1517 -1169 -633 -1032 -941 -1097 -442 -899 -558 -1189 -1105 -905 -830 -949 -716 -838 -834 -970 -785 -958 -1156 -584 -1476 -880 -1114 -944 -1032 -937 -957 -1106 -1186 -1096 -1297 -627 -768 -879 -811 -1555 -1008 -1374 -926 -928 -1122 -844 -995 -1358 -1130 -702 -834 -897 -878 -943 -991 -1074 -1068 -793 -1087 -869 -1196 -1213 -1490 -1314 -904 -1224 -1024 -843 -1197 -908 -934 -1090 -1045 -986 -1156 -762 -1417 -1424 -1056 -1036 -1143 -1024 -1268 -871 -1002 -1213 -841 -918 -921 -1207 -605 -1504 -676 -1268 -1540 -1020 -903 -695 -1024 -990 -719 -755 -693 -640 -1196 -772 -783 -1207 -997 -787 -1180 -1188 -789 -887 -1250 -912 -609 -678 -1215 -1068 -1036 -1816 -727 -1222 -772 -899 -594 -1128 -920 -1325 -998 -1252 -590 -956 -973 -979 -1133 -789 -477 -1223 -1048 -785 -1065 -1477 -741 -1068 -813 -1271 -934 -1174 -1040 -1058 -1051 -1128 -995 -926 -1150 -877 -1348 -1104 -1066 -978 -878 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/random.txt deleted file mode 100644 index d72ad5081..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -6779 -10777 -11501 -5893 -7883 -5737 -15108 -11007 -13806 -16898 -11907 -8756 -11188 -6097 -8751 -6661 -14519 -18648 -7048 -13007 -12404 -7055 -3908 -5132 -7399 -16110 -11226 -8678 -12597 -10626 -7220 -14398 -10836 -9245 -11894 -10812 -12762 -18205 -19982 -13699 -6625 -13143 -15151 -6598 -11947 -6758 -22142 -9746 -6988 -9371 -9419 -7232 -6048 -8363 -9648 -20041 -4967 -7830 -12165 -6907 -11069 -8957 -13723 -8176 -11196 -13229 -17803 -9520 -8808 -8921 -7953 -15778 -12555 -7711 -21534 -11440 -7751 -13864 -7272 -11474 -8237 -12088 -12244 -8914 -9604 -9613 -12612 -15331 -13566 -8713 -9792 -12350 -4368 -11190 -15155 -13448 -13989 -12674 -13464 -7320 -9500 -11117 -8662 -11684 -12022 -13041 -13971 -10892 -12299 -12936 -14313 -7498 -11201 -8231 -17985 -11806 -11222 -15826 -10591 -10447 -10787 -7666 -7841 -11245 -11852 -11327 -11856 -8767 -11054 -14154 -6989 -11544 -11684 -9351 -12745 -4440 -7540 -8498 -10009 -10642 -11879 -7483 -4537 -18583 -12181 -8460 -11612 -14559 -7274 -8544 -11299 -13549 -14205 -9942 -11996 -7440 -8896 -9298 -6544 -4900 -12008 -10636 -9932 -10090 -13094 -9542 -7084 -11490 -14604 -10955 -12375 -5107 -11831 -10023 -8553 -16169 -13427 -13057 -14004 -5326 -13621 -7232 -13009 -13537 -11423 -12502 -14832 -12599 -10579 -7183 -5483 -11401 -11475 -17088 -8208 -13588 -10249 -8476 -7365 -7563 -6451 -13881 -13036 -10129 -13671 -10454 -9838 -13943 -13217 -6957 -8508 -10591 -13479 -5755 -12569 -5508 -9171 -12061 -8783 -8348 -8674 -9377 -16350 -5831 -10165 -8892 -11391 -12727 -9138 -10765 -8815 -15614 -12205 -8816 -12898 -16006 -10645 -8821 -9029 -13526 -12012 -8670 -8440 -13972 -8805 -13040 -14346 -10489 -14451 -8020 -13525 -15035 -9388 -9032 -3814 -12535 -7297 -11455 -16977 -12393 -6387 -12258 -7735 -6222 -15027 -9266 -5926 -18224 -10804 -14073 -5208 -8550 -12939 -8062 -7603 -6397 -18192 -6648 -14857 -12762 -16917 -10853 -12829 -11271 -7035 -10048 -10247 -11477 -7521 -7371 -11443 -14692 -14234 -8085 -6098 -11726 -11196 -12287 -6051 -12874 -7723 -10407 -12177 -11736 -11204 -9433 -21922 -9565 -8259 -9721 -10871 -9790 -6151 -11071 -10364 -14680 -10504 -13884 -14819 -10579 -8269 -18016 -9020 -13838 -11384 -11416 -7581 -9857 -11664 -10379 -8587 -15517 -11311 -3112 -9002 -14226 -7597 -12329 -18161 -9968 -10823 -12521 -10060 -17928 -9638 -9644 -9784 -13355 -12793 -13271 -10147 -9692 -14863 -7064 -9167 -11658 -10732 -8529 -7512 -10491 -16000 -4979 -10437 -10853 -8698 -6763 -11618 -9587 -11086 -5269 -12105 -17338 -7352 -11835 -9685 -10340 -9782 -5984 -9570 -12457 -13129 -9665 -11365 -11547 -10663 -12517 -9958 -14424 -7873 -12125 -10650 -9127 -16026 -11054 -9089 -10444 -8349 -6192 -5663 -14541 -9621 -17388 -11177 -12712 -9062 -10394 -10123 -7564 -5631 -10774 -10729 -12058 -8621 -12588 -10249 -8450 -8945 -8477 -12608 -8928 -13670 -13878 -7366 -11916 -11264 -12537 -8386 -8984 -7315 -6335 -18334 -11597 -9350 -11200 -13643 -9839 -15668 -10225 -13160 -11355 -15373 -11010 -10159 -5788 -7993 -14973 -11939 -10700 -10322 -9932 -11502 -14776 -12530 -10926 -17152 -11962 -12004 -12186 -6706 -9939 -14239 -9307 -8872 -9517 -3074 -10127 -9477 -10849 -10834 -15315 -10774 -14911 -12182 -14501 -12594 -8981 -11070 -15683 -9951 -12229 -13898 -15942 -7151 -11020 -7975 -12978 -13805 -11784 -8557 -5998 -16000 -13855 -13406 -4315 -10272 -15373 -13020 -10990 -15288 -10763 -8203 -9557 -9305 -12526 -8851 -7935 -13516 -10270 -8171 -8646 -13028 -8694 -12834 -7443 -14068 -13495 -6390 -15022 -8325 -12119 -19602 -11704 -13836 -12258 -16226 -5469 -15776 -11669 -10314 -13519 -13753 -10288 -9131 -8393 -6484 -12565 -12488 -8989 -14185 -14400 -11158 -19094 -18613 -8317 -7958 -14000 -13218 -11071 -7495 -5306 -15727 -11002 -8602 -10800 -7551 -8896 -9642 -15658 -4530 -10004 -10083 -13665 -9499 -11080 -12432 -14501 -15696 -10024 -11757 -6452 -9536 -11399 -7215 -8753 -11839 -9280 -10989 -10836 -14758 -8001 -13367 -15558 -5543 -6195 -10093 -7853 -9008 -12301 -14127 -8158 -12138 -12194 -9194 -9477 -9101 -12740 -5971 -14815 -12913 -8854 -8857 -16308 -13044 -10889 -10888 -9943 -6937 -11090 -11263 -8715 -10516 -9865 -7178 -7938 -12235 -5999 -11919 -8994 -11521 -10444 -8711 -16932 -9889 -11388 -8965 -9508 -10827 -12137 -5155 -11151 -11029 -12094 -6316 -14768 -8586 -10414 -11176 -8588 -10402 -10194 -11102 -6516 -14640 -10795 -8837 -12002 -9125 -12315 -6661 -15662 -9168 -6181 -12088 -11018 -8949 -6878 -7997 -18639 -7519 -16301 -14010 -12108 -9383 -8266 -9338 -10053 -8050 -9894 -13092 -6861 -15052 -10115 -11634 -9656 -8349 -10250 -10621 -11611 -11199 -13781 -12547 -5135 -14826 -14099 -12961 -9576 -8890 -11680 -7711 -8371 -10252 -13754 -8616 -10693 -15589 -11572 -7586 -12313 -14711 -3761 -9928 -11409 -11046 -10254 -12884 -11427 -5328 -10845 -9742 -17010 -6773 -9755 -14530 -5956 -10037 -10371 -11756 -8529 -9403 -17249 -10517 -9881 -12910 -12500 -17150 -9182 -8614 -13270 -7327 -6154 -10264 -9064 -9490 -8903 -6723 -17760 -9407 -14570 -11638 -8120 -7971 -11123 -8580 -13836 -5006 -12943 -12986 -12360 -7051 -13709 -16084 -7980 -12251 -13858 -9303 -8346 -16492 -8031 -13051 -6671 -8861 -9525 -7091 -11163 -8879 -6612 -9589 -15131 -7571 -15121 -8249 -9629 -16890 -9404 -11058 -7927 -5321 -7410 -11501 -10949 -10301 -12872 -14520 -14926 -6186 -13110 -7823 -7109 -7369 -11859 -7752 -6848 -10294 -10982 -9430 -10643 -7946 -13648 -11253 -22101 -13794 -6788 -12862 -14584 -11299 -9497 -8642 -8862 -12201 -14923 -5893 -8607 -11355 -7511 -11747 -12719 -11511 -8542 -8064 -14225 -12694 -12075 -2808 -7623 -7688 -11102 -15374 -18051 -8430 -14995 -10463 -15664 -7258 -9609 -12748 -8256 -13108 -14086 -16285 -9989 -10375 -7613 -8539 -12271 -10956 -6863 -10968 -11370 -12088 -14480 -11315 -11815 -9069 -10037 -7991 -11598 -9888 -8919 -14381 -6088 -6158 -7478 -16966 -11579 -13940 -7787 -6435 -7328 -12967 -12412 -11457 -8910 -9953 -16295 -9526 -6134 -11049 -6568 -9735 -14383 -8554 -13837 -11962 -14212 -10561 -8163 -18231 -6806 -10672 -11235 -10898 -10851 -8796 -6885 -8470 -8804 -21674 -10225 -9288 -13986 -5267 -9068 -15474 -13299 -14558 -6983 -15568 -13375 -8002 -10605 -9116 -9802 -12631 -7675 -14602 -13240 -10151 -9222 -11368 -6477 -10741 -9379 -10999 -9641 -10797 -11371 -9247 -11078 -4631 -16255 -12587 -5885 -5528 -11083 -10563 -8286 -10904 -18833 -12384 -15205 -11156 -9068 -11585 -9042 -14248 -6872 -10498 -9754 -8416 -12528 -9084 -9761 -10213 -10583 -12331 -13852 -11570 -8084 -9479 -4816 -9474 -9438 -9675 -10753 -16784 -12652 -11334 -8547 -15942 -12274 -16359 -5953 -10200 -10902 -10135 -16239 -11375 -8732 -6369 -7468 -15020 -8750 -7192 -10922 -11744 -6553 -12446 -7192 -8296 -7509 -8582 -10865 -8967 -7970 -8032 -9043 -6637 -6793 -12313 -8204 -8342 -8751 -17014 -9157 -9756 -8650 -6179 -9727 -11243 -10227 -11372 -10610 -8649 -8962 -11895 -9174 -9161 -10201 -12281 -8112 -12426 -10041 -9768 -13303 -14167 -13196 -11788 -10557 -14685 -10191 -10287 -9644 -16157 -14750 -9474 -13628 -15340 -4392 -10178 -8196 -15533 -16633 -9595 -11985 -11857 -7276 -13628 -17494 -7658 -6408 -10713 -7526 -12129 -11215 -6423 -11730 -7253 -10211 -10257 -12464 -10988 -7543 -7697 -8317 -7628 -14098 -9756 -9501 -6664 -12132 -9262 -8615 -11262 -9528 -10289 -15236 -12818 -13198 -11233 -17278 -12646 -5242 -16536 -10569 -14761 -9787 -11158 -11330 -12342 -10731 -12276 -16562 -9263 -16423 -9851 -16628 -11416 -9270 -13885 -11872 -10848 -7858 -9888 -13332 -12194 -7111 -14668 -10621 -12623 -14631 -12945 -17060 -14739 -10150 -9505 -10719 -7561 -5570 -8475 -11456 -7317 -10139 -11988 -12314 -4942 -19066 -8522 -11838 -11702 -12079 -11405 -6452 -11789 -6364 -11363 -8303 -5865 -17773 -15195 -4471 -14379 -12896 -12749 -12483 -9625 -5143 -6168 -9706 -8908 -9849 -13327 -11957 -9586 -9743 -5797 -13546 -26892 -9538 -15418 -10713 -19398 -7436 -9352 -11928 -9526 -13285 -8853 -9559 -7205 -9366 -13004 -14431 -18789 -20713 -9994 -10861 -13982 -7902 -9388 -12499 -12123 -5956 -5402 -11146 -13845 -12163 -10418 -7025 -8665 -7738 -15400 -12184 -12375 -9630 -7039 -12403 -7604 -7197 -9381 -8239 -18658 -10441 -13688 -9379 -10342 -13580 -8894 -9273 -6656 -9794 -10238 -7147 -13589 -7994 -9214 -9676 -10775 -12179 -12455 -13661 -11073 -4359 -6350 -10121 -9794 -10131 -7855 -11545 -6868 -8579 -13972 -9071 -6341 -15678 -8520 -12913 -7776 -13337 -13901 -12059 -10975 -12276 -14853 -10916 -13252 -9955 -12799 -7244 -12570 -12486 -6560 -4660 -12584 -12605 -13190 -7993 -12695 -11054 -9928 -8589 -10717 -12673 -13333 -12220 -8099 -7370 -15777 -7040 -12965 -9828 -13249 -5516 -7235 -12210 -14866 -15755 -5327 -10487 -9850 -10872 -20123 -9366 -13254 -8246 -11866 -13308 -7729 -14240 -9827 -11013 -13447 -13751 -13549 -12860 -12021 -7807 -8290 -10317 -19910 -11014 -9363 -13336 -12259 -11445 -7385 -9644 -5555 -11554 -13329 -10966 -7812 -6073 -10344 -17086 -11280 -14181 -7639 -9135 -9271 -11285 -11546 -12186 -9436 -9930 -15938 -15791 -11420 -7185 -8451 -7678 -9951 -7342 -8926 -8800 -12998 -13099 -8486 -8616 -12523 -10510 -7349 -10882 -11623 -12139 -9496 -11208 -11388 -11340 -11416 -11462 -11896 -13211 -11425 -9018 -16049 -11150 -11425 -10544 -8749 -17791 -17732 -16231 -8451 -13188 -5108 -8963 -12486 -6703 -17724 -17489 -7229 -8341 -9196 -4806 -4421 -10510 -11567 -13539 -9438 -11128 -11397 -13911 -13370 -13668 -16119 -12092 -8784 -9910 -12134 -12604 -8271 -7065 -8372 -8861 -10040 -8542 -8760 -13766 -15962 -8731 -14987 -8534 -13932 -17078 -6662 -11657 -20388 -12251 -11106 -8540 -9239 -16248 -10196 -14635 -6256 -11165 -9496 -11422 -11171 -7682 -8192 -10582 -7189 -5860 -6835 -9160 -12403 -9182 -10615 -7004 -10827 -7615 -8793 -11717 -12468 -10779 -10758 -10452 -8976 -9113 -8820 -6892 -7197 -16327 -12584 -13939 -9053 -11440 -6569 -11310 -15082 -16643 -11024 -13022 -10756 -14168 -12933 -13620 -7376 -13419 -14542 -8067 -11867 -8873 -10594 -12522 -12897 -12268 -13034 -12320 -10693 -12934 -14158 -4736 -14284 -8692 -11739 -11751 -9230 -12080 -9396 -13332 -8395 -10192 -10456 -16928 -4907 -11695 -9319 -5972 -14144 -9961 -13271 -10854 -8205 -9090 -12225 -17641 -14844 -15425 -8524 -8197 -6521 -11524 -14363 -8029 -8162 -17173 -10826 -11831 -9129 -10988 -17114 -12646 -8756 -7320 -13034 -25712 -7226 -14022 -13210 -21338 -14382 -9525 -6577 -10804 -10825 -10404 -5791 -9345 -8975 -10254 -19983 -8767 -13154 -9325 -10578 -11778 -8085 -8288 -9011 -8380 -14719 -12215 -11405 -9866 -8841 -13323 -5837 -10281 -7916 -13821 -7421 -11373 -11547 -5743 -13569 -5001 -5412 -14801 -12181 -8124 -13041 -7905 -12962 -9324 -10700 -8601 -6386 -10091 -13237 -9828 -9766 -14443 -11163 -6665 -13669 -9844 -7070 -14922 -14781 -4391 -10402 -8316 -12906 -8674 -9863 -6878 -10700 -8306 -15084 -13816 -13061 -7453 -9243 -8310 -14524 -11308 -11633 -13350 -17777 -13246 -12800 -12439 -5031 -11775 -9044 -11012 -8679 -8869 -9453 -15780 -15404 -16838 -8931 -9108 -10851 -11190 -14004 -7507 -14140 -9878 -6852 -6986 -5592 -14901 -11198 -10400 -12634 -13144 -9014 -10735 -7758 -14055 -20222 -15197 -9839 -11462 -16372 -15832 -8566 -9918 -11509 -14471 -15028 -12600 -8826 -11416 -9142 -10330 -10579 -12733 -9822 -17979 -9790 -13488 -9441 -15724 -11130 -12630 -10160 -7379 -12537 -13432 -9532 -13160 -12002 -11936 -6690 -10223 -7129 -12091 -9899 -12841 -13589 -18023 -8155 -11896 -10343 -7566 -11862 -10622 -11158 -12629 -7023 -12757 -11800 -10411 -6922 -11194 -10615 -10527 -11253 -6403 -11303 -4559 -10439 -7411 -7988 -9400 -7120 -18571 -11884 -17524 -14569 -8395 -12249 -9719 -12854 -8192 -8956 -9231 -11333 -6236 -11151 -11311 -6514 -10501 -13707 -14468 -9429 -8037 -14813 -5008 -10351 -10670 -11746 -12499 -12624 -12341 -16553 -4523 -9474 -12310 -15093 -5161 -11247 -5999 -9804 -10468 -11252 -10772 -10793 -15721 -14990 -7541 -15224 -8554 -10035 -9032 -22182 -9351 -13705 -7892 -15163 -11793 -5855 -9464 -7614 -10494 -10029 -15352 -9813 -13135 -5890 -15253 -8684 -16423 -12938 -10495 -8174 -16123 -11866 -12883 -8626 -10709 -7308 -6140 -10013 -10098 -10737 -6281 -14755 -14760 -16687 -9909 -9286 -11039 -12121 -12131 -10620 -12791 -14787 -10833 -7831 -12477 -13635 -14322 -12799 -7219 -6896 -12398 -11303 -8436 -4656 -9203 -8289 -7467 -8835 -8929 -7514 -10193 -8526 -5814 -10106 -13901 -9203 -10282 -14358 -14615 -10081 -12984 -8423 -11899 -11935 -11602 -12196 -14845 -11221 -10964 -9951 -7814 -9315 -18365 -6146 -11696 -10278 -12526 -9476 -13039 -10358 -10145 -10687 -6483 -10970 -7024 -11848 -8211 -7598 -8343 -6203 -10048 -10295 -7611 -7623 -6024 -10510 -15708 -13423 -8776 -5165 -11003 -9522 -7847 -9721 -12019 -6628 -12339 -11509 -9421 -12599 -8802 -12294 -6703 -10449 -16330 -6362 -13581 -12625 -6243 -11227 -12919 -10804 -10879 -5473 -7915 -13668 -17167 -10983 -8078 -20742 -13491 -10842 -10446 -10763 -7976 -9238 -13635 -6975 -8179 -5754 -8108 -12448 -8033 -13753 -9348 -18170 -9667 -11137 -15182 -7035 -5675 -8525 -8305 -11694 -9294 -9811 -3703 -7664 -12940 -13549 -11837 -8807 -10998 -8586 -10995 -13631 -15186 -15260 -8982 -10496 -10805 -9178 -12117 -11709 -8706 -13449 -12443 -15940 -13829 -15143 -11450 -9601 -13410 -12233 -9321 -10710 -10245 -9693 -11671 -13549 -11706 -9338 -9668 -7096 -12543 -15352 -6167 -9042 -13036 -7091 -13201 -10148 -13810 -8711 -17995 -10172 -14289 -8892 -13513 -8764 -11189 -9076 -6996 -7359 -8107 -6561 -6914 -9145 -9580 -8995 -11044 -7232 -14514 -10647 -15547 -12428 -14697 -11475 -14562 -13472 -13530 -13564 -17211 -10794 -10521 -7875 -8634 -18407 -11453 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/best.pt deleted file mode 100644 index 5f8cad062d8775753a2c4e5090576834048b12bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15831 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

- - DACBench - -
-DACBench -
-

- -[![Run Python Tests](https://github.com/automl/DACBench/actions/workflows/run-python-tests.yml/badge.svg)](https://github.com/automl/DACBench/actions/workflows/run-python-tests.yml) -[![Documentation Status](https://readthedocs.org/projects/dacbench/badge/?version=latest)](https://dacbench.readthedocs.io/en/latest/?badge=latest) +![AutoML.org Logo](https://www.automl.org/wp-content/themes/automl/images/logo.png) + +[![Run Python Tests](https://github.com/automl/DACBench/actions/workflows/pytest.yml/badge.svg)](https://github.com/automl/DACBench/actions/workflows/pytest.yml) +[![Documentation Status](https://github.com/automl/DACBench/actions/workflows/docs.yml/badge.svg)](https://github.com/automl/DACBench/actions/workflows/docs.yml) DACBench is a benchmark library for Dynamic Algorithm Configuration. Its focus is on reproducibility and comparability of different DAC methods as well as easy analysis of the optimization process. @@ -24,7 +17,7 @@ You can find baseline data of static and random policies for a given version of We recommend installing DACBench in a virtual environment: ``` -conda create -n dacbench python=3.6 +conda create -n dacbench python=3.10 conda activate dacbench git clone https://github.com/automl/DACBench.git cd DACBench diff --git a/dacbench/__init__.py b/dacbench/__init__.py index dbf51adec..890279dd3 100644 --- a/dacbench/__init__.py +++ b/dacbench/__init__.py @@ -6,3 +6,16 @@ from dacbench.abstract_env import AbstractEnv, AbstractMADACEnv __all__ = ["AbstractEnv", "AbstractMADACEnv", "AbstractBenchmark"] + +from gymnasium.envs.registration import register +from dacbench import benchmarks + +for b in benchmarks.__all__: + bench = getattr(benchmarks, b)() + bench.read_instance_set() + env_name = b[:-9] + register( + id=f"{env_name}-v0", + entry_point=f"dacbench.envs:{env_name}Env", + kwargs={'config': bench.config} +) diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index 22bb8ca3e..0cf6d5ff5 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -80,7 +80,6 @@ def serialize_config(self): self.config[k], list ): if type(self.config[k][0]) == np.ndarray: - print(k) conf[k] = list(map(list, conf[k])) for i in range(len(conf[k])): if ( diff --git a/dacbench/benchmarks/theory_benchmark.py b/dacbench/benchmarks/theory_benchmark.py index f46098758..23e48a7ec 100644 --- a/dacbench/benchmarks/theory_benchmark.py +++ b/dacbench/benchmarks/theory_benchmark.py @@ -7,7 +7,7 @@ import pandas as pd from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs.theory import RLSEnv, RLSEnvDiscrete +from dacbench.envs.theory import TheoryEnv, TheoryEnvDiscrete INFO = { "identifier": "Theory", @@ -73,7 +73,7 @@ def __init__(self, config=None): assert ( "max_action" not in self.config ), "ERROR: max_action should not be used for discrete action space" - self.config.env_class = "RLSEnvDiscrete" + self.config.env_class = "TheoryEnvDiscrete" n_acts = len(self.config["action_choices"]) action = CSH.UniformIntegerHyperparameter(name="", lower=0, upper=n_acts) else: @@ -83,7 +83,7 @@ def __init__(self, config=None): assert ("min_action" in self.config) and ( "max_action" in self.config ), "ERROR: min_action and max_action must be specified" - self.config.env_class = "RLSEnv" + self.config.env_class = "TheoryEnv" action = CSH.UniformFloatHyperparameter( name="Step_size", lower=self.config["min_action"], @@ -95,7 +95,7 @@ def __init__(self, config=None): # create observation space self.env_class = globals()[self.config.env_class] - assert self.env_class == RLSEnv or self.env_class == RLSEnvDiscrete + assert self.env_class == TheoryEnv or self.env_class == TheoryEnvDiscrete self.config[ "observation_space" @@ -104,7 +104,7 @@ def __init__(self, config=None): ) def create_observation_space_from_description( - self, obs_description, env_class=RLSEnvDiscrete + self, obs_description, env_class=TheoryEnvDiscrete ): """ Create a gym observation space (Box only) based on a string containing observation variable names, e.g. "n, f(x), k, k_{t-1}" diff --git a/dacbench/container/remote_env.py b/dacbench/container/remote_env.py index 5ff000f5e..ae4360eb9 100644 --- a/dacbench/container/remote_env.py +++ b/dacbench/container/remote_env.py @@ -8,7 +8,7 @@ from dacbench.abstract_env import AbstractEnv from dacbench.container.container_utils import Decoder, Encoder -NumpyTypes = Union[np.ndarray, np.int, np.float, np.random.RandomState] +NumpyTypes = Union[np.ndarray, np.int32, np.float32, np.random.RandomState] DefaultJsonable = Union[ bool, None, diff --git a/dacbench/envs/__init__.py b/dacbench/envs/__init__.py index 32fc2b6f7..47c53851e 100644 --- a/dacbench/envs/__init__.py +++ b/dacbench/envs/__init__.py @@ -11,17 +11,20 @@ SigmoidEnv, ) from dacbench.envs.toysgd import ToySGDEnv +from dacbench.envs.theory import TheoryEnv __all__ = [ "LubyEnv", "luby_gen", "SigmoidEnv", + "ContinuousSigmoidEnv", + "ContinuousStateSigmoidEnv", "FastDownwardEnv", "ToySGDEnv", "GeometricEnv", + "TheoryEnv" ] - cma_spec = importlib.util.find_spec("cma") found = cma_spec is not None if found: @@ -55,16 +58,4 @@ else: warnings.warn( "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -theory_spec = importlib.util.find_spec("uuid") -found = theory_spec is not None -if found: - from dacbench.envs.theory import RLSEnv, RLSEnvDiscrete - - __all__.append("RLSEnv") - __all__.append("RLSEnvDiscrete") -else: - warnings.warn( - "Theory Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) + ) \ No newline at end of file diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index e5a61068b..bcd4c2c04 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -305,7 +305,7 @@ def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): HISTORY_LENGTH = 5 -class RLSEnv(AbstractEnv): +class TheoryEnv(AbstractEnv): """ Environment for RLS with step size. @@ -314,7 +314,7 @@ class RLSEnv(AbstractEnv): def __init__(self, config, test_env=False) -> None: """ - Initialize RLSEnv. + Initialize TheoryEnv. Parameters ---------- @@ -324,7 +324,7 @@ def __init__(self, config, test_env=False) -> None: whether to use test mode """ - super(RLSEnv, self).__init__(config) + super(TheoryEnv, self).__init__(config) self.logger = logging.getLogger(self.__str__()) self.test_env = test_env @@ -423,7 +423,7 @@ def reset(self, seed=None, options={}): Environment state """ - super(RLSEnv, self).reset_(seed) + super(TheoryEnv, self).reset_(seed) # current problem size (n) & evaluation limit (max_evals) self.n = self.instance.size @@ -481,7 +481,7 @@ def step(self, action): np.array, float, bool, bool, dict """ - truncated = super(RLSEnv, self).step_() + truncated = super(TheoryEnv, self).step_() fitness_before_update = self.x.fitness @@ -604,12 +604,12 @@ def close(self) -> bool: return True -class RLSEnvDiscrete(RLSEnv): +class TheoryEnvDiscrete(TheoryEnv): """RLS environment where the choices of r is discretised.""" def __init__(self, config, test_env=False): """Init env.""" - super(RLSEnvDiscrete, self).__init__(config, test_env) + super(TheoryEnvDiscrete, self).__init__(config, test_env) assert ( "action_choices" in config ), "Error: action_choices must be specified in benchmark's config" @@ -627,4 +627,4 @@ def step(self, action): if isinstance(action, np.ndarray) or isinstance(action, list): assert len(action) == 1 action = action[0] - return super(RLSEnvDiscrete, self).step(self.action_choices[action]) + return super(TheoryEnvDiscrete, self).step(self.action_choices[action]) diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index f194edb42..3ee4f4843 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -50,6 +50,14 @@ To instantiate a benchmark environment, run: bench = SigmoidBenchmark() benchmark_env = bench.get_environment() +Alternatively, if you do not plan on modifying the benchmark configuration, you can also use our the default version in the gymnasium registry: + +.. code-block:: python + + import gymnasium as gym + import dacbench + environment = gym.make("Sigmoid-v0") + .. automodule:: dacbench.abstract_benchmark :members: diff --git a/examples/baselines_ppo.py b/examples/baselines_ppo.py deleted file mode 100644 index eacc52110..000000000 --- a/examples/baselines_ppo.py +++ /dev/null @@ -1,73 +0,0 @@ -from stable_baselines import PPO2 -from stable_baselines.common.callbacks import ( - BaseCallback, - CheckpointCallback, - CallbackList, -) -from dacbench import benchmarks -from dacbench.logger import Logger -from dacbench.wrappers import PerformanceTrackingWrapper, ObservationWrapper -from pathlib import Path -import argparse - - -class LoggerCallback(BaseCallback): - def __init__(self, logger, verbose=0): - super(LoggerCallback, self).__init__(verbose) - self.env_logger = logger - - def _on_step(self): - self.env_logger.next_step() - return True - - def _on_rollout_end(self): - self.env_logger.next_episode() - - -def make_benchmark(config): - bench = getattr(benchmarks, config["benchmark"])() - env = bench.get_benchmark(seed=config["seed"]) - if config["benchmark"] in ["SGDBenchmark", "CMAESBenchmark"]: - env = ObservationWrapper(env) - wrapped = PerformanceTrackingWrapper(env, logger=config["logger"]) - logger.set_env(wrapped) - return wrapped - - -parser = argparse.ArgumentParser(description="Run ray PPO for DACBench") -parser.add_argument("--outdir", type=str, default="output", help="Output directory") -parser.add_argument( - "--benchmarks", nargs="+", type=str, default=None, help="Benchmarks to run PPO for" -) -parser.add_argument( - "--timesteps", type=int, default=1000000, help="Number of timesteps to run" -) -parser.add_argument( - "--seeds", - nargs="+", - type=int, - default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - help="Seeds for evaluation", -) -parser.add_argument("--fd_port", type=int, default=55555) -args = parser.parse_args() - -for b in args.benchmarks: - for s in args.seeds: - logger = Logger(experiment_name=f"PPO_{b}_s{s}", output_path=Path(args.outdir)) - perf_logger = logger.add_module(PerformanceTrackingWrapper) - config = {"seed": s, "logger": perf_logger, "benchmark": b} - if b == "FastDownwardBenchmark": - config["port"] = args.fd_port - env = make_benchmark(config) - model = PPO2("MlpPolicy", env) - logging = LoggerCallback(logger) - - checkpoint = CheckpointCallback( - save_freq=1000, - save_path=f"{args.outdir}/PPO_{b}_s{s}/models", - name_prefix="model", - ) - callback = CallbackList([logging, checkpoint]) - model.learn(total_timesteps=args.timesteps, callback=callback) - logger.close() diff --git a/examples/benchmarks/baselines_ppo_sigmoid.py b/examples/benchmarks/baselines_ppo_sigmoid.py deleted file mode 100644 index 7487f505d..000000000 --- a/examples/benchmarks/baselines_ppo_sigmoid.py +++ /dev/null @@ -1,51 +0,0 @@ -import tensorflow as tf -import warnings -from stable_baselines3 import PPO2 -from dacbench.benchmarks import SigmoidBenchmark -from dacbench.wrappers import PerformanceTrackingWrapper - -# Baselines uses an old TF version -# As soon as baselines3 is out of beta, we should use it -# Until then we try to surpress as many of these warnings as possible -warnings.simplefilter(action="ignore", category=FutureWarning) -tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR) -tf.logging.set_verbosity(tf.logging.ERROR) - - -# Environment creation method -# Overwrite standard configuration with given options, but adapt action space automatically -def make_sigmoid(config): - bench = SigmoidBenchmark() - for k in config.keys(): - if k == "action_values": - bench.set_action_values(config[k]) - else: - bench.config[k] = config[k] - return bench.get_environment() - - -# Experiment configuration -# Play 5D scenario -action_values = (3, 3, 3, 3, 3) -env_config = { - "seed": 0, - "action_values": action_values, - "instance_set_path": "../instance_sets/sigmoid/sigmoid_5D3M_train.csv", -} - -# Make environment -# To track rewards we use our wrapper (this is only for simplicity) -env = make_sigmoid(env_config) -env = PerformanceTrackingWrapper(env) - -# Make simple PPO policy -model = PPO2("MlpPolicy", env) - -# Run for 10 steps -model.learn(total_timesteps=200) - -performance = env.get_performance()[0] -for i in range(len(performance)): - print( - f"Episode {i+1}/{len(performance)}...........................................Reward: {performance[i]}" - ) diff --git a/examples/benchmarks/chainerrl_cma.py b/examples/benchmarks/chainerrl_cma.py deleted file mode 100644 index 428f0d197..000000000 --- a/examples/benchmarks/chainerrl_cma.py +++ /dev/null @@ -1,52 +0,0 @@ -from pathlib import Path -from dacbench.logger import Logger -from dacbench.wrappers import PerformanceTrackingWrapper, ObservationWrapper -from examples.example_utils import make_chainer_a3c -from dacbench.benchmarks import CMAESBenchmark - -# Make logger object -logger = Logger(experiment_name="CMAESBenchmark", output_path=Path("../plotting/data")) - -# Make CMA-ES environment -# We use the configuration from the "Learning to Optimize Step-size Adaption in CMA-ES" Paper by Shala et al. -bench = CMAESBenchmark() -env = bench.get_benchmark() -logger.set_env(env) - -# Wrap to track performance -performance_logger = logger.add_module(PerformanceTrackingWrapper) -env = PerformanceTrackingWrapper(env=env, logger=performance_logger) - -# Also wrap to make the dictionary observations into an easy to work with list -env = ObservationWrapper(env) - -# Make chainer agent -obs_size = env.observation_space.low.size -action_size = env.action_space.low.size -agent = make_chainer_a3c(obs_size, action_size) - -# Training -num_episodes = 3 -for i in range(num_episodes): - # Reset environment to begin episode - state, _ = env.reset() - - # Initialize episode - terminated, truncated = False, False - r = 0 - reward = 0 - while not (terminated or truncated): - # Select action - action = agent.act_and_train(state, reward) - # Execute action - next_state, reward, terminated, truncated, _ = env.step(action) - r += reward - logger.next_step() - state = next_state - logger.next_episode() - # Train agent after episode has ended - agent.stop_episode_and_train(state, reward, done=terminated or truncated) - # Log episode - print( - f"Episode {i+1}/{num_episodes}...........................................Reward: {r}" - ) diff --git a/examples/benchmarks/ray_dqn_fd.py b/examples/benchmarks/ray_dqn_fd.py deleted file mode 100644 index d900b2d3e..000000000 --- a/examples/benchmarks/ray_dqn_fd.py +++ /dev/null @@ -1,24 +0,0 @@ -import ray -from ray import tune -from dacbench.benchmarks import FastDownwardBenchmark - - -# Method to create env -# Here we use the published version of the FastDownward Benchmark -def make_fast_downward(config): - bench = FastDownwardBenchmark() - return bench.get_benchmark(config["seed"]) - - -# Initialize ray -ray.init() -# Register env with creation method -tune.register_env("fd", make_fast_downward) - -# Experiment configuration -config = {"env": "fd", "env_config": {"seed": 0}} -stop = {"training_iteration": 10} - -# Run DQN -results = tune.run("DQN", config=config, stop=stop) -ray.shutdown() diff --git a/examples/coax_ppo_cmaes.py b/examples/coax_ppo_cmaes.py new file mode 100644 index 000000000..a70f6575f --- /dev/null +++ b/examples/coax_ppo_cmaes.py @@ -0,0 +1,103 @@ +import jax +import jax.numpy as jnp +import coax +import haiku as hk +from numpy import prod +import optax + +from dacbench.benchmarks import CMAESBenchmark +from dacbench.wrappers import ObservationWrapper + + +# the name of this script +name = 'ppo' + +# the Pendulum MDP +bench = CMAESBenchmark() +env = bench.get_environment() +env = ObservationWrapper(env) +env = coax.wrappers.TrainMonitor(env, name=name, tensorboard_dir=f"./data/tensorboard/{name}") + + +def func_pi(S, is_training): + shared = hk.Sequential(( + hk.Linear(8), jax.nn.relu, + hk.Linear(8), jax.nn.relu, + )) + mu = hk.Sequential(( + shared, + hk.Linear(8), jax.nn.relu, + hk.Linear(prod(env.action_space.shape), w_init=jnp.zeros), + hk.Reshape(env.action_space.shape), + )) + logvar = hk.Sequential(( + shared, + hk.Linear(8), jax.nn.relu, + hk.Linear(prod(env.action_space.shape), w_init=jnp.zeros), + hk.Reshape(env.action_space.shape), + )) + return {'mu': mu(S), 'logvar': logvar(S)} + + +def func_v(S, is_training): + seq = hk.Sequential(( + hk.Linear(8), jax.nn.relu, + hk.Linear(8), jax.nn.relu, + hk.Linear(8), jax.nn.relu, + hk.Linear(1, w_init=jnp.zeros), jnp.ravel + )) + return seq(S) + + +# define function approximators +pi = coax.Policy(func_pi, env) +v = coax.V(func_v, env) + + +# target network +pi_targ = pi.copy() + + +# experience tracer +tracer = coax.reward_tracing.NStep(n=5, gamma=0.9) +buffer = coax.experience_replay.SimpleReplayBuffer(capacity=512) + + +# policy regularizer (avoid premature exploitation) +policy_reg = coax.regularizers.EntropyRegularizer(pi, beta=0.01) + + +# updaters +simpletd = coax.td_learning.SimpleTD(v, optimizer=optax.adam(1e-3)) +ppo_clip = coax.policy_objectives.PPOClip(pi, regularizer=policy_reg, optimizer=optax.adam(1e-4)) + +# train +for _ in range(10): + done, truncated = False, False + s, info = env.reset() + + while not (done or truncated): + a, logp = pi_targ(s, return_logp=True) + s_next, r, done, truncated, info = env.step(a) + + # trace rewards + tracer.add(s, a, r, done or truncated, logp) + while tracer: + buffer.add(tracer.pop()) + + # learn + if len(buffer) >= buffer.capacity: + for _ in range(int(4 * buffer.capacity / 32)): # 4 passes per round + transition_batch = buffer.sample(batch_size=32) + metrics_v, td_error = simpletd.update(transition_batch, return_td_error=True) + metrics_pi = ppo_clip.update(transition_batch, td_error) + env.record_metrics(metrics_v) + env.record_metrics(metrics_pi) + + buffer.clear() + pi_targ.soft_update(pi, tau=0.1) + + if done or truncated: + break + + s = s_next \ No newline at end of file diff --git a/examples/multi_agent_sigmoid.py b/examples/multi_agent_sigmoid.py new file mode 100644 index 000000000..d8793b857 --- /dev/null +++ b/examples/multi_agent_sigmoid.py @@ -0,0 +1,19 @@ +from dacbench.benchmarks import SigmoidBenchmark + +bench = SigmoidBenchmark() +bench.config['multi_agent'] = True +env = bench.get_environment() +env.register_agent(0) +env.register_agent(1) +env.reset() +terminated, truncated = False, False +total_reward = 0 +while not (terminated or truncated): + for a in [0, 1]: + observation, reward, terminated, truncated, info = env.last() + action = env.action_spaces[a].sample() + env.step(action) + observation, reward, terminated, truncated, info = env.last() + total_reward += reward + +print(f"The final reward was {total_reward}.") \ No newline at end of file diff --git a/examples/ray_ppo.py b/examples/ray_ppo.py index 46daedddb..52fdd1bdc 100644 --- a/examples/ray_ppo.py +++ b/examples/ray_ppo.py @@ -18,10 +18,10 @@ def make_benchmark(config): parser = argparse.ArgumentParser(description="Run ray PPO for DACBench") parser.add_argument("--outdir", type=str, default="output", help="Output directory") parser.add_argument( - "--benchmarks", nargs="+", type=str, default=None, help="Benchmarks to run PPO for" + "--benchmarks", nargs="+", type=str, default=["LubyBenchmark"], help="Benchmarks to run PPO for" ) parser.add_argument( - "--timesteps", type=int, default=1000000, help="Number of timesteps to run" + "--timesteps", type=int, default=10000, help="Number of timesteps to run" ) parser.add_argument( "--save_interval", type=int, default=100, help="Checkpoint interval" @@ -55,5 +55,5 @@ def make_benchmark(config): for i in range(args.timesteps): trainer.train() if i % args.save_interval == 0: - trainer.save(args.outdir + f"/{b}_{s}") + trainer.save(args.outdir + f"./{b}_{s}") ray.shutdown() diff --git a/examples/benchmarks/tabular_luby.py b/examples/tabular_rl_luby.py similarity index 100% rename from examples/benchmarks/tabular_luby.py rename to examples/tabular_rl_luby.py diff --git a/tests/benchmarks/test_fd_benchmark.py b/tests/benchmarks/test_fd_benchmark.py index 3a9517216..b17cb5b64 100644 --- a/tests/benchmarks/test_fd_benchmark.py +++ b/tests/benchmarks/test_fd_benchmark.py @@ -17,6 +17,8 @@ def test_get_env(self): env = bench.get_environment() self.assertTrue(issubclass(type(env), FastDownwardEnv)) + #TODO: This test breaks remote testing, possibly due to too many open ports. + #Should be investigated # def test_scenarios(self): # scenarios = [ # "fd_barman.json", From 1c84c85ff312963fbe68ce80f693e75e5b1c3bef Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:40:36 +0200 Subject: [PATCH 37/44] example dependencies --- setup.cfg | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/setup.cfg b/setup.cfg index edfd4aebc..6fb7190ff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -54,15 +54,13 @@ dev = coverage[toml]==7.2.1 pre-commit==3.1.1 example = - chainerrl - ray - tabulate - dm-tree - opencv-python - stable-baselines3 - jupyter + ray[rllib]==2.3.1 + tabulate==0.9.0 + jupyter==1.0.0 + tensorflow==2.12.0 + coax==0.1.13 docs = - automl-sphinx-theme + automl-sphinx-theme==0.2.0 all= gymnasium==0.27.1 numpy==1.24.2 From 756c9282d078e4f2c09aa06027a101fc8c934f1e Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:46:00 +0200 Subject: [PATCH 38/44] formatting --- CHANGELOG.md | 1 + dacbench/__init__.py | 5 +++-- dacbench/abstract_benchmark.py | 2 +- dacbench/container/remote_env.py | 2 +- dacbench/envs/__init__.py | 6 +++--- dacbench/envs/theory.py | 8 ++++---- dacbench/logger.py | 2 +- dacbench/wrappers/reward_noise_wrapper.py | 2 +- dacbench/wrappers/state_tracking_wrapper.py | 1 + pyproject.toml | 2 +- tests/benchmarks/test_fd_benchmark.py | 4 ++-- 11 files changed, 19 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e92342505..6d626fe35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ The main change in this version is going from OpenAI's gym to the newer gymnasium version. The outward change is slight, but this interface is now **incompatible with version 0.1.0**. To adapt to this version, you'll mainly have to replace instances of 'done' for termination with two variables: 'terminated' indication algorithm termination and 'truncated' indicating a timeout. Combined they're equal to the old 'done'. +Additonally, the default version of the environments is now available in the gym registry. ### Multi-Agent / Round Robin Control Option We added more options for controlling several hyperparameters at once. Using the PettingZoo API, users can now select which hyperparameters to control and use a typical Multi-Agent RL interface to do it. diff --git a/dacbench/__init__.py b/dacbench/__init__.py index 890279dd3..5e9291e3d 100644 --- a/dacbench/__init__.py +++ b/dacbench/__init__.py @@ -8,6 +8,7 @@ __all__ = ["AbstractEnv", "AbstractMADACEnv", "AbstractBenchmark"] from gymnasium.envs.registration import register + from dacbench import benchmarks for b in benchmarks.__all__: @@ -17,5 +18,5 @@ register( id=f"{env_name}-v0", entry_point=f"dacbench.envs:{env_name}Env", - kwargs={'config': bench.config} -) + kwargs={"config": bench.config}, + ) diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index 0cf6d5ff5..b3ada9029 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -326,7 +326,7 @@ def __decorate_config_with_functions(conf: dict): Parameters ---------- - conf : + conf : config to parse """ diff --git a/dacbench/container/remote_env.py b/dacbench/container/remote_env.py index ae4360eb9..145f4ed54 100644 --- a/dacbench/container/remote_env.py +++ b/dacbench/container/remote_env.py @@ -41,7 +41,7 @@ def json_decode(json_str: str) -> Jsonable: @Pyro4.expose class RemoteEnvironmentServer: """Server for remote environment.""" - + def __init__(self, env): """Make env server.""" self.__env: AbstractEnv = env diff --git a/dacbench/envs/__init__.py b/dacbench/envs/__init__.py index 47c53851e..cc8da2753 100644 --- a/dacbench/envs/__init__.py +++ b/dacbench/envs/__init__.py @@ -10,8 +10,8 @@ ContinuousStateSigmoidEnv, SigmoidEnv, ) -from dacbench.envs.toysgd import ToySGDEnv from dacbench.envs.theory import TheoryEnv +from dacbench.envs.toysgd import ToySGDEnv __all__ = [ "LubyEnv", @@ -22,7 +22,7 @@ "FastDownwardEnv", "ToySGDEnv", "GeometricEnv", - "TheoryEnv" + "TheoryEnv", ] cma_spec = importlib.util.find_spec("cma") @@ -58,4 +58,4 @@ else: warnings.warn( "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) \ No newline at end of file + ) diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index bcd4c2c04..7f91678ec 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -85,7 +85,7 @@ def flip(self, locs): locs: 1d-array positions where bits are flipped - Returns + Returns ------- the new individual after the flip @@ -108,7 +108,7 @@ def combine(self, xprime, locs_xprime): locs_xprime: : 1d boolean/integer array positions where we change to xprime's bits - Returns + Returns ------- the new individual after the crossover @@ -125,7 +125,7 @@ def mutate(self, p, n_childs, rng=np.random.default_rng()): Generate n_childs children by flipping exactly l bits Returns - ------- + ------- the best child (maximum fitness), its fitness and number of evaluations used """ @@ -197,7 +197,7 @@ def crossover( count_different_inds_only : bool whether to only count different individuals rng: - random number generator + random number generator """ assert p <= 1 diff --git a/dacbench/logger.py b/dacbench/logger.py index 83803ff59..9263ad909 100644 --- a/dacbench/logger.py +++ b/dacbench/logger.py @@ -30,7 +30,7 @@ def load_logs(log_file: Path) -> List[Dict]: } ... } - + Parameters ---------- log_file: pathlib.Path diff --git a/dacbench/wrappers/reward_noise_wrapper.py b/dacbench/wrappers/reward_noise_wrapper.py index 55f42eca0..d4821f7aa 100644 --- a/dacbench/wrappers/reward_noise_wrapper.py +++ b/dacbench/wrappers/reward_noise_wrapper.py @@ -111,7 +111,7 @@ def add_noise(self, dist, args): ------- function Noise sampling function - + """ rng = np.random.default_rng() function = getattr(rng, dist) diff --git a/dacbench/wrappers/state_tracking_wrapper.py b/dacbench/wrappers/state_tracking_wrapper.py index 6a0833186..603effea8 100644 --- a/dacbench/wrappers/state_tracking_wrapper.py +++ b/dacbench/wrappers/state_tracking_wrapper.py @@ -184,6 +184,7 @@ def render_state_tracking(self): RBG data of state tracking """ + def plot_single(ax=None, index=None, title=None, x=False, y=False): if ax is None: plt.xlabel("Episode") diff --git a/pyproject.toml b/pyproject.toml index 7ff56d88d..a2194c81e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [tool.pydocstyle] inherit = false ignore = 'D100,D212,D401,D203,D404,D104,D400,D415' -match = '.*\.py' +match = 'dacbench/.*\.py' [tool.pytest.ini_options] filterwarnings = [ diff --git a/tests/benchmarks/test_fd_benchmark.py b/tests/benchmarks/test_fd_benchmark.py index b17cb5b64..58c6fc393 100644 --- a/tests/benchmarks/test_fd_benchmark.py +++ b/tests/benchmarks/test_fd_benchmark.py @@ -17,8 +17,8 @@ def test_get_env(self): env = bench.get_environment() self.assertTrue(issubclass(type(env), FastDownwardEnv)) - #TODO: This test breaks remote testing, possibly due to too many open ports. - #Should be investigated + # TODO: This test breaks remote testing, possibly due to too many open ports. + # Should be investigated # def test_scenarios(self): # scenarios = [ # "fd_barman.json", From 5dcb60aeb56828425086c9de02bae22fc5527517 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:48:30 +0200 Subject: [PATCH 39/44] version matching --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 6fb7190ff..2f1ac3c2c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,7 +62,7 @@ example = docs = automl-sphinx-theme==0.2.0 all= - gymnasium==0.27.1 + gymnasium==0.26.3 numpy==1.24.2 scipy==1.10.1 cma==3.3.0 From 0ab651b646aeb9b139f37ef8580e2247aab292a3 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:50:09 +0200 Subject: [PATCH 40/44] unify gym version --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 2f1ac3c2c..08ba6a23b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,7 +30,7 @@ classifiers = [options] python_requires= >=3.10 install_requires = - gymnasium==0.27.1 + gymnasium==0.26.3 numpy==1.24.2 scipy==1.10.1 pandas==1.5.3 From cddb1bbb1767b1252917f5c88fadb2a45a4ac8a2 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:53:29 +0200 Subject: [PATCH 41/44] no examples installs for test --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 4d29e0bdb..69ef1fff9 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -34,7 +34,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e.[dev,example,all] + pip install -e.[dev,all] - name: Build fast-downward run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest From dd70a8ba36a48866acef0ce6da8e438c78b2fb7e Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:58:00 +0200 Subject: [PATCH 42/44] stry gym reference --- tests/test_logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_logger.py b/tests/test_logger.py index 631c1ae54..4bf1ff437 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -4,8 +4,8 @@ from pathlib import Path import numpy as np -from gym import spaces -from gym.spaces import Box, Dict, Discrete, MultiDiscrete +from gymnasium import spaces +from gymnasium.spaces import Box, Dict, Discrete, MultiDiscrete from dacbench.agents.simple_agents import RandomAgent from dacbench.benchmarks import SigmoidBenchmark From 625bed94c136c39936d36f16945c91d9f1b98a69 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 15:30:47 +0200 Subject: [PATCH 43/44] escaped registry --- dacbench/__init__.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/dacbench/__init__.py b/dacbench/__init__.py index 5e9291e3d..4172b6838 100644 --- a/dacbench/__init__.py +++ b/dacbench/__init__.py @@ -11,12 +11,17 @@ from dacbench import benchmarks -for b in benchmarks.__all__: - bench = getattr(benchmarks, b)() - bench.read_instance_set() - env_name = b[:-9] - register( - id=f"{env_name}-v0", - entry_point=f"dacbench.envs:{env_name}Env", - kwargs={"config": bench.config}, +try: + for b in benchmarks.__all__: + bench = getattr(benchmarks, b)() + bench.read_instance_set() + env_name = b[:-9] + register( + id=f"{env_name}-v0", + entry_point=f"dacbench.envs:{env_name}Env", + kwargs={"config": bench.config}, + ) +except: + print( + "DACBench Gym registration failed - make sure you have all dependencies installed and their instance sets in the right path!" ) From 70ac4de67e1acb48261610eba696a2d49e91f609 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 15:37:40 +0200 Subject: [PATCH 44/44] updated getting started notebook --- Getting started.ipynb | 151 +++++++++++--------------------------- examples/example_utils.py | 107 +-------------------------- 2 files changed, 44 insertions(+), 214 deletions(-) diff --git a/Getting started.ipynb b/Getting started.ipynb index ef1d23671..2533600f2 100644 --- a/Getting started.ipynb +++ b/Getting started.ipynb @@ -2,14 +2,12 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import warnings\n", "warnings.filterwarnings('ignore')\n", - "import numpy as np\n", - "from chainerrl import wrappers\n", "from pathlib import Path\n", "import pandas as pd\n", "\n", @@ -19,15 +17,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from dacbench.benchmarks import LubyBenchmark, SigmoidBenchmark\n", "from dacbench.wrappers import PerformanceTrackingWrapper, RewardNoiseWrapper\n", "from dacbench.logger import Logger, load_logs, log2dataframe\n", - "from dacbench.plotting import plot_performance, plot_performance_per_instance\n", - "from examples.example_utils import make_chainer_dqn, train_chainer" + "from dacbench.plotting import plot_performance, plot_performance_per_instance" ] }, { @@ -43,15 +40,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "action_space_class: Discrete\n", - "action_space_args: [6]\n", + "config_space: Configuration space object:\n", + " Hyperparameters:\n", + " sequence_element, Type: UniformInteger, Range: [0, 6], Default: 3\n", + "\n", "observation_space_class: Box\n", "observation_space_type: \n", "observation_space_args: [array([-1, -1, -1, -1, -1, -1]), array([128., 128., 128., 128., 128., 128.])]\n", @@ -61,7 +60,7 @@ "min_steps: 8\n", "seed: 0\n", "instance_set_path: ../instance_sets/luby/luby_default.csv\n", - "benchmark_info: {'identifier': 'Luby', 'name': 'Luby Sequence Approximation', 'reward': 'Boolean sucess indication', 'state_description': ['Action t-2', 'Step t-2', 'Action t-1', 'Step t-1', 'Action t (current)Step t (current)']}\n" + "benchmark_info: {'identifier': 'Luby', 'name': 'Luby Sequence Approximation', 'reward': 'Boolean sucess indication', 'state_description': ['Action t-2', 'Step t-2', 'Action t-1', 'Step t-1', 'Action t (current)', 'Step t (current)']}\n" ] } ], @@ -81,7 +80,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -98,7 +97,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -115,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -131,7 +130,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -150,14 +149,15 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[-1 -1 -1 -1 -1 -1]\n" + "[-1 -1 -1 -1 -1 -1]\n", + "{}\n" ] } ], @@ -176,14 +176,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Episode 1/1...........................................Reward: -6\n" + "Episode 1/1...........................................Reward: -1\n" ] } ], @@ -209,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -233,94 +233,29 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now we run the environment on 5 different seeds, logging the results of each one.\n", - "In this example, we use a simple RL agent." + "In this example, we use a simple random agent." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Episode 0/10...........................................Reward: 1.3011316427214563\n", - "Episode 1/10...........................................Reward: 3.3744850921123946\n", - "Episode 2/10...........................................Reward: 2.3631684324627718\n", - "Episode 3/10...........................................Reward: 4.317746116997824\n", - "Episode 4/10...........................................Reward: 1.6797188664568847\n", - "Episode 5/10...........................................Reward: 2.7827871422251107\n", - "Episode 6/10...........................................Reward: 2.5116556799296275\n", - "Episode 7/10...........................................Reward: 3.5007718971969197\n", - "Episode 8/10...........................................Reward: 4.106872497507007\n", - "Episode 9/10...........................................Reward: 4.793092410210768\n", - "Episode 0/10...........................................Reward: 3.031774376928836\n", - "Episode 1/10...........................................Reward: 3.531218880633655\n", - "Episode 2/10...........................................Reward: 4.167165087384353\n", - "Episode 3/10...........................................Reward: 5.233201705455833\n", - "Episode 4/10...........................................Reward: 2.188207601128754\n", - "Episode 5/10...........................................Reward: 1.8568553859700894\n", - "Episode 6/10...........................................Reward: 3.3535213565300914\n", - "Episode 7/10...........................................Reward: 3.9143173726764315\n", - "Episode 8/10...........................................Reward: 5.9210770071618875\n", - "Episode 9/10...........................................Reward: 1.7347809873492697\n", - "Episode 0/10...........................................Reward: 1.2267208210243266\n", - "Episode 1/10...........................................Reward: 4.272024200240991\n", - "Episode 2/10...........................................Reward: 4.018067293012267\n", - "Episode 3/10...........................................Reward: 6.092753761710156\n", - "Episode 4/10...........................................Reward: 2.8559608448320155\n", - "Episode 5/10...........................................Reward: 4.566827138251945\n", - "Episode 6/10...........................................Reward: 1.6729707197368913\n", - "Episode 7/10...........................................Reward: 3.294847132837542\n", - "Episode 8/10...........................................Reward: 4.483649588788299\n", - "Episode 9/10...........................................Reward: 2.38138037478034\n", - "Episode 0/10...........................................Reward: 1.6510698360234835\n", - "Episode 1/10...........................................Reward: 2.128216159693229\n", - "Episode 2/10...........................................Reward: 5.916633060036471\n", - "Episode 3/10...........................................Reward: 2.5946635073954556\n", - "Episode 4/10...........................................Reward: 1.9370437373865061\n", - "Episode 5/10...........................................Reward: 2.8583409558781687\n", - "Episode 6/10...........................................Reward: 2.709995561782036\n", - "Episode 7/10...........................................Reward: 4.22106134601858\n", - "Episode 8/10...........................................Reward: 4.00098190503663\n", - "Episode 9/10...........................................Reward: 3.8897015883042507\n", - "Episode 0/10...........................................Reward: 3.448686970958871\n", - "Episode 1/10...........................................Reward: 3.8641567543854487\n", - "Episode 2/10...........................................Reward: 4.055595574984241\n", - "Episode 3/10...........................................Reward: 1.1747168367918102\n", - "Episode 4/10...........................................Reward: 1.9570821025256233\n", - "Episode 5/10...........................................Reward: 1.4562154261767166\n", - "Episode 6/10...........................................Reward: 1.8993780855495175\n", - "Episode 7/10...........................................Reward: 2.3341211959967425\n", - "Episode 8/10...........................................Reward: 2.85351960011256\n", - "Episode 9/10...........................................Reward: 4.658324104566514\n", - "Episode 0/10...........................................Reward: 2.257800049332543\n", - "Episode 1/10...........................................Reward: 3.3820616461689674\n", - "Episode 2/10...........................................Reward: 0.8288001998682013\n", - "Episode 3/10...........................................Reward: 2.6205201908469493\n", - "Episode 4/10...........................................Reward: 3.1124064373231706\n", - "Episode 5/10...........................................Reward: 2.4906180892787058\n", - "Episode 6/10...........................................Reward: 2.120601125600685\n", - "Episode 7/10...........................................Reward: 2.5516422919869104\n", - "Episode 8/10...........................................Reward: 1.0484662491724799\n", - "Episode 9/10...........................................Reward: 6.036117355497821\n" - ] - } - ], + "outputs": [], "source": [ + "from dacbench.agents import RandomAgent\n", + "from dacbench.runner import run_benchmark\n", + "\n", "for seed in [0, 1, 2, 3, 4]:\n", " env, logger = setup_env(seed)\n", " \n", " # This could be any optimization or learning method\n", - " rl_agent = make_chainer_dqn(env.observation_space.low.size, env.action_space)\n", - " env = wrappers.CastObservationToFloat32(env)\n", - " \n", - " train_chainer(rl_agent, env, num_episodes=10, logger=logger)" + " agent = RandomAgent(env)\n", + " run_benchmark(env, agent, num_episodes=10, logger=logger)" ] }, { @@ -332,7 +267,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -352,14 +287,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqkAAAFYCAYAAABwAGXmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzdd3gUZdcH4N9sTwXSSECKAhs6BhJKQkdFVEBRFGkiiIKKr4CIIAoiIthQUUF5lU8R8JUOCogCSg9dpJcklFCSLUm2z+zs8/2x7JhNNmETErJJzn1dXMDs7OyzMzszZ552OMYYAyGEEEIIIQFEVtEFIIQQQgghpCAKUgkhhBBCSMChIJUQQgghhAQcClIJIYQQQkjAoSCVEEIIIYQEHApSCSGEkAJo4htCKh4FqVVIamoq4uPjff5p2rQp2rZti/vvvx+TJ0/GhQsXKrq4d0xCQgLi4+Mruhh+2bp1K1566SV07twZLVu2RMeOHTFo0CAsWrQIVqu10PpvvPEG4uPjsXnz5goo7e0ZNmwY4uPj8c8///i1/iOPPIL4+HhcuXLllut69kvBP61atUKPHj0wefJkpKWl3e5XKFfz589HfHw8vv3224ouSql5rkkvvPBCmWzv4MGDaNmyJY4fP14m2/P1G8zNzcX06dPxxx9/eK0bHx+PhISEMvnc9PR0TJw4EcnJyWjTpg369u2LxYsXg+f5YstZ1J/8BEHArFmz0KFDB3To0AEvv/wyrl696nO7kyZNQteuXeFwOEr9XXJzc/HDDz9g8ODB0nWrS5cueOWVV5CamurzPZ7f9vz5873K3bt3b7z//vulLgupehQVXQBS9iIjI5GcnOy1jDGGrKwsnDx5EmvXrsWWLVuwbNkyNGvWrIJKSfJzuVx4/fXXsWHDBqjVarRs2RJt27aF0WjE6dOnceTIESxbtgxLlizBXXfdVdHFrTQSEhKk/cUYg91ux8WLF7F27Vps3rwZS5cuRcuWLSu4lMQfNpsNr7/+Ovr27Vuux2zOnDlYvXo1OnXqVC7bP3ToEJ577jlYrVbExcWhTZs2SEtLw5w5c7B161YsXLgQoaGhXu85deoUwsPD0a1bt1tuf8GCBViyZAm0Wi3i4uKwbds2pKWlYd26dVAqldJ6Z8+exS+//IIZM2ZArVaX6rvs2bMHr732GvR6PWrVqoUmTZqgRo0ayMjIwG+//YbffvsNL7zwAiZMmHDLbSmVSrzxxhsYO3Ys7rvvPiQlJZWqTKRqoSC1CmrUqBE++ugjn6/l5ORg/Pjx2LNnD+bMmYPvv//+DpeO+LJy5Ups2LABSUlJ+PTTTxEVFSW9Zjab8e6772Lt2rWYMGECfv75Z+m1CRMmYPTo0ahdu3ZFFPu2zJ07FzabrVyD7ieffBIDBgwotPynn37C9OnT8fbbb2P16tXl9vmk7CxcuBBZWVn4z3/+U2bb9PUbLM9mfp7nMWnSJFitVgwZMgRTpkyBUqkEYwyfffYZFixYgE8//RTTpk2T3nP58mWYTCb07NmzyOt6fj/++CPuvfdeLF++HDKZDEuXLsXMmTOxc+dO9OzZU1pv3rx5qFevHh5//PFSfZfU1FSMGjUKMpkMU6ZMweDBg6FSqaTX9+zZg1dffRVff/01wsPD8dxzz91ymz169EDbtm0xY8YMrF+/HnK5vFRlI1UHNfdXMzVr1pQugKmpqbfVzEPKzvr16wEAU6dO9QpQASA0NBTvvvsuYmJi8Pfff+P06dPSazExMWjUqFGhmpfKoE6dOmjUqFGpa3Fux6BBgxAXF4cTJ07gxo0bd/zzScnodDp8//336NOnD2JjY8tsu3f6N7h3715kZmaiUaNGmDp1qlSzyXEcXnnlFWi1Wixbtgw6nU56j+d8b968+S23bzAYkJubi3bt2kEmc9/eO3ToAAC4ePGitN7Ro0exbds2jBs3DgpFyeuqLBYLXn/9dbhcLrz33nsYMWKEV4AKAMnJyZg3bx4Ad+2uyWTya9sjR47E+fPnsW7duhKXi1Q9FKRWQ3FxcQDcNQZ5eXlerxkMBrz33nvo2bMnWrZsic6dO2PKlCnIzMyU1jl37hzi4+Px5JNPFtr2+PHjER8fjw8++MBrOWMMycnJ6NixI1wuFwB3rcKPP/6IwYMHo3379mjRogU6deqEsWPH4siRI17vX716NeLj4/HTTz9h1qxZSEhIQFJSEr744gtpHU8zWvv27ZGUlISJEyciKyurxPtHp9Nh1qxZ0j5ITk7Gf/7zH6/g0CM+Ph5PP/009Ho9pk2bhs6dO6NVq1bo168ffvrpJ78/02AwFPu6SqXCs88+iyeeeMKrdqGoPql6vR7vvvsuevbsidatW6Nfv35Yt24d1q1bh/j4eK/aQ09/N57n8fnnn0vv6du3L3799VcA7hvcSy+9hMTERHTq1Anjxo3DtWvXCpWT53n897//Rb9+/dC6dWu0a9cOw4YNw++//15o3aL6pJ49exavvPIKOnXqhISEBIwZM6Zc+o/GxMQAcN9wCzpw4ACef/55tG/fXtoXixcvhiAIXut5fpcrVqzA3r17MXToUCQkJCAxMRFjxozx+ZsBgMOHD+Pll19GSkoKEhIS0L9/f3z//fdF9kncuHEjnnjiCbRu3RqdOnXCxIkTC+1/Tz+/1NRUrFu3Dv3790fr1q3RvXt3fPbZZxBFERaLBbNmzULnzp3Rtm1bDBo0CAcPHiz0eRaLBQsXLsTjjz+OxMREqZ/hxIkTcf78eZ+f+8cff2DixIlSGVesWFHkvt+5cydatmyJhISEQue6Lz/++CNsNptXrd/cuXMRHx+P5cuXFyp7ixYtEB8fX6isf/75J+Lj46V+jwV/g/Hx8VizZg0A4D//+Y+0P/PT6XR46623kJKSIp1bxX3X/M6dOwcASElJKRQcymQyJCYmQhRF7N27V1p+6tQpAPCra1ZoaChkMplX5YOnL3twcLC07OOPP0Z8fDweeeQRv8pd0JYtW3D9+nW0atUKjz76aJHrpaSkoFevXujcuTOuX7/u17a7d++OyMhIfPfdd6UqG6laqLm/GtqxYwcAICIiApGRkdLyy5cvY9iwYbh27RoaNGiA7t27IzMzE6tXr8a2bdvwf//3f2jWrBmaNGki1UKZzWavWrz9+/cDcAeM+Z08eRJ6vR79+vWDTCaDy+XCCy+8gD179iAqKgpt27YF4L4gb9u2DTt37sSyZcvQunVrr+0sXrwYV69eRefOnXHlyhU0atQIgPuiOX78eLhcLiQmJiIsLAx//vknjh07BqfT6fe+SUtLw7Bhw6DT6dCgQQP07NkTV69exebNm7F161bMmzcP999/v9d7TCYTBg0aBKPRiISEBNjtdhw4cADTp0+HyWTC6NGjb/m5TZs2xYULFzBt2jS89957Pm9II0eO9Os73LhxA0OHDsWlS5fQsGFDdO/eHWfOnMHrr79eaH/m9+KLLyI1NRWdOnVCXFwcDh48iAkTJiAnJwefffYZQkND0aFDB5w8eRJbtmzByZMnsWnTJqkGxWaz4dlnn8WRI0dQs2ZNdOnSBVarFQcOHMD+/fsxcuRITJ48udiyHz58GKNGjYLVakWbNm0QGxuLAwcO4Omnny7Tpj+bzYa0tDRERESgXr16Xq/99NNPmDFjBuRyOVq1aoWoqCgcOnQIc+bMwa5du/D1118XCjC2bt2KP//8Ew0aNEBKSgpOnz6N7du3SwFj/fr1pXVXrlyJt99+Gy6XC23btkWtWrVw+PBhzJ49G4cOHcJnn30GjuOk9VesWIH09HQ0bdoUXbp0wd9//41ffvkFBw8exK+//lqoFn3RokXYuXMnEhIS0LFjR6SmpuKrr76C1WrFoUOHcOnSJSQkJCA7OxtHjhzBiBEjsHbtWjRu3BiAO8gbNGgQzp49i7p166JDhw5wOBw4ceIEfvnlF2zfvh0bNmxA3bp1vT73ww8/hE6nQ5cuXXD27FnEx8fDZrMV2vdHjhzBuHHjIJfL8fXXX/s1GGn9+vUIDw/36qfYtWtXfPfdd9i3bx+efvppafnBgwelc/7gwYPS9wKAXbt2AXAHQr707dsXR48exeXLl5GYmIi4uDivlg1BEPDUU0/BYDCgQ4cOMJlMOHjwIKZNmwaLxYIRI0YU+z08D+hFtXx4fuP5H8o8Qaper8eIESNw8uRJiKKItm3bYty4cV7ntEqlglarxaZNmzBw4EDExcVh0aJF4DgObdq0kfbB/v37sWDBAq/fWUls2rQJAPDQQw/dct2vvvqqRNtWKBTo0qUL1q5di3/++QetWrUqVRlJFcFIlbFv3z6m1WrZ0KFDC70mCAK7fv06+/nnn1liYiLTarXsu+++81rnySefZFqtli1YsIC5XC5p+apVq5hWq2W9e/dmTqeTMcbYW2+9xbRaLdu2bZu03rlz55hWq2XNmjVjLVq0YFarVXpt4cKFTKvVsl9++YUxxtj69euZVqtlzzzzDHM4HNJ6PM+ziRMnMq1Wy958881CZdBqtWzfvn3SclEUmclkYh07dmTNmzdnO3bskF7Lyspiffr0kd53Ky6Xi/Xr149ptVr2ySefMFEUpdc2b97Mmjdvzu699152/fp1abln20899RTT6XTS8nXr1jGtVsuSk5Nv+bmMMXbmzBl27733Stvr3bs3mzFjBtu4cSPT6/VFvm/y5MlMq9WyTZs2ScvGjx/PtFote+edd6TjJYoie//996Xtr1q1Slp/6NChTKvVsvbt27Pz589Ly+fOnSutP2HCBMbzPGOMMYvFwnr37s20Wi3766+/pPXfffddptVq2ciRI5nJZJKWnzt3jnXu3JlptVr2+++/F/rcY8eOMcYYczqd7KGHHmJarZb9/PPP0nomk0laV6vVssuXL99yf3r2S/7vyRhjdrudnTp1io0aNYpptVq2fPlyr9fPnDnDWrRowTp16sSOHz8uLbdYLOz5559nWq2WffXVV9Ly/L/L/OeNIAjSZ3zwwQfS+pcvX2atW7dmbdq0YampqdLyvLw81rdvX6999Pnnn0vbLrg/HnzwQabVatnKlSul5fnX37hxo7T8zz//lJY/9NBDLDs7W3rttddeY1qtln344YfSsgULFjCtVssmT57sdQ5YLBY2bNiwQvvA87ktWrRgFy5cYIwx6X2ea9Lzzz8v7d+kpCTWsmVLr3O1OOnp6Uyr1bLRo0d7LXc4HCwhIYF17NjR63o1d+5cFh8fz+Lj49mECRO83vPAAw+whIQE6ZpT8DfImO9zirF/z/VHH33U65z83//+x7RaLevevfstv8uWLVuYVqtlw4cP9/n6448/zrRaLZs+fbq0rHv37tJn9+vXj7300kvsgQcekPb5li1bvLaxe/du1rJlS+k9Wq2Wvfvuu4wx9zXuscceY0899dQty1qc++67j2m1WrZ///5Svd/zm/n88899vv7zzz8zrVbLvv7669spJqkCqLm/Ctq/f3+hKUpatGiBrl27Ytq0aeB5Hq+++qrXU//hw4dx9OhRJCUlYcyYMV5P2AMGDECvXr2Qnp6OnTt3AnDXYgDAvn37pPU8zWIPPPAABEHA0aNHpdd27doFuVyOzp07A3A3//fo0QMTJ0706sukVCqlJj1fzclNmjSR+lgB7iay33//HQaDAY8++ii6dOkivRYdHY3p06f7vd9SU1Nx+vRptGjRAq+++qrUpwsAevfujaeffhpWq9VnM/6kSZO8aqX79u2L8PBw6HQ6GI3GW362py9aixYtALinqFm2bBleffVVJCcn4+mnn/bZZF6QXq/Hxo0bUadOHUyZMkWqmZHJZJg0aRLuueeeIt87bNgwqWYaAB588EEA7v5yngEegLvZ0HMcL126BACw2+34+eefoVar8eGHH3rVFDVu3Bhvv/02AHdNeFEOHTqE8+fPo1OnThg4cKC0PDQ0FLNnzy5Vrc+UKVO8zoPWrVujf//+2LlzJ0aOHIlBgwZ5rb9kyRIIgoCJEydKx8LznWfNmgWVSoUlS5ZINWIeDRs29DpvFAqFtO38072tXbsWdrsdzz77LNq3by8tDwsLw4QJE3DPPfd4da0BgPbt2xfaH55z5OzZs4W+c/v27dGnTx/p/926dZOael9++WWvmsEHHngAwL/HEQCCgoLQtWtXjB8/3uscCA4ORt++fQH4PjdTUlKk31f+93lcvnwZo0aNgsViwbx587zO1eIcOHAAgPscyU+lUqFTp04wGAw4c+aMtDw1NRVarRYNGzb0atG5cuUKMjIykJKSUqj/ZEm88cYbiIiIkP7/xBNPICQkBFevXoXZbC72vZ07d0ZERAT27dtX6FxYtGiR1O3A0+0jNzcXV69ehVKpxPz587Fu3Tp88cUX+O233/DWW29BEARMnjzZq7tQcnIyVq9ejTFjxmDYsGH48ssvpXEIv/32G06cOIFXX31VWp/n+VuWuyBPN6r817yy5JlWy9MyR6ovClKroMjISPTt2xd9+/bFww8/jCZNmgD4d4qPXbt2YezYsV43fc/FIH8AmJ8nKPGs16lTJyiVykJBalhYGJ566ikAkPq6mc1mHDlyBAkJCahRowYAoF+/fli4cKFXU47ZbMbhw4fx559/AoDP/nkFb1T5P8dTxvzat2+PsLAwn9+pqO088MADPgMiT9NWwT58HMcVapLiOE66gPtq8vSlWbNmWL16NVasWIGxY8ciISFBGvnr6cM4derUYkcfp6amgjGGbt26eU03A7ibEgt2Vciv4HeoVasWACAqKqrQYK7w8HAAkPq+/fPPP3A4HEhMTPS6gXv06NEDGo0Gf//9d6F+nR7FHcd69er5PPa3kpCQIJ0Lffv2Re/evZGYmAiNRoPvvvsOEydO9PqdFXceREdHo2nTptDr9YX6yPpqkvTss/zz23q+o6/m5u7du2PTpk145plnCn2Hgjz9yn0NRvHVpaNmzZoA3N1K8vOcG/n7MD7zzDNYtGiR14wROTk52Ldvn7R/fB3D4o6PwWDAqFGjkJWVhcGDB+O+++4rct2CPH0Z69SpU+i1gg/LJpMJp06dQvv27XHvvffi2rVr0ry6nqZ+f6ZxKk7B4yGTyaT+zbcaHBQUFITZs2dDqVRizpw5ePDBB/HSSy+hT58++PTTT6WHEU93kho1amDv3r349ddfpQcKj6FDh+KBBx6AxWKRBl56NGnSBOPHj8e0adOkfS2KIj777DOkpKSgY8eO4Hker7/+OhISEtCuXTsMHDiwUB/eonjKV5KuVCXh6UpCgxoJ9UmtgnxNQbVkyRLMmjULX331Fdq1a1foRua5EXzxxRdeg5EK8lw0QkJC0K5dO6SmpsJoNKJmzZrYv38/EhMTce+990KpVEo35NTUVAiCUOjmkJubi+XLl2PXrl24cOGCVBtQXI2ZJzjKLzs7GwB8TsPEcRzq1KnjVdNSFM92fN0MgX8vnJ71PDQajc+aGc+FvGCt2620bt1aOj5WqxX79+/H//73P2zbtg2rVq1CUlISHnvsMZ/v9RxHTxBTUFHfDYD0AOHhOQ6eAMfXax632ncKhQKxsbHIyMhATk4OoqOjC61T3HEE3Pvfn+OYX1FTUBkMBrz44ov45ZdfUKtWLammybP/evXqVex2b9y44dXX0deDkKcWO/9Dhec7lmSEenHb9vXbKngcgX+PV1HHuKAbN27gxx9/xP79+5GWliYNsPSs7+tByde56XHs2DFwHAeZTIa1a9fihRdeKPTgUxTPdcFXP878QeqIESNw4MABiKKIpKQk5OXlYc2aNTh48CDuuusu7Nq1CxzH3VaQeqtzXRTFW26jR48eWLp0KebPn49Dhw4hOzsbCQkJmDNnDi5fvowVK1Z4HfOIiAifD36A+8Fmy5YtOHHixC0/d82aNUhLS5MGtS5YsAAbNmzAiy++iPr16+Ozzz7DuHHjsGHDhluO+I+KioLZbL7lgM/S8nx/vV5fLtsnlQcFqdXEsGHDkJ6ejqVLl2LMmDHYsGGDV1ON52bXtm3bQgMi8ss/iXa3bt2wb98+pKamomHDhjAajUhMTERQUBBatWol1Zr5Gqxw5swZDB8+XApYEhIS0LhxY7Ro0QIhISEYNWqUz8/31Yx4q2Zgf6dYKa6GMv/rBW9SpR184JGbm4u0tDTUrFkTd999t9drwcHB6N69O7p37465c+fiu+++w6+//lpkkOqp2SgqMC7uO97OwKRb7bv8ZSqqqbWsjqM/IiIiMG3aNDz++ONYsWIFpk6dCplMBlEUwXHcLUc9+xvsFeRPEFOQr998cW53gNnevXsxZswY2O123HXXXUhOTkajRo3QqlUrGI1GTJkypVTlfPPNN3Hx4kUsWbIEs2fPxieffOJXeYr7TcfFxUGr1eLgwYMQRVHqcpSUlCTVah46dAiPPPII9u3bh+bNm/t8QPJXSY9FUdq0aYP//ve/hZZ7ulMV9zCZnyfQt9vtxa7H8zy+/PJL3H///VKt/7Jly9CtWzeMGzcOgDsAf+WVV7B79+5bBvItWrRARkYGjh07ho4dOxa77l9//YWMjAx069YNDRs29Ot7ec6T0pwvpGqhILUamTRpEv766y9cuXIFM2bM8EpJ57lw33fffUUGiAV17doVc+fOxb59+6QaIk8/u/bt2+Pw4cM4fvw4du3ahTp16ng1B86aNQs5OTmYOHEiRo8e7XWT3717d4m+l6ep7erVq9IsAfn5Ow2VZzsF+wR6eJoNy7of1o4dO/Daa69JTX5FGTBgAL777jvk5uYWuY6nFtJXn0EAfk8DU1K32neCIOD69etQKpVF1rjlP46+FKzBvl2ebjB2ux0GgwFRUVGIiYlBZmYmpk6dWmTt1e2IiopCeno6bty4UajGmOd5rFixAo0bNy6y2015Y4zhrbfegt1ux0cffST1QfXIn0iiJJKTkzFs2DCYTCZs2rRJetDyp1+q54GgqL7dXbp0wbfffosTJ07gwIEDaNSokVT7GBMTg/379+Po0aMwmUxFjuq/U+x2O44fPw6VSuWzW4anO4WnP/TevXuxatUqtGnTBsOGDSu0vueadKtkHsuWLcP169exaNEiAO59mZOT49UH3dMy4Akoi9OjRw/8+uuv+OOPP/D8888Xu+6iRYtw4MABmEwmvPzyy8Wu6+GpofXVKkCqF+qTWo0EBQVJA4m2bNkiTUUFAO3atQPw75N8QR999BEee+wxbNiwQVrWuHFj1K1bF/v27cOhQ4cQHBwsTTjtmSpm5cqVuHTpUqGL3rFjxyCXy/Hcc88VqoXy1Lz620zueZIvmGsbcE/f4m9w49kHv//+u8+aQc9cpImJiX5tz19t2rQBx3HYvn17kcEl4L55APBqZi4oKSkJHMdh165dPvuL/fXXX7ddXl9atGgBjUaDQ4cO+WwC/PPPP8HzPNq1a1dkraPnOG7durXQa3q9vszytXt49qdGo5G6NHgecvKfGx52ux39+/fH0KFDS90M6enP6PmN53fkyBHMnDkTy5YtK9W2y4LBYMDly5dRt27dQgEqUPJz08NTex4WFoZJkyYBAN55551b1gACQIMGDQAU/bDpafLfunUrTp8+7TVNVfv27ZGRkSHNfepPkHq7LSPFEQQBw4cP9zkVW0ZGBg4ePIi4uDipttPhcGDDhg348ccffe5zz/U4JSWlyM+0WCz4+uuv0a9fP+na4bm+5e9b7DkW/tTE33///ahbt640HVpRtm/fjoMHD0KlUuGJJ5645XY9PNdsz7En1RcFqdVM165dpcEzs2bNkgaNdOrUCU2aNMHevXuxYMECrwvijh078H//9384ffp0oQEiXbp0QXp6Onbt2oW2bdtKTbKef69duxZA4ZtDbGwsRFEsFAysX78eS5YsAQC/s2H17NkTdevWxebNm72ylOTm5uKtt97yaxuAO0jSarU4ceIEPv30U6998Mcff2D58uUIDg4udvLq0qhfvz4efvhhadT34cOHC63z999/Y9asWZDL5Rg6dGiR26pTpw569eqFzMxMfPTRR17f4csvv5TmXCzrG3FwcDAef/xxOBwOTJo0yWu0cFpaGmbNmgUAGDx4cJHbaNOmDVq3bo2///4bCxculJY7HA68+eabRQ64Kg2z2YzZs2cDcA+I8/xuhw4dCo7j8OGHH+LYsWPS+k6nE++++y5Onz4Nxlipa9OfeOIJKJVKfPvtt17bz8vLw4cffggApZ5gvSzUrFkTGo0GN27c8EpE4HK58O233+K3334D4P+56cujjz6KpKQkXL58GV9++eUt1/fM75l/f+XXrl07hISEYOnSpRBF0WvWBM+/165di8jISL/m3PQE1P5mSCqJsLAwtGvXDmlpaV4JNYxGI1577TWIoogxY8ZIgWJycjLq1q2LjIwMzJs3TzqfGWNYsGABjhw5gubNmxdb87l48eJCtZieObL37NkjnVeea3H+2tWiaDQaTJs2DRzH4Y033sDSpUsLDXTdvn07XnvtNTDG8OKLL5aoH7ZnZhh/5tAlVRs191dDU6ZMwc6dO3Hx4kUsWrQIL730EjiOw8cff4wRI0bg008/xYoVK9CsWTPo9XopI8yMGTMK9Snq2rUrfvrpJ5hMJq+bQ3BwMFq2bImjR49Co9EU6rc0fPhwzJw5E2PHjkVSUhJq1KiBM2fO4OLFi2jYsCEuX77slRqwOEFBQZg7dy6ef/55vP7661i+fDmio6Oxf/9+qNVqxMbG+tXMzXEcPvnkEzzzzDNYuHAhNm3ahGbNmuHatWv4+++/oVarMXv27GL77JaWp/vDrl278PTTT6Nhw4a45557oFAokJ6ejnPnzkGpVOLdd9/1mhrJl2nTpuHYsWNYvHgxtm/fLiUKOHfuHOrVq4fLly+Xaf9Oj9dee03q3tGrVy8kJSXBZrNJA+eeffZZ9O7du8j3cxyHOXPmYPjw4Zg3bx42btyIhg0b4ujRozCbzWjcuLHfo489fv75Z+zZs0f6P2NMmkUiLy8Pd911FyZMmCC9fu+992LChAn4+OOPMWjQILRs2RIxMTE4fvw4rl27hujoaMyZM6fkO+emBg0aYOrUqZg5cyYGDRqEpKQkBAcH4/Dhw8jJycGAAQOKnYGhvJg6a7AAACAASURBVMnlcgwZMgTffvstnnjiCXTo0AEajQbHjx/H9evXpWPg77lZlLfffhuPPfYYFi9ejL59+xY7M0CTJk1Qt25dHDt2DDzPF+rTrFQqkZycLE3Rlr8m1fNvp9OJrl27+vVw5rnGffzxx9i5cyeeffbZMg2WZsyYgQEDBmDKlClYuXKlNOjUZDLh0UcflWZHAdwB8wcffIDRo0fjm2++wZYtW6RMWhcuXEB0dDQ+/fTTIvvKGo1GLF68GAMHDiyUtGLw4MGYP38++vfvj7i4OOzevRtt2rS5ZR9Tj549e+LDDz/ElClTMHPmTHzxxRdo3rw5QkJCcObMGamlYuTIkRgzZkyJ9pHnQb1Hjx4leh+peqgmtRqqW7cuXnjhBQDAN998I/Vrio+Px9q1azFkyBAA7qbhzMxMdO3aFT/88INXVhcPz1RUQOFmcM8NwnOjy2/IkCF4//330bRpU/zzzz/YsWMH1Go1Xn75ZaxZswYtWrTAtWvXikwrWVBSUhL+97//oXfv3sjIyMCuXbuQkJCAH3/80e8pqAD3DXHNmjUYPHgwBEHA1q1bce3aNfTv3x8rVqzwmn+yLAUFBeHbb7/F559/jj59+kAQBOzbtw87duyAIAgYPHgw1q1b55UWsihxcXFYuXIlBgwYALPZjK1bt0KhUOCzzz6TRq0XlfHmdgQHB2PJkiWYOHEiYmJisGPHDhw/fhwdOnTAwoUL8cYbb9xyG40aNcLPP/+MAQMGwGAw4K+//kKDBg3www8/4K677ipxmY4cOYINGzZIfzZu3IjDhw+jYcOGeOWVV7B27dpCA2mef/55fPvtt0hOTkZGRgZ27NgBjUaD4cOHY82aNYVu9iU1ePBgLF68GJ06dcKJEyewc+dOREdHY+rUqXjvvfdua9tlYcKECXjjjTfQsGFDHDx4EHv27EFkZCSmTJmCtWvXIioqCkePHr2tkd1arRbDhg2DIAh4++23ix14x3EcBgwYAJ7nfXbDAP5t8m/QoIHUtxkA7rnnHun4+juqf9CgQXjkkUfA8zx27tzpcy7a29GoUSNp0NLp06eRmpqKu+++G3PmzMH7779fKJBOTEzEqlWr0LdvX5jNZmzbtg02mw1DhgzBunXrim0S/+abbyCKIsaOHVvotRdffBFjx46F0WjEwYMH0atXL8yfP79ErSx9+/bFunXrMGTIEERERODQoUPYunUrbDYbHn74YSxbtgyTJ08u0TatVit2796N5s2b+5UKllRtHPNnWC4hpFJwOBxIS0tD3bp1fQ5QGjt2LLZt24aNGzf61axHSCDIzc1Fjx49kJSUhK+//rqii0PK0cqVK/Hmm2/i888/L7blhVQPVJNKSBUiCAKeeOIJ9OnTp9Dgnl27duGvv/6SuhIQUlnUqFEDw4YNw86dO3H58uWKLg4pR8uXL4dWqy2UvIBUT1STSkgV884772DZsmUICgqSBpVkZmbi+PHjCAkJwX//+1+fU3UREsisViv69++PVq1a+T3HKqlcNm/ejPHjx+PHH3+UZlsh1RsFqYRUMYwxrF+/HitXrpSyBUVHRyM5ORnPPfec3xNqExJoDh06hOHDh2P58uU+5xkllZcgCHj44YfRq1cvn1N0keqJglRCCCGEEBJwqE8qIYQQQggJOBSkEkIIIYSQgENBKiGEEEIICTgUpBJCCCGEkIBTpdKiulwMer351iuWgRo1ggAAubm2O/J5JDDQca+e6LhXT3Tcqyc67ndedLTvzJBUk0oIIYQQQgIOBamEEEIIISTgUJBKCCGEEEICDgWphBBCCCEk4FCQSgghhBBCAg4FqYQQQgghJOBQkEoIIYQQQgIOBamEEEIIISTgUJBKCCGEEEICToVmnHI6nWjbti0cDofX8uDgYBw5cqSCSkUIIYQQQipahQap6enpcDgcmDt3Lho2bCgtl8mogpeQQCO6GKy8iCClDAo5naOEEELKV4UGqadPn4ZMJkPv3r0RFBRUkUUhhPjgYgxmhxN5dif0Fh4WXkS9mkGoV4vOV0IIIeWrQoPUU6dOoX79+hSgEhJAGGOw8CJy7QL0Zh4mhwi7IEKllIExhiyzA7HhaiipNpUQQqoEF2NwOF1wOF3gnS6EaxTQKOUVXayKDVLPnDkDlUqFUaNG4fDhw1AoFOjTpw9ef/11hIaGVmTRCKlWPIGpyeGuMc2zO2ETRKjkMoSo5KgVrADHcXCKLugsAoxWATFh6oouNiGEkBJgN4NRXnRJQanF4YSZFyGILvAiAwNDfHQoYgMgSOUYY6yiPjwlJQVmsxkTJ05Es2bNcPz4ccyfPx8tWrTADz/8AI7jSrQ9xhgEQSyn0npTKNwHz+m8M59HAkNVO+4WhxO5NgE6M49cmwAr74RCziFUrUCwSu7zHLyea0dMmAat6oaX+BytrKracSf+oeNePVWV4847XXA4RdgFF+xOEVaHCJNdAC8yOJwihJsBqVzGQSWXQa2QQSmXIdvMo1WdcNSpeedauVUq33WmFVqTOm/ePNSoUQPx8fEAgKSkJERGRmLSpEnYs2cPUlJSKrJ4hFRJNl5Erk2A3uKA0SrAwjshl7kD07hgDWS3CDzDgxQwWt1Bbc1g1R0qNSGEEF8ET62oIMLudMHmEJHnEGB3uiDcbL53gUHGuYNRlUKGcI0CSoXM5/U+kKoeKjRIbd++faFl3bt3B+AeVFXSIJUxIDfXVhZFu6UaNdxPGHfq80hgqKzH3S64m/INVgE5Nh4WhwiZjEOISo4wpRwyGQcIIqx+tkQYcu3IUHC4OzKknEseGCrrcSe3h4579RSox110MXcz/c2aUbtThPnmmAFeZBBEF0QXA8cBSrnsZkDKIUQmyzdrEgOcIgQnIDh8f47F4oDJZEfuHYxWo6PDfC6vsCBVr9dj27Zt6NixI+rVqyctt9vtAIBatWpVVNEIqRIcThdMdnf/UaNNgIUXwYEhWKVA7TC1OzAtpRC1HNlmHnHhmoDoXE8IIVUFyzeISeo3yjth4UXwors/qSi6azwVcg4qBQeNUoYwjQKK27iuB6IKC1I5jsPbb7+N4cOHY8qUKdLyjRs3Qi6Xo127dhVVNEIqLUF0Ic/uRI5NgOHmlFGMMQSr5YgKVZXZBSxUpUCWiYfRJiCOglRCCCkxxhh4kf3bd9TpgpUXYeGd7mDU6a4dBdzBqKd2NEQlrzazq1RYkBoREYEhQ4ZgyZIlCA0NRWJiIg4dOoSFCxdiyJAhaNCgQUUVjZBKxSm6kOfwDkxdLiBIJUNkiLJcJt6XyTgo5ByyTA7EhKohr2JP74QQUpYE0btm1CaIMDuc0pRPgouBMQbZzUFMKjmHcI0cSjlXbQao+lKhfVInT56M2rVrY9WqVfjmm29Qu3ZtvPLKK3juuecqsliEBDyni8FsdyLHzkNvEWDmnRBFhiCVHLWClXfkKTtMo0Cu3Ylcu4AIGkBFCCFwuv6tGXU4XdJ4ALvgnt7J6XLB6WKQcYBKLoNSIUOoRgGlnLvloNXqqEKDVKVSidGjR2P06NEVWQxCKgXRxWByOJFnE6C38jA73PPaaZRy1AxSQnWHm3/UChlEkUFn5ilIJYRUKy7mDkbt+WpHzTfnl+ZFF3iXC6LI3P1GFe6a0WCVDEq5glqeSqBCg1RCSPHypyXVmXl385DokjrJqxUV2y8pVCOHwcrDwjsRUsQ8d4QQUll5+o16akZ9TX4v3pxvVCH/d77RULm8XLpaVTd0VyEkwDDGYL45z52UltQpui98GjkiFYFTaxmskuN6nnu+VQpSCSFVAWMMN0wOZGabYXaIcIgihJuDmBggTX6vVHAIVsmhkFXvfqPlie4qhAQAT1rSPLsTeosDJofoTkuq8E5LGmhknHvqkxsmB2qHqavNiFNCSNV1LdeOc1lmGPNsUCncI+rDNHIoqN/oHUdBKiEVhDEGqyDCZHdCb+GRd7M/k0LOIVSlQM2gwAxMCwpXK6C3CMixCYgOVVd0cQghpNR0ZgeuWp1gYIgN11R0cao9ClIJucNsgjstqdEqINcuwMq7oJC7m87Dg9SV7kldIZcBHKAz84gKUVWKwJoQQgoyWnmk6a2Qq+SICdfAbC4iJRO5YyhIJeQOsAvupnyDlUeuXZDSkoaq5Kgdrqp0gWlBYWoFDFYBJocT4RplRReHEEJKxGR3Ik1nhU0QcXdkcEUXh9xEQSoh5cThdCHvZlrSHJsAi8MJTubuaH+7aUkDTbBKjhyrO5kABamEkMrEwjtxQWdBnt2JmHBqDQokFKQSUoZ4583sT1YeBqsAKy+CgSFEpUB0WNXOzBSiliPbzCM2XAMNpUolhFQCdkFEms4CvZV3Vx5QgBpQKEgl5DY5RZeUeSl/WtJgtQyRoSooqnBgml+oWoEskwM5NgGxFKQSQgIc73QhXW9FlplHTKiqSlciVFYUpBJSCk4Xg8kuINcmuNOSCu60pMEqOSKCldVyEme5jINCziHL5EB0aNWuNSaEVG5O0YV0gxXX8uyIClVVy2t2ZUBBKiElILoYrhituHAtD5abGUeCKygtaSAK1yiQa3cizy6gFqVKJYQEINHFcNFow9UcOyJC6NodyChIJcRPvNOFc1lmXDJY4XSKqKFRQFXBaUkDjVohh0EUoDPzFKQSQgIOYwyXc6y4bLQhPEgBtYK6JgUyClIJ8YPtZuf6PJEhMkQFUUFN2UUJ1ShgsPGw8E5KlUoICRiMMWTm2nHRaEOIWo5gFQWogY6qgQi5hTy7gDM3zLie50BMmBpBdGErVohKDrNDhNEqVHRRCCFEcsPkQIbeCrVchlA1PUBXBhSkElIMnYXHmRtmGK08aoerqXnfDzKOg0YhQ5bJAafoqujiEEIIdGYH0g1WcDKgRhDN5VxZ0B2XEB8YY7iWZ8e5LDNsThEx4TRavSTCNAqYHE7k2Kg2lRBSsTzpTgXRhQjqK1+pUJBKSAHukZ9WnMu2gAGIDqUJnktKKZeBMYZsMw/GWEUXhxBSTeXZBSndaVQIBaiVDQWphOTDO11I01mQrrNCo5ShVjA1C5VWmEYJo02AyeGs6KIQQqohC+9Ems6KPLsTUaGU7rQyoiCVkJtsgohz2WZcyrGhRrASYdSx/rYEKWWwCSIMVr6ii0IIqWY86U4NVh7RYSpqDaukKEglBO4mobNZ7hH8UaEqBFFaz9vGcRyCVXJkm3g4nDSAihByZ+RPdxpN6U4rNQpSSbWns/A4m2WGwSK4R/BT9pEyE6Z2D6AyUm0qIeQO8KQ7vUrpTqsEOnqk2pJG8GebYeFFxITTE3dZk8s4KOQcss0OuGgAFSGkHHnSnWbm2BFJ6U6rBDqCpFoSXQyXjDacz7aAMSAmjEbwl5cwtQK5NifybDSAihBSPlz50p3WpHSnVUapglSXywWdTgeepyY8UvkIonsEf5rOAjWN4C93GqUcvOiCzuKo6KIQQqogxhiu5kt3SlkBq44SBakXL17EuHHj0K5dO3Tt2hWHDh3C3r17MXDgQBw8eLC8ykhImbEJIs5nW2gE/x0WqlZAb+Vh5cWKLgohpIqhdKdVl99BakZGBgYOHIj9+/ejS5cu0gTdcrkcaWlpGDlyJI4ePVpuBSXkdnlG8Gfm2mkE/x0WopbD7BBhtFHrCyGk7OjMDqTrKd1pVeV3kPrJJ59Ao9Fg48aNmDFjhhSktm/fHhs3bkRUVBS++OKLcisoIbdDn28EfyyN4L/jZBwHtUKGLJMDTpGmoyKE3D4p3amL0p1WVX7fqfft24enn34akZGRhbI21K5dG4MHD8bx48fLvICE3A7PCP6zNIK/woVpFMizO5FjpwFUhJDbQ+lOqwe/g1Se5xEeHl7k60qlEg4HDYwggSP/CH4XYzSCv4Kp5DK4GIPO7JBaYgghpKQo3Wn14XeQ2rRpU2zbts3na06nE+vXr0d8fHyZFYyQ2yGILqTrLUjXW6FWyKgpKECEaRQwWgWYHTSAihBScvnTncZQutMqz+8g9YUXXsCePXvw2muvYd++fQCAzMxMbN26FcOHD8fJkyfx7LPPlltBCfGXNILfaEO4RoEwDY32DBTBSjmsghMGykBFCCkh3ulCmu5mutMwNWTUdavK41gJ2t1Wr16N2bNnw2KxgDEGjuPAGINarcb48eMxYsSIcizqrblcDHq9+Y58Vo0aQQCA3FzbHfk84h+T3Yk0vQU6C4+oEBVUirIdIBUaqgYAmM3UtaW0cqwClHIOrevUKPPjU17ofK+e6LgHDqfowgW9FVdybIgKVZXr4Nfqfp2/lmtH89gwxIZr7thnRkeH+VxeoiqmAQMG4IEHHsCePXtw6dIluFwu1K1bF8nJyahVq1aZFJSQ0tJbeGTo3f2UYsLUUNBTdkAK1SigMzlgtAmoHaau6OIQQgKc6GLIMFC60+qoREfabDZjw4YNSElJwXPPPYfnn38eNpsNv/76K+x2e3mVkZBiMcZwPc+Oc9lmmHknYsJVFKAGMIWMg0zGIdvsgIsGUBFCiuFJd3olh9KdVkd+B6mZmZl47LHHMHPmTKSnp0vLDx8+jFmzZmHgwIEwGAzlUkhCipJ/BL9II/grjXCNAjlWAXk2mo6KEOKblO7UQOlOqyu/g9SPP/4YJpMJ3333HVq2bCktnz17NpYuXQqdTodPPvmkXApJiC/5R/CraAR/paJRysGLLuhpABUhpAiedKcaJaU7ra78DlL379+PkSNHolOnToVea9euHYYNG4YdO3aUaeEIKYqdRvBXeiFqOXQWB2wCTUdFCPGWnS/dabiG0p1WV34HqVarFSpV0TVVoaGhyMvLK5NCEVIck92Js1lmXM2zIzJERU1AlVSoSgGzQ4TRKlR0UQghAcRo5ZGut8LpYtRCVs35HaQ2b94ca9asAc8Xbp4TBAHr169H06ZNy7RwhBRksPI4m2WGzsIjJkxdaaYwIoXJZBxUChmyTA44XTSAihDine40MoRqUKs7v9tIR48ejTFjxuCpp57CwIED0aBBA3Ach0uXLmH16tU4efIkvvrqq/IsK6nGGGPu/kkGK+xOF2qH0wCpqiBcrUCOXUCOTaD824RUcxbeiQs6C/LsAmLC1ZTulPgfpHbr1g0fffQR5syZg5kzZ0o/HsYYIiIiMGfOHHTv3r28ykmqMdHFkJljwyWjDRwHmluzClEpZO4kHBYekcFKuikRUk150p0are75k6kSggAlnMz/4YcfxkMPPYTjx48jMzMTLpcLcXFxaNmyJZRKqpYnZU8QXbhosOJKjh1BKhl1oK+CwtQKGKw8LLyGRvASUg3xThcu6CzIMru7cVG6U+JR4jsCx3Fo1aoVWrVqVR7lIURiF0Sk6624lmdHzSAlDZCqooJVclzLc8Bg4SlIJaSacYoupBusuG5yICqUErEQbyW6I5w/fx6//PILdDodRLHwtDEcx2H27NllVjhSfZkdTqTpLMi28IgKUdEAqSqM4zgEKeXINvOIDdfQsSakmnCnO7VSulNSJL+D1M2bN2PChAlwuVxFrkNBKikLBiuPdJ0VuXYBMWFqerKuBsI0CujNPHJs7mNOCKnaPOlOLxttqBmkpHSnxCe/g9Qvv/wSderUwSeffIKmTZsWO2cqIaXhGcF/0WiFTaAR/NWJQsaB49wTeEeFqui4E1KF5U93GqpRUFcuUiS/69YzMjIwYsQItG7dmgJUUuZcjOGy0Ybz2RY4RYYYClSqnTCNAjk2J/LszoouCiGkHF2ndKfET34HqbGxsbDb7eVZFlJNOUUX0vVWpOmtUCo4RISoaCqiaihIKYfdKcJgLZwwhBBSNWSb3QEqpTsl/vA7SB0yZAiWLl0Kg8FQnuUh1YxdEHE+24IMgxVhGgVdtKq5ULUcOjMPu1B4YCYhpHIzWnmk6S2U7pT4ze96dkEQwHEc7rvvPiQmJiIiIqJQbRcNnCIlQSP4SUGhKgVumHgYbQLilNRPjZCq4t90py7EhFKASvzjd5D68ccfS//esWOHz3UoSCX+cj9RW5FroxH85F8yGQelnEOWyYGYUDXk9LsgpNKjdKektPwOUk+fPl2e5SDVRP4R/HYawU98CNcokGt3IscmIDKEalwIqczsgogL2ZTulJROmbav+prgnxCP/CP4BZEhmkbwEx9UChlE0QWdhQZQEVKZedKdZlt4RFO6U1IKJZr7YceOHdi5cyesVqvXpP6iKMJiseDQoUPYt29fqQvz8ssv48yZM/j9999LvQ0SmJyiCxeNNlw22hCkktEAKVKsUI0CBisPs8NJU9QQUglRulNSFvy++q9atQrTpk0DYwyAu/+p598AoFKp0L1791IXZN26dfj9999Rv379Um+DBCa7ICLDYMXVXAdqBCkQTBM3k1sIUclxLc+BHJtAQSohlQylOyVlxe9fzg8//IB69eph06ZNWL9+PRhj+Ouvv7Bjxw6MGjUKTqcTgwcPLlUhbty4gffeew+xsbGlej8JXGaHE2ezzMjMtSMiREkBKvELx3HQKGW4YXJAEItOxUwICSze6U4VlO6U3JYSZZwaOHAg7r77bmi1WoSEhODAgQOIiYnBpEmTkJKSgm+++aZUhZg2bRpSUlLQqVOnUr2fBCajlceZLDN0Fh4xoSqoaYopUgLhagVMdieMVqGii0II8QOlOyVlze92NI7jUKtWLen/DRo0wOnTp/HII48AAHr06IGvvvqqxAVYsWIFTpw4gV9++QUffPBBid/vXUagRo2g29qGvxQ3nw7v1OdVJowx3Mhz4KrVCZdchnviwqvMVEJyufu4h4aqK7gk1YMdHGzgEB6uqdBpa+h8r57ouJdMZo4NWXYnImoGoWZQ5R13UN2v8yFOhrAwTUD87v0OUhs0aICzZ89K/2/YsCFOnTol/d/pdMJisZTowzMzM/H+++/j/fffR0RERIneSwKTy8VwJceGNJ0ZAFCb5sQjtyE8SAGjlUeuTUBNylBDSMC6kWfHhWwLZBxXqQNUElj8DlIfeughzJ8/H0FBQXjxxReRkpKC6dOnY82aNWjUqBGWLl2Ku+++2+8PZoxh6tSp6NatG3r37l2qwhfeJpCbayuTbd2K5wnjTn1eZeAZwX8lxwaN0j2C31LFphHyPFmbzY4KLkn1oc+xI0PB4e7IkAorA53v1RMdd/8YrDzOZZvBOxmiQlWV/vpY3a/zFosDJpMduXewfik6Oszncr+D1FGjRuHcuXNYtGgRxowZg/79+2PZsmWYMmUKOI6DXC7H/Pnz/S7Q0qVLcebMGWzYsAFOpxMApNkCnE4n5HI51cBVIjSCn5SXELUc2WYeceEaaChVKiEBxZ3u1ELpTkm54Fj+eaT8oNPpEBUVBQDgeR4bN25ETk4OUlJS0KRJE7+3M2zYMOzfv7/I199//30MGDCgJEWDy8Wg15tL9J7Soifsf5kdTqTrLcgy84gMqdoDpKr7E3ZFcLkYskw8msaGIi5cUyFloPO9eqLjXjyzw4lz2WbkWN3pTqtKcpbqfp2/lmtH89gwxN7B6+1t16R6eAJUwD036qOPPlqqAr3zzjuF+rB++eWXOHXqFL744gvcddddpdouubOMVh7peitybAJiQlVQ0Hx4pIzJZBwUcg7ZJgdiQtVVZhAeIZWZXRCRpqN0p1WNxeFEnj1wZlQpUZC6du1a7N69G9nZ2V4Zpzw4jsP333/v17buueeeQstq1qwJlUqFVq1alaRYpILcMDmQYbDALrjcFykKHkg5CdMokGt3ItcuIIIGUBFSofKnO42ha3+lxBiDzsLjosGGS0ablBHSk476nT7xeKh5xbRc5ed3kDpv3jx8/fXXUCqViIyMhExGNWbVFWMMmTfnwnOBITpURf2HSblSK2Qwigx6M09BKiEVyCm6kKa3ULrTSkQQXcjMsUuBqOdvqyD6XF8llyE0QMaV+B2krlmzBp07d5ZG+JeHOXPmlMt2Sdm6bnIgQ2+FQs4hIogCBnJnhGjk0Ft51OGdCFFRqlRC7jRPutOruQ5KdxqgTA6nOxA12HDJaMUlow1Xc+0Qixh9pJRzqFczCPVqBaFBrSDUrxUElZyDNib0zha8CH5f6c1mM3r37l1uASqpHHQWHhkGKzgZUIPmwiN3UIhKjut5DhitAgWphNxhLsZw2ehJd6qkdKcVzMUYss28u6ne4A5GLxltMBSToS9MrUCDCHcgWv9mUBobrinUz/9arr28i+83v6/0Xbp0wb59+zBw4MDyLA8JYLk2Aek6CwTRhehqmomDVBwZx0GjlCHL5EDtMDWUVItDyB0hpTs1UrrTisA7XbiSa8elm8HoRaMNl3NssAuFxwYBAAegdpga9SP+rR1tUCsYNYIUla5rnt9B6ltvvYVnn30WEydOxH333YfIyEifXzYpKalMC0gCg4V3Ik1vgZl3onYYBaikYoSpFTBaBeTYBHpQIuQO8XTx0ihlCFVTK0Z5yrMLN2tH/+0/ei3PDlcRzfUqOYd6+QLR+rWCUK+WpsrUdPv9a7t69SpMJhN+/fVXbNy4sdDrjDFwHOeVKpVUDQWnGqlsT2Kk6vDUnurMPKJCaMAeIeUt2+xAut4KmYxDuIa6eJUVF2O4YXJIgeilm6Psjbaim+traDzN9cFSc31Vn1nH7yB15syZyMvLw6hRo9CwYUMoFPQ0VR0IogsZBiuyzDxiQlVV+mQglUOoWgGDVYDJ4aSbJiHlyGDlkaa3QHS5052S0nE4XbiS8+9UT5cM7uZ6h7OI5noOiAvXSIGopw9pdRwH4nekee7cObz88ssYPXp0eZaHBBDRxXDRYEVmrh2RITRRPwkMQUoZcqwCDFaeglRCyonRyuNCNqU7Lalcm+AORI02XDJYcdFow3WTA0Xl9lQrZFIQ6vlzV82gKp25sST8DlJjY2NpbtRqhDGGKzk2XMmxo1aQkk4YEjA4jkOwWo5sE4/YMA00yqrR94qQQGG08jifbYFVEBFD/LLAUwAAIABJREFU82D75HIxXDc5btaOWqXm+ly7s8j31ApWeo2sr18ryJ0MgfZvkfwOUp977jnMnz8f3bp1Q+PGjcuzTCQAXMtz4KLRhmC1nEZykoATplYgy+RAjk1ALAWphJQZAwWohdgFEZdz7NK8o5duTobPFzH5qIwD6tTQoH7NINTPN+UTtfyUnN9B6unTp8FxHPr164d69eohKioKcrn3zaEkaVFJ4Mo2O5BhsEIp4xBGIzlJAJLLOCjkHLJMDkSHqgvN80cIKTkKUN2uGG1ITTfg3A0TLhlsuGFyoIjWemiUMikY9Yyur1tTQ4kOyojfEcj27dshl8sRGxsLQRBw7dq18iwXqSA5VgHpeit1lCcBL1yjQK7diTy7gFqUKpWQ26K38Ligs8BWTQNUxhhOXjdj06ksHLua53OdiGClu5k+4t/R9VGhKmquL0d+B6mrVq1CrVq1yrMspIKZHe65UK28EzE0FyoJcGqFHAZRgN7CU5BKyG3QWXik3QxQo6tZgOp0MaRmGLHpVBYuGW3S8pgwNZpEh3iNrqc5Yu88v/f4Y489hieffBIvvvhieZaHVBDPXKg5NpoLlVQeoWoF9FYedXgRwdR3mpAS01l4XNCZ4XC6qlWAauGd+POcHlvOZMOYL5WoNjoEj7Wti8QGtWCz8hVYQgKUIEg1Go2Iiooqz7KQCiKILqTrrci28O6RhtS/jxRg4Z3QWwQwxtAgIriiiyMJUctxPc8Bg5VHsCqoootDSKWiMztwQW+Bw+mqNskxss0ObDmdjb/O62G/OU8pxwFJ9WqiT/MYNIoKQShlswsYfgepjzzyCFasWIGePXtSsFqFiC6GDL0VV/PsiApRQUEBarXjcjEYbe5mc72Fh87CQ28VoDfz0Fvdy2z5ckQPTbwLDzSNrsAS/0vGcdAoZMg2OxAbpqa5fAnxU3ULUC/oLNh0KgsHLuVIc5aqFTJ0axyJ3k2jKc1ygPI7SJXJZDh//jy6deuG+vXrIzIystC8qTS6v3JhjOGy0YorOTbUClZCRXOhVkl2QXQHoFYBunyBp/uPe1L8ovJC+/K/w5loERuKujUDo+YyTKOA0SogxyYgim40hNxSttmBtGoQoLoYw5Erudh8KgtnsizS8lpBStzfNBo9GkcihPqZBjS/j87u3bulgVMOhwNXr14tt0KROyMz146LOTaEahQIorkmKyUXY8izOaXAU3cz8Pz33zwsvOj39sLUCkSGKBEZonL/CVYhMkSJqBAVQtUKzN16HtlmHgt3X8T0B7UBUXOplMvAGIPOzCOyCt9wCSkL2WYHLugs4MWqG6A6nC7sStNj86ls3DA5pOX1awWhT7MYdGhQMyCuXeTW/A5St23bVp7lIHfYDZMDFw02qOQyGrEYwHjR5VXr6dUkb+FhsApw+lkNKueACE/gGapCZLA7GI3yBKQhSqgVxT+sPJ/cALO3nMNFow1r/7mOJ+6tUxZf87aFahQw2ASYHSLCNPR7JsSXLJO7BlUQWZVs3s61CfjjrA5bz2bD7Pj34bx1nTD0aVYbzWNDq2RQXpWV+GouiiKOHz+OzMxMqFQqxMXFoUWLFuVRNlJOjFYeGQYLXGCICKKpeyoKYwwmh7NQzachX7N8XjEp9goKVsl9BJ7/BqA1NcrbHhQXHxOKh1vUxi8nbmDDiRtoUzccTaJDb2ubZSFYKUeuzQG91UFBKiE+ZJncfVCdYtWbAzszx4bNp7KxJ90A4eZDu0LGIfnuWniwWQzuCpCuSaTkSnQ13759O9555x3cuHED7GbPY47jEBMTg+nTp6Nnz57lUkhSdkx2J9J0VtgF93QjpPw4RRcM1pu1n1YeOrNQoD8oX2RavYI4zt2PqmDNZ1S+Zvk7lb52QOtYHLuah0tGG77efRGzHm4KTQV3F+E4DsEqOXRmHnHhQVBT/2pCJDdMDqTpLHCyqhOgMsZw6oYZm05m4e98k++HqOTopY3CffHRqBlEaUgrO7+D1IMHD2LcuHGIjIzE+PHj0ahRIzDGkJaWhmXLluGVV17BDz/8gLZt25ZnecltsAki0vQW5NmdiAmvmn2R7hTGGKy8eDPoFKRaUE+NqMHiHsjj73gktULmFXx6BaPBKtQKVgZM6k+FXIYxKQ0wfeMZZJl5LDuUiZEd61d0sRCqVkBncsBo5REbrqno4pD/Z+/N4+uq6/z/57n33H1LcrMnTbeUtnRnLwVaKYgiVEXQAQV18Asq/FDnh+OCo4P+8DvgjDOOOIi4gKgMgzIomws7FBAKrQW6pm2SZk/uvp7998dNQgtNe9PcLcl5Ph4+DDc393yak/M5r/NeXm+TiuAwgeqZ/gJ1IvP9Bp+DC5bUcfbCmmOWLZlMH/IWqT/84Q9paWnht7/9LT6f77DvXXHFFXzkIx/hjjvu4K677ir4Ik2mjqzq7B9JMZKUafA7zDFueaDqBiNJiaGkzGBCYighEcqoDMazDCclsofYMh2LKpd4WDNSrffwpiS33TqtHhpaq1xctqaZ37zWyzMdIda0BljTGijrmkSLgNUqMJyUcn6/0+j3aWJSDAbiWfaH0ugzQKBOZL6/qM7DhSfWs6YlYHp8z0DyFqnbt2/nuuuue5dABfB6vVx66aWmQK1QVN3gQDjNQEKi1mevmIhcJSCpGkOJURGalA77eiQlj/vpHQ2bVTgs6vnOaGi124ZtBnaSvndJHVt7YuwcTPKzl7v57kVL8DvLm17zOURiGZV4RqXKbab6TGYvYwLVMAyC01ig5mO+bzJzKViHgSAIKIpy7DealBTdMOiOpOmLZqlx27DPQLF0LJKSOh4JHUzIo2JUYjAhEcujMckqQK3XQYPPTku1m0a/E6/NMipCbfgc4rSKghYKiyDwf86cyzce2UU8q/Lzlw/yhfXzy/q7cNqsRNK52l9TpJrMVgbiWfaNpAGDmmkqUPePmu+/Yprvz2ryFqmrVq3it7/9LVdccQVu9+FjEZPJJA888AArVqwo+AJNjh/DMOiLZTkYyeBzWcve3FIsdMMgmlHeERGVRr+WSefhE2q3Wmjw2an3Oaj3OmjwOaj32WnwOahxvx19HhuXl0xKR/u4WUOtx85Vp7Xy481dvN4T47l9Yda3B8u6Jo/DykhKosnvxF2iZjITk0phXKAKBjXu6SVQTfN9k3eS99m+/vrrueqqq7jooov4xCc+wbx58wDGG6cGBwe5+eabi7VOk+NgMCHRGUrjtFnw2Kf3ha3qBqGUfEhENCdAh0ZFqZJHl7zXYaXe66DeNypCvfbxrwPO2RkNLQRr51Xzek+MV7qi/HpLD0sbvNT7yhfl8DpEBuMSkYyM225az5jMHvrjWfZPQ4EqqTqb94d5fOeQab5vchh5K5dTTjmFH/7wh3z729/mtttuG7+hG4ZBXV0d3//+9znjjDOKtlCTyRFKyXSG0wgCZa8TzBdJ1RlOSm8L0TERmsjVh+bjWV/tto1GQt8dFZ3uQr1SEQSBT502hz1DSaIZlTtf7OKm8xeVrYnBIgjYRQvDCZkGnxPRrME2mQWMCVRBgOppIlCPZr7/vqX1LGv0mcGDWc6Ed+377ruPtWvXjkdMATZu3MiGDRt466236OnpAaClpYVly5YhiqYAqBTiWYUDo3OZyxnROhIpST1MfB7asBTJHLum2SpA0GMfFZ5jEdGcCK33OrCb/phlwesQ+czaufzrU/vYO5zi0R2DXLy8sWzr8TlFoumcDdh072o2MTkahmHQH8/ZTFksAtXToBbbNN83yZcJleVtt93GTTfdNC5SN27cyNe//nU2btzIypUrWblyZanWaDIJ0rLG/pE0iaxKvb/0AtUwDKIZ9fC60MTbNk75zJG3W4V3RUHHvg56THeCSmVls5/zFtfyxO4RHtw+wIpmP/Nq3Mf+wSJgt1rQjZyFWNBtM6MxU0BSdfpiGZw2K3VehxmZriAOFahWi1DRzYKm+b7J8TChSLXb7TzxxBOsXr0al8tFb28vfX199PX1HfUDm5srY5b3bERSdfaHUoTSMg1F9okcS8vnROjhFk6ydmz/UI/denha/pCoaJXLrA+drnxsTQtv9Sfoj0vcubmLmy9cXDZHCZ9DJJJWSMkaXrPZ4riIZRS6wmmGUjKiIBBOybRWuQiYYqLsGIZBXzzLgZF0RQtUVTd4pSvC4zuG6DLN900miWAYR3aC/N73vsfPfvazSYuFnTt3FmRhx4OuG4RCyZIcKxDIpSNiscwx3lkaVE2nYyRFbzRLnc9eNF9O3TD4yeYuXuyMHPO91S7bYVHQ+kOalaaraDC7+4/N/lCa7/xxN5oBFyyp4+OntJZlHWNRpvZaD3OnGNGttOu92OiGwWBCojuSJi1p1Poc6LpBOKXgtFto9jtp8jtnfHlNpZ73wwSqVajICGRa1nh67wh/2T1MeJqZ78/2fb4/luXERl9JJ/fV1b3bgx+OEkn98pe/zKmnnsru3buRZZkf/ehHnH/++SxevLhoizQ5PnTDoCuSoS8mEfQWT6ACPL5jaFygWoScBdF4JPSQbvk6r8Ocnz5LWRB088EVTTy4vZ8/7RpmdUuAZU1H3oCKiSAIuG1WRpLyrBBUhUJSdQ5G0vTGstisFhr8jlywwiLQ4LeTkFT2jaSIZhRaqlxmOUWJMQyD3liWA6E0YgUKVNN836SQHDWctWHDBjZs2ADAz3/+cz70oQ+xcePGUqzLJE8Mw6AnkuFgJEPAJRZVGO4eSvLAtly5x/qFQT55+hyzPs3kiFy8vIG/9cXYN5Lmrpe6uOWiJWVxV/A6RUYSEpGMQkOFNRFWImPp/eGUTLXLhusdPrOCIOB32nDbrITSComsSqPfQUuVC9cM9WGuJA4VqDarUFFlF2Pm+692R8edWEzzfZOpkvddw+/3s2vXLlOkVhgDCYmuSAa33VpU4/J4VuG/nu9EN2BOlZMrT201BarJhFgtAteeOZdvPLqbcFrh3ld6+OxZ80q+DtEiYLEIDCcl6rz2otZpT2cOS+/LGvW+ozdIiVYLDT4HKVmlK5IhllFpqXJS53WYjY1FYkyg7g+lsVeIQNUNg209cR7fOWia75sUhbz/eqLRKHV1dcVci8kkGUnmzPotlpzlTrHQDYMfb+4iklFwihauP2e+mTo1OSaNfidXnNzC3a8c5MXOCKtbA5wxr7rk6xizo4pn1YpLjVYC70rv+xx5p+89dhGXaCWcUdg9lCSaUWitck3bmvNK5VCB6hCFsntfj5nv/3HnEAOHmO/PqXJy4YkNpvm+ScHIeye56KKLeOCBBzj33HOpra0t5ppM8iCaUdgfSqPoetHTKA+/Ocib/QkA/v6MNppKWExtMr15z6IgW3ti/K0vzj2vHOSEek/JJ+G4bFYiaYVQSjZF6juIZhS6j5LezweLRaDWY0dSNfpiWWJZhZaAi0afwxQqBcAwDA5GMhyIpHGKlrIKVNN836TU5C1SLRYLHR0drF+/nra2NoLBIBbL4RuQIAjcc889BV+kyeGkZJUDoRQpWS16nd2OgQQPbu8HYOMJtWWJhJlMXwRB4Oq1bXz9kZ0kJY2fvtTNjecuLHna3euwEkrJNAecZu0kk0/v54NDtNLotxDLquwZShJJ5+yqpsv0o0qkUgRqbyzLH3cO8eJ+03zfpLTkLVI3b95MdXVOoEiSdEy/VJPikFU09o+kiKSVSaXljodoRuGOFzoxDJhX4+KKk1uKdiyTmUuVy8anT2/jh88d4M3+BE/uGeH8xaUtHfLaRQYTMpG0giswu0XqVNL7x0IQct3mHruVkZRMPKvRHHDQ5HfiNB8OJoU+2hR7IJzGaSu9QDXN900qgbxF6lNPPVXMdZjkgaLpHAilGUrK1HvtRfWY03WDO17oJJZVcdusXH/2/KJaW5nMbE5tq+LsBTU8vz/Mf7/ey7JGH82B0pWNWCwCNlFgKCEVJGo4XSlEej8fbFYLjX4nCUllfyg9Xqsa9JjNa/mgj0ZQO8NpXDZrUXsOjoSi6fx4cxevdkfHX6v32nnf0nrTfN+kpBzXX/7Q0BD9/f0sWLAAh8OBKIrvSv2bFBZNN+gKp+mPZ6n12Ite6/W/bwywczA3GOEza9uoN+17TKbIJ05pZedgkpGUzI83d/LN9y0uqVj0O0SiWYVYRiHomV0paN0wGIhLHIwWLr2fDz6HiNtmJZyW2TmYpNHnoKXKWRY7sulCuQWqpOr857P7eWO0D2FRnYf3L63npNbKNd83mblMSum89tprXHLJJaxfv56/+7u/48033+SVV15hw4YNPPbYY8Va46zHMAwORtP0RLNUuWxF76x/oy/OH94YAHITg05pqyrq8UxmBy67lWvObEMAOsMZfj/6N1Yq7KIFXTMYScklPW65kVSd/SMp9g4n0fTcOMpSPhxYLQJ1Xgdeu5WDkQw7+hP0x7Oo+hGHHc5qdMOgO5LOCVR76QVqRtH4/tP7xgXqx9Y0808XnMApbVWmQDUpC3mrne3bt/PpT3+aVCrFJz/5yfHXA4EAoihy44038uyzzxZlkbOd/rhEdySL22EtWnpujHBa5sebuzCAhbVuPramuajHM5ldLGnw8f4T6wH4w5sDdAynjvEThcXnFAmnZZKSWtLjlotoRmHXYIKuSAafQ6S6jNOhXHYrjQEHsq6zezDJ7sEEsYxy7B+cJYwJ1K5wJidQS2zjlZJVvvfkvvEM2pWntvKBZQ0lXYOJyTvJW6T+4Ac/oLW1ld///vdcc801GEbuKXjFihX84Q9/YOHChdx5551FW+hsZTgp0RlOY7MIRd+0VN3gv57vJCGpeOxWrjt7vmkhY1JwPrKqiTlVTgwD7nyxi6yiHfuHCoTbbiUta0TSM1sc6YZBXyzL7qEE4bRMvc9R9AfcfLAIAjVuO9VuG0MJmR2DCbrCaeTR8ZmzlfEIaig3mKXUAjWRVbn1iQ46RlIIwNVntJW8udHE5EjkrUC2bt3KJZdcgtPpfNeTuNfr5aMf/Sh79+4t+AJnM9G0woFQGk03qHIXv4vyd9v62DMa2br2zLnUzrK6PZPSYLNauHbdPESLwGBC4r7Xe0t2bEEQcNmsDCWlGSuMJFVn33D50vv5YBctNPjtWATYN5Jm12CCUEoeD37MJjTdoDucE6geh7XkgxCiGYX/+8ReOsMZLAJcu24u69uDJV2DiclETCpMZrdPLFokSULXZ+amXw6Sksr+UIq0rBL0FF+gbu2J8eiOIQA+sKye1a2Boh/TZPbSVu3i0tVNADy9N8S2nljJju1zWElkVaIzMNU8lt7vjpY/vX8sBCE3OanOayOcUdg5kGB/KF3SyHq50fSxGtQM3jII1HBK5rt/3ktPNIvVInDd2fM5c35NSddgYnI08hapq1at4pFHHjni99LpNA888AArVqwo2MJmM2NeqNGMQp23uF6oACNJmZ+82AXACXUeLl1l1qGaFJ/3LalnSb0XgJ+93E08WxrRKFotIORKafQZErmr1PR+PoijXq1Om4XOcJq3BhIMJmbOuZkITTfoGq1B9TqsJZ9xP5yUuOUvexlISNgsAl9cP59TzSZZkwojb5F6ww03sGPHDj7xiU/w0EMPIQgC27dv55e//CUf/OAH6enp4bOf/Wwx1zorGPNCHU7J1PkcRe+oVDWdH71wgJSs4XOIfP7seVgrLDVoMjOxWASuOXMuTltuStEv/nqwZOlev0MkmlGJZ6d/A1VW0So+vZ8PHodIo89BWtHYNZhgz1Byxja4jQvUUBqvs/QCtT+e5ZY/72U4KWO3WviH9yxkVYuZPTOpPPIWqWvWrOHOO+9kYGCAW2+9FcMw+Pd//3e++93vks1m+f73v88ZZ5xRzLXOeFTdoDOUpi+epdZrL8mN5v6tfewbSSMAn103t+Rz1U1mN7VeO1ed2grAawdjvLA/XJLjuuxWJFUjnJ7edlTRjMLuoWQuve+s7PR+PlgsArUeO36nSG8sy1sDcXqiGVRt5pSSHSpQfS6x5J6xPdEM3/3zXsJpBafNwj9uXMiyJl9J12Biki+TujrWrVvHX/7yF3bs2EF3dze6rtPS0sLy5csRRdOceSrkRuClORjNUOO2YS9BV/2W7ih/2jUMwKYVjaxo9hf9mCYm72Td/Bq29sR5tTvKvVt6WNLgpc5b/OERHoeVkaRM8zQc2Tlmzt8dSZNRSmfOXyqcNitNfguxjMqeoWRuYlXAVZIG0mKi6Qad4TTd4TR+lw13iUsyOkNpbnuqg6Sk4bFb+fK5C1lQ6ynpGkxMJsMxlaWiKHR0dKCqKu3t7bhcLpYtW8ayZctKsb5ZQ18sm/MydIoluWEOJSR++lI3AEsbvHx4RWPRj2liciQEQeBTp81hz1CSWFblJy928bXzFhW91MVrFxlMyEQyCk3TSKRmFY2DkQx98Sy20XrO6Rw9nQhBEKhy23BrVoaTEvGsSrPfQVPAhaPIA02KgTo6NbArnCZQBoG6dzjFvz21j7SSK+36ynnttFW7SroGE5PJctQr/e677+bMM8/kkksu4aMf/ShnnHEGt956K6o6M+uEysVgQqIrnMEhWkrS3SlrOrc/f4C0ohFwinzurHnmNBGTsuJzinxmbRsAu4dSPL5zqOjHtFgEbFaBoYSENk2mH8209H4+2K0WGv1ORKvAvlCaHQNxhpPStLKrGivlKpdA3TmQ4LYnO0grGtUuGze9d5EpUE2mBROK1Iceeoh/+Zd/we/38/GPf5wrr7ySefPmcffdd3PbbbeVco0zmnBapjOcQscg4CpNKuu+13rpDGcQBPjcWfOoKtFxTUyOxqqWAOeeUAvAb//WT3ckXfRj+pwisaxKrETOAsfLWPf+rsFDuvenUfS3EPgcIg0+BwlJZddgko7hFGm58u2qcgI1xcFohqoyCNTtfXH+9el9SKpO0GPj6+9dRHPAWdI1mJgcLxOG7X7zm9+wevVq7rnnHhyOXH2YYRh86Utf4v777+fGG288qm+qybFJZFUOjKTJKDr13tL8Ll/ujPDknhEALlnZxImNZsG8SeVw+UnNvNWfsyC6c3MX33r/4qLWZztEC5pmMJyUK7Zp8ND0vn0Gp/fzwWoRqPM6yMga3dFMrla12kW911GRriTjAjWSJeASS24L9trBKD96vhNVN6j32vnq+YvMIS0m04oJd/99+/Zx8cUXjwtUGK0d+9SnkGWZ/fv3T/nghmFw9913c8EFF7By5Uo2bdrEww8/POXPnQ5kFI39oRTxrEqd116Sm05/PMvPX87VoS5v8nHxcnMus0ll4RCtfHbdXCwCHIxm+d22/qIf0+u0EknLFWl3FE0fnt6vmgXp/Xxw2a00+h3Ims7uwSR7hpIl89nNl8MEqrv0AvXlzgi3P3cAVTdoDji56b0nmALVZNoxoUjNZDL4fO+OsrW2tmIYBvF4fMoHv/POO7ntttv40Ic+xJ133sm6deu48cYbeeyxx6b82ZWMrOrsH0kxkpSp89mxlOCmI6s6tz93gKyqU+22jQoB82ZnUnksrPWwaXmuke+PO4fYOZAo6vE8dispWauoCVTj6f2h2ZvePxYWQaDGY6fKbaM/nmXHQILucBqlAuyqVE3nwEiK7jGBWuJz9/y+EHds7kQzctPdvn5+O9XT3BnBZHYyoUjVdf2IT+xWa+5i07Sp1QIpisLPf/5zLr/8cj73uc+xdu1avvKVr3Daaafxq1/9akqfXcmousGBcJqBhESdz16yFNW9W3o4GM1iEeDzZ83D7zQ3LJPKZdOKRhYE3RjAT17qKmrtoSAIOG0WBhNSRQicQ835DWP6mvOXCodoodHvQBCgYyTNzoEEoZRctsYqdXQgy8FolqoyCNSn9oxw10vdGAYsCLr52nnt5n5vMm0pm4+H1Wrl3nvv5ZprrjnsdZvNhiRJZVpVcdGN3JzmvmiWoMeGrQReqACb94d5tiMEwGWrm1k8OorSxKRSES0C1545F7tVIJRSuHdLT1GP53eIJLJq2aOpZnr/+BAEAb/TRp3XRiSjsHMgwf5QmqxS2sYqVdPZPypQq8sgUP+4c4i7XzkIwOJ6D1/Z2F7yaVYmJoXkqH+90WiUvr6+w16LxWIAhMPhd30PoLk5v7nvFouFxYsXA7na1FAoxIMPPsiLL77It7/97bw+YzphjKbvDkYy+FxWHGJpNq/eaIZf/DW3aa1u8fP+E+tLclwTk6nSFHDydye18MtXe9i8P8yaFj+nza0uyrFEqwWE3DzzWk9pasQPRTcM+uO5/WEmmvOXCtFqod7nICWpdIbTxDIKLVUu6rzFL6tSNZ19oTQ9owNZSj0g4g9vDPDbv+VquJc1+vjihvklu8+YmBQLwZggJ7JkyZIJN2rDMI74PUEQ2LFjx6QX8ac//YkbbrgBgA0bNvCDH/wAp3PyFhmGYaCU6MlZHL34VTW/4/XHMuwaSGATLSWzfMoqGl958E0ORjLUeu3826Ur8TnNp+qpUKhyF5P8MAyD7zy2i20HY3gdIv/x0ZXUFKn5Iy2rZGSdVa0Bqt7R6T/Z630yZBWNzlCankgau2iZFd6npUDTDUIpGV03aAo4aatx45tk2jvf8y6rOvuGk3SH09R47SWNoBqGwW9eOcjvtuaCRie3VfHl956AfRoOPKgUZvs+3xfNsrzZT3NV6bx07ROMB55QsXz4wx8u2mLeyYknnsivfvUrdu/ezQ9+8AOuueYa7rnnnhmzUY8kJfYNpxAESiZQDcPgzucPcDCSQbQI3Hj+IlOgmkw7BEHg+g0L+eL/bCcpqfzomX1848KJH6CngtsuEk5lCKXkd4nUYhFOyXSGUgwlJIIee8k7wGcyVotAvc9BZtTCK5ZRmVPjotHvLGip1aECNei1lzSCahgGv3ixi0feGABg7YIavrixvWSlZCYmxWbCSGq5eOihh/jKV77Cfffdx0knnTSpn9V1g1AoWaSVHU4gkHvCiMUyR31fPKthhYE4AAAgAElEQVSwezBJejSFVyqe7Qjxs1G7qStObuF9S800fyHwjs6UTyZnZt10pfJKV4Tbn+8E4JOntbLxhLqiHCeWUbAIAiub/YeJjXyv93w5NL2fVTSCXjO9X0wMwyCWUcdLKVoDLqry6HY/1nlXtJxTS08s12dQyvS6bhjc88pBnt6b6zc4c341/2ft3Ir0i51uzPZ9vj+W5cRGH43+0g19qKs7smd72R63otEoDz30EIODg4e9fuKJJwIwNFT8sYjFJi1r7BtJkZRUaktk1g/QHcnwy1dzdagnzwlwwZLi3NBNTErFaXOrWTc/V49632u99MezRTmO1yGSkoprR5VVNDqGU+wdSmEYmPWnJUAQBKrcNoJeO8MJiR2DCTrDKST1+N0cZFVn37hAtZdUoGq6wV0vdY8L1A3tQa450xSoJjOPsolUXdf56le/yv3333/Y65s3bwbghBNOKMeyCoak6uwPpQinFep8jpJ5kmYUjdufO4CiGdR57XxmbduMKZswmd1ceeocgh4bsmZw5+YuVL3wSSCrRcBqhaGEhFaEzx/r3j8YzeB3md37pcZutdAYcCJaBPaN2lWNJKVJ21XJo/t777hALd2tVNUN7nihk837wwC8d3Ednz59jul7bTIjKVuRYk1NDVdccQU/+clPcDqdrFixgtdee40777yTyy67jAULFpRraVMm55OXYjAhUe8tnReqYRj84uVuBhISokXg+rPn45mgGNnEZLrhtlu5Zu1c/uWJDvaH0jz85gAfXtlU8OP4nTZiWZVYVinYqNR3pvfN6Gl58TlzE6AiaZmdgyqNPgctVS7cedQEl1OgyprOj547wNbe3DCdi5Y1cNnqJvNBx2TGUlYF87WvfY2mpiZ++9vf8sMf/pDGxkZuuOEGrr766nIua0poukFXJENfLNcIIZawgP2pvSO83BUFcnWo84Pukh3bxKQULG308b6l9Ty+c4jfvzHAymY/C2s9BT2GQ7QQ0QxCSbkgIjWraHRHMvTFsjjEnEWSKSrKj2gRqPM6SMsa3dEMsaxCa5WLOq9jwsDCWIq/L56l1mMvaQe9pOr84Nn9vNmfm8B2ycomPriiwfxbMpnRVFzj1FQod+OUYRh0RzIcCKXxOcW8nsoLRWcozbf/tAdVNzh9bhWfP2te0TYv3TAYissIFqh22WaV1clsL6ivBGRN558f301PNEuDz8H/94HFBa8HTEgqhmGwvMmPxy4ed+NUNK3QFUkzkpKpdtvM0aYVim4YRNMKimbQ4HPQUuXE77Qddt6l0XHW5RCoGUXj+0/vZ/dQ7v52+UnNvP/EhpIdf7Yx2/d5s3FqhjKQkOiOZHDbrSUVqClZ5fbnD6DqBo0+B39/RnHrUMMpBb9TpNZjJ5pRGEpIyBUwTtJkdmC3WvjsulyTyGBC4r9ff/dQkanisVtJSRqR9PE1UGm6QW8sw66hBJG0TL3PYQrUCsYiCNR47FS5bfTHs+wYSNAdTiOPNlaVU6CmZJXbnuwYF6hXndpqClSTWcOE6f6rrrpq0h8mCAL33HPPlBY0XRlJSnSG0lgtQkn9SA3D4KcvdTOUlLFZBa4/Z35Rb4ZjM9TnVLsIeuyE0zL9sSzhlIJlNLJayhIHk9lJW7WbS1c1cf/WPp7cM8LqFj+rWgIF+3yLIOAQLQwlJBonaR33zvR+QwmjESZTwyFaaPQ7iGdVOkbSKFYLrdXutwWq1469hPtbIpsTqF2RDAJw9do2zlkYLNnxTUzKzYRqqqenuLOyZxLRjML+UBpF16nzls4LFeDPu4d57WBuVO1Vp86hrbp4EyI03SCaUZhbkxszKAi5mq5qt51QKidWR5Iy4uhULbMxxKSYvH9pPdt6Y+weSvHTl7r57sVL8RVwTrnPKRJJK0QyCvnKAjO9P/0RBIGAy4bHrhNOycSzCuEyCNRoWuHWJzvojWWxCHDtmXNZO7+mZMc3MakEJtzRn3rqqVKuY9qSlFT2j6RIy2pJzfoB9o2k+O/XegFYN7+acxYWdwMLpWSCbjutAddh5QSiRaDB56DGbSOUkumLZRlJyNjF3GZveveZFAOLReCaM+dy06O7iGVV7v7rQa4/u3C12GNTe0aSMgsnGAU9hqYbDCSydEcySIpGg2/i5huT6YFotdDodZCWVURvaZtgQymZf3mig8GEhNUicN1Z8zilrapkxzcxqRTMvOwUyCoaB0IpohmFOm9pO3aTUq4OVTOgJeDkU6fPKerxE1kV0WJhTrVrwrF/NquFRr+T5U1+Fjd4cdqsDCUkImkFvQiekyYmdV4HV57SCsCr3VFePBAp6Od7HSKRjEI8q074nqySG9qxdygFQIPfaQrUGYTbLpZUoA4lJG75814GExI2q8CXNiwwBarJrMWsSZ0CB0ZSDCUl6r0OLCW8KemGwU9e7CKUUrBbLVx/9ryiTjtRNJ2kpLGgNleHeizsooXmgJOgx85wUmIgnmUgIeG2W/E7RdN02qSgnLWghtd7Yrx2MMYvXz3I4npvwSa8uWwWohmFUFIi4Hr3GM1oWqEznCaUlqlx20o6t91k5tEXy3Lrkx1E0goO0cKXNizgxMYjdz2bmMwGzJrUKZBRNJyiteSNQo/vGGLbqJnzp0+fQ0tV8epQDcMglFSo99lpCUzuOA7RQmuVi1qPnaGExEBCYiAu4XVY8TlE09/PpCAIgsCnT59Dx3CKWFblJy928dXz2wvyMCQIAm67lcGEdNh1Zqb3TQrNwUiGW5/sIJ5Vcdks3HjuQhbVecu9LJNZhKzqJCS1ogJJZk3qNGP3UJIHtuUsd9YvDLJuQXHrUGMZFbfDwpwq13iN3mRx2qy01bip9ToYSmYZTEj0xyV8DhGvw2qKVZMp43fauPqMNr7/zH52DSX5086hgtn0+Bwi8axKOC3jJpfe74pk6I9lcdjM7n2TqXMglOa2JztIyRoeu5V/3NhuDmMxKQm6YZCSNFKShtUq4HeI1PnsBZu2N1UK6pUUDoepqTG7D4tFPKvwXy90ohswp8rJlae2FvV4kqojqTqL6j1HTHVOFrfdyrwaD3VeB4MJiaGERH9Mwu8S8dhNsWoyNVa3BnjPoiBP7w3xwLZ+ljf5mVMAtwurRUDEYDAuERAFusMZM71vUjD2Dif516f2kVF0/E6Rf9zYXlSXlnzRdINwSgYBPHYRl81i7tEzCGk0aqqoOh6HldYqJ0GvHb+zspx5JiVS77vvPp5//nnS6TS6/rZ5u6ZppFIpOjo6ePPNNwu+SJPc086dm7uIpBWcooXrz5lfVENp3TAIpWRa/E4afYWNFHnsIguCIvVeBwPxLMNJmYH4mFgt66Rek2nO5Se1sGMgyWBC4sebO/nn9y8+7gzAoQRcNiJpmYGsYqb3TQrGjoEE//7MfiRVp9pl4yvntdMcKH9kXlZ1RlIytR47okUgllWJZnJ1sl6HiGMWTRmcSbwrauoUqQ86qHLZSjqAaDLkrQjuuusu/u3f/g273Y7X6yUSidDY2Eg0GiWTyeB0OrnyyiuLudZZzSNvDvLG6Mzmvz+jjaYipxgjaYWAU6S12lW0m7HXIdJe56XepzAQlxhOysQzWapcNlwVesGYVDZOm5Vrz5zLd/68h4PRLA/+rZ+PndRSkM9NSioCmOl9k4KwvS/OD57dj6IZ1HrsfPW89pLbGB6JlKwSz2g0+53MD7pxiBaSkkYsqzCSlElmVUKajttuxWsvfU+GyeSRVJ1EVkXWdLwOK3OqndR4Ki9qeiTyFqkPPvggS5cu5d577yUSiXD++efzy1/+kubmZu6//36+853vsGrVqmKuddayYyDB77b3A3DuCbWcMa+6qMfLyBqaYdBa5cJbQHP0ifA7bfgcIvW+XGR1JCkTyyhUmelUk+Ogvc7DpuWN/P6NAR7bMcSqlgBLGqbegFLrdZAswPpMTF47GOX25zvRdIMGn4Ovnteel3NKsYllFCRVZ26Ni7nVrnEB6nOK+JwiTX4niaxKNCMTSimE0wq6YeCx50q2SulyY3J0dN0gKaukJA2b1YLfKY4O35leQ0byfgTq7e3lgx/8IF6vlzlz5hAIBNiyZQtWq5UrrriCCy+8cFbZT5WKaEbhjhc6MQyYV+PiipOnHhU6GppuEMkoNPucJX2qFwSBKpeNxfVeljX5aPQ7SUoag/EskqqVbB0mM4MPrmhkXo0LA/jJi11kZPNvyKQyeLkzwg+fO4CmG7QEnNx0/qKyC1TDMBhOSmg6LKz1MD/oPmKE1GoRqHLbmBf0sKLZz7JGH80BFwbGeJ9BWtYwDNMXu1xIqsZIUmYwIQPQVu1ieZOP5U1+mgPOaSVQYRIiVRRFPB7P+H/PnTuX3bt3j//36aefTmdnZ0EXN9vRdYM7XugkllVx26xcf/b8oo/lC6VyDSFzql1lsaEQBIFqt53FDV5ObPRR53UQy6oMJiRkVT/2B5iYkJuC9tl187BZBUZSMr96zbTUOx403WBrT4xH3xpkz1DSHMoxRZ7bF+KO0ebXtmoXXz9/EVXuqTelTgVNzzUFukQrJ9R7aK3Kb++3ixZqvQ4W13tZ2RzgxEYftR47sqrTH5cIpWQzwFAidN0gnlXoj2VJZDUCTpGljbnz0l7npdptn7Y19HnnchcuXMjWrVu57LLLAJg/f/5hTVKxWAxZlgu/wlnM/74xwM7BXILxM2vbih7ZTEpjU6XcZU+zWwSBoMdO1WjDSn88SzitIAhQ5bIVpBnGZGbTHHDysTUt/GpLD8/vC7OmJWBO7smTkaTMs/tCPLcvRCStjL/uc4isavGzpjXA8ibftIvKlJMndg/zy1dzD0sLa93c+J6FeEpQTnU0xhqkgh4782vcx+3i4rJZcdmsNPgcpGSNaEZhJJWrXw1rCi6bFa/DrF8tNJKqEc+qqBp4HVbm1ripcdvwO2fOOPK8r5BLLrmEm2++GVmW+fa3v825557LF77wBW6//XYWLFjAPffcw5IlS4q51lnFG31x/vDGAAAXLKkr+s1V1XKF1QuCboJlfrI/FKtFoNbroMptJ5ySGYhnCaeUXNrJVdpxhSbTj/MW17KtN8ab/Ql+8deDtNd5qCqAndpMRB2Nmj6zd4Q3+xMcGjOt89oZTsokJJUX9od5YX8Y0SKwtMHLmtYAq1sD1FZATWWl8viOQe57Pedvvbjeyz+8Z0HZBX5a1ohlFJr9TuYF3QVZjyAIeB0iXsch9atZmVBytH5VN/A4zPrVqXBorandaqHKaaPO56DaNTN7OPIWqZdffjkDAwP8+te/RhRF3vve97JhwwZuv/12ALxeLzfeeGPRFjqbCKdlfry5CwNYEHTzsTXNRT/mmN1Ic8BVkV54okWg3uegxm1jJCWPuwHYRQsBV+V3KJqUB4sg8Jm1bdz0yC4SksrPXu7mHzYsqMi/8XIxmJB4pmOE5/eFiWfV8dcDTpFz2oOsXxik3udgOCmxrTfO1p4YOweTqLrBG/0J3uhP8MtXe2irdrF6NMo6P+iuqKk15cIwDH7/xiAPjja+Lm/y8YX1C8pu4fR2g5SbturjH9RyNMbqV6vcNloCOrGsSiQlE87IDCYkrBYBj8OK22Z6ZOdDVtFISCqaBp7RqGnQbcfnFGdM1PRICEaeFc7RaJSqqipUVUUU39a2W7ZsIRqNsmbNGoLBYNEWmg+6bhAKlab/NhBw8Xp3hIFQipoCRhA03eD//mUve4ZTeOxWvnPhkoLNIZ+IWEbBAJbW+8peH5UvipZLU/XHssQyKnabQKAEKQ6vN1dykUxKRT2OSWF5uTPCf73QCeRGCb9nUe2kfn6mnXdF09nSHeWZjtB4SRGAIMDKJj8bFgVZ1RKY8OEvI2u80Z8TrH/ri5OUDq89DDhFVrcGWNMSYFmTr+yi7HiZynk3DIPfbuvn4bcGAVjT4ue6c4rfV3CsNYVSChZBYG6Ni+aAs+QPE1klVw4QSsnEsyppRcMuWvA5rDjEyogEVsr1rukGKVklKWk4rBYCrlyHftUMjJrW1fmO+HreInXDhg1cdtllXHfddQVdWCGZCSL1/q29PPrWEABf2rCANa2Bgn32kZBVnVBK5oR6L61V5Z9yMllkVWc4JTEQk4hlc7VPfqdYtFRSpWxeJpPnjhc6eakzgt1q4ZaLltAwiRrvmXLee2NZntk7wuYD4cOEZY3bxvr2IOcsDE6601zXDfaOpNjaE2NrT4z++OG/I5tVYFmjL1cW0BKgepo8CMPxn3fDMPj1ll7+vHsYgNPaqvjsurllLU/S9FwHv8cuMq/GXXZPVsMwxutXQymZRFZFUnP+qx6Htax9B+W+3seipqpm4HWI1Hrt1Ljs+F3ijM1QTCRS8073RyIR6urqCrYgk3ezrSc2LlA/cGJ90QWqMTpVqtHvoHGaGpTbRQstARdBt308sjqQkPDYrficM/eCNpk8V53ayu6hJOG0wo83d/KN954wo9NkY0iqzitdEZ7pCLF3ODX+ukWANa0BNrQHWdHkP+4HO4tFYHG9l8X1Xv7upBYG4lm29sTZ1htj91ASRTPY1htnW28cOMj8GjdrWnNlAW3VlVleNBV0w+Duvx7kmY4QAOvmV/OZtXPL+rcmazojidEGqeDxN0gVkqPVr0ZG61fdDitee/GCDpWEphskJZWUnIuaVrtsMzZqOhnyjqTedNNN7NmzhzvuuIPa2smlykrFdI6kjqRk/unRXaRkjUV1Hr52/qKi11mGUzI2q4UTG30lMe0vBVlFYzAhMZiQSEgqXocVn0Ms2I2w3E/YJlPjrf4Etz7ZAcBHVjXxwRWNef3cdDzvXeE0z3SEeOlAhLTydtS03mtnfXuQsxcEi17ek5JU/tYXZ1tPjO19icPWAbkI7urWACe15gYulDMVfiQme9413eCnL3Wx+UAEgPcsCvLJ0+aU9WE5MxqtbPQ7mB/0lL1h61go2tv1q5GMQlJSsVgEvCWsXy3l9Z5RNJLvjJq67bmM4Ax7gDsaU46kWiwWOjo6WL9+PW1tbQSDQSyWwzcUQRBMQ//jQNV0fvT8AVKyhs8hct1Z84ouUDOKhqobLKwtzVSpUuG05QrK67wOhhJZBpMS/XEJn0PE6zAL9Gc7y5p8XLCkjj/tGuah7f2saPazIOgu97IKRkbReLkzwrMdIfaH0uOvWy0CJ88J8J72WpY2ekt28/M4RM6cX8OZ82tQdYM9Q8nxsoChpEw4rfDUnhGe2jOCQ7SwvGmsLMCP31n+aN9kUDWdOzZ38Wp3FID3Lqnj4ye3lHXPiWcVMrJOW7WLuTXuaWHdZ7NaqPXYqfXYx+tXw2mZWEZlICNhEy147dZpHV0cj5pKGk6blRp37t8726OmRyLvSOq5556b1wc+9dRTU1rQVJiukdRfb+nhT7uGEYD/99yFrGz2F2aRE6DrBgMJidYqF4vqPDP6aS0p5QYBDCUlMrKGzylOSZRPx4iayeHIqs63Ht9NbyxLk9/Bty9ccszGnko+74ZhcCCU5umOEH/tjJA9ZOhFk9/BhvYg6xbUVJToMwyDvliWraNuAR3DqcMsrwRyk4/GygJaAs6yiL18z7us6dz+3IHRkga4eHkDl65qKptANQyDUFrBQvkapArJWP1qLKswkny7ftVlz/mvFlp8F+t6zygaiayKrueipnVeO1WzMGp6JKbcODUdmI4idUt3lP987gAAm5Y3cOnq4ttNDSclvHaRpY2zx4w7kVUZTGQZSspkFQ2/S8Rjn7xYrWSxYpI/neE0N/9xD5pucP7iOq48tfWo76/E856SVV46kKs17Y5kxl+3WQVOa6tiw6JaTqjzTIvsQTyr8LfRutU3+uKHCW3I+bSuaQmwpjXA4npPyRqQ8jnvkqrxH88c4K2BBACXrmpiU55lJMWg0hqkCo2mGyQklWhGJpTKlQPoOrgdFjz2wtgxFfJ6V0ejpunRqGnAJVLrsVPttk9b14tiUFCROjQ0RH9/PwsWLMDhcCCK4rtS/+VguonUoYTENx/bTVrRWNrg5Ssb24teIJ6SVLKKzuIGL3XembV5HQvDMIhnVQYSEiNJGVnVCbhEXPb8hXolihWT4+PhNwd4YFvOv/LL5y5kxVEyGJVy3g3DYO9wiqc7QrzaFUHW3t6+51Q5Wd9ey7r51WWfZDQVFE1n52CSbT0xXu+JET5k4hWAy2ZhRbOfk1oDrGz2F7Vc6VjnPSNrfP+ZfeweyjWkXX5SC+8/sb5o6zkWhzZIzQu6Z/zgirH61Wg6VzqSklSEAtSvFuJ6z8i5Dn1dN/A53xamZkPvkSmISH3ttde45ZZb2LlzJwA///nP0TSNr3/963z1q1/lwgsvLMxqj5PpJFIVTec7f9pDZzhDwCnynQuXFL2JQdUNhhMS84Ju5te4p0WEpRgYhpGrb0pkGUnKKLqedy1QpYgVk6mj6wa3/GUve4dTVLts3HLRkgkFT7nPe0JS2bw/zDMdIfpi2fHXHaKFM+ZWs2FRkAXBmXdNG4bBwWiGrT25soBD62wh51CwqM7LSa1+VrcGaCqwS8nRzntKUvneU/vG1/TJ01rZeEL5HHAyskYko9DoyzVIuSfx8D0TyCoasaxKOCUTzSqk5dxEJq9j8vWrx3u9vzNqWuUScxMTXTYzanoMptw4tX37dj796U/T1NTEJz/5yfEGqUAggCiK3HjjjXg8HtavX1+YFc9w7nutl85wBkGAz501ryQm+qGkRNBjp6VCp0qVCkHITUIJuETqfQqDcYmRUWPpgLmZzBosFoFrz5zLNx7dRSSjcPcrB7nurHkVc23ohsGuwSTP7B1hy8EYqv52PGFejYsN7bWsnVc9qUzAdEMQBNqq3bRVu/ngikaiaYVtvbnGq7cGEsiawe6hJLuHktz3eh+NPgdrWnNlAYvqPEWzfYpnFW57ch/dkdwe/pkz2jh7YfmG2Yw1SM2dRg1ShcZpy4nReq99vH41lMzt6+GUUrT6VcMwyCo6cUkFA7wOKwvr3FS7crWmlbKfTFfyjqReffXV9Pf38+CDD5JOpznzzDP5xS9+wdq1a0kmk1x++eX4fD5+85vfFHvNEzJdIqmHTr+5ZGUTH1pZ/PqleFZB12FJg5dqtzlj+1B0wyCcVhiIZwmlZQwDql027EcQq+WOqJkUnmc7Qvzs5W4APrtuLmfOr3nXe0p53mMZhef3h3m2I8Rg4u3juWwW1s6vYUN7kHk1M8eR4HiRVJ0dAwm29sTY1hsjmlEP+77HbmXV6JjWFU3+44osHum8R9MKtz7ZQW8si0WAz66bxxnzqqf2jzlOxhqkBAPaql20VLlmhfdvvuijJV6xjMJISiYpq+jasetX87neVd0gOToxyymaUdOpMuVI6tatW/n85z+P0+kkk8kc9j2v18tHP/pR/vM//3Nqq5wF9Mez/PyvuRvi8iYfm1Y0FP2YsqaTlnQW1LpNgXoELIKQqxdy2QinZQbiWcJpBUGAKpdtVkYlZhPnLKzh9VFbpF++0sPieu+kpy5NFV03eHMgwTN7R9jaE+OQUlMW1XnY0B7ktLlVFTM2shJwiJbxqKluGHSGM+N1rN2RDClZ48UDEV48EMEqwJIG37hbwPHW44+kZG59ooPBhIRoEbju7HmcPKeqwP+y/NBHG6TcdpG5NW7qvXYzavcOLIJAlctGlctGS8CZ818drV8dTki5+lW7FZfdmledqGEYZBSdxGjU1OcQaQ44qXbbCurHbfI2k6o4t9sn3rglSULX9Qm/b5Kzvrn9uQNkFZ1ql43Prptb9AJqwzAIJWUafA5aAtNzqlSpsFoE6rwOqt12QqlRsZpSsFoEqlxiWUcamhQPQRC4+ow5fO3hFAlJ5a6XuvjHje0laW4Ip2Se2xfmuX0hRlLy+Oseu5V1C3JR0+k4rrjUWASBBUE3C4JuLlnVxEhKZttohHXHQBJVN3hrIMFbAwl+taWX1iona1oCrG4NsDDozqthdTAhcesTHYykZGxWgS+sX1B0u8CJUDSdkaRMtdvG/BpPScrFpjui1ULQYyc46r96aP1qPC5hO0r9qqrpJCWNtKLhGi0pqPXkoqZHyriZFI68ReqqVat45JFHuOqqq971vXQ6zQMPPMCKFSsKuriZxq+29HAwmksRff7seSXxLYxmVDwOK3OqXabIyhPRItDgcxB02xhJyQzEJYaTMnbRgtNlM3+PMxC/08bVZ7TxH8/uZ8dAkj/vGuZ9S4vTpa3pBn/rjfNMxwh/64tzaMHV0gYv69uDnNJWVXHTl6YTtR475y2u47zFdWQVjTf7x8oC4iQklZ5olp5oloffGsTvFHNlAS0Bljf5jihS+mJZbn2ig0hGwSFa+IcNC1jaeOT0ZLHJKBqRdK5Bal7QfVxWerOdd9avxrMqI0mJhKQRTivUjo5sTY926JtR0/KR91/3DTfcwJVXXsknPvEJNm7ciCAIbN++nb1793LvvffS19fHzTffXMy1TmvGOnMBLl3dzOJ6b9GPKakasqpzQr23ooy8pwui1UKj30nQY2ckJdMXyzKYkHCKVlA1LIKAVRBmxVzp2cBJcwKsbw/ybEeIB7b2sbzJV9Ao5nBS4tmOEM/vCxPJvG2r5HOInL2whvXtwYJ3p5vkBMkpbVWc0laFrhvsC6XG3QJ6Y1niWZXn94V5fl8Ym0VgaeNoWUBLAK/XwYGRFLf8eS8JScVls3Djue0sqvOU5d+SyKqkZY22qlyDlBnFmxrCqBj1OkQa/Q4SWZVoRiGLQDStIKk6DV4HwdFpUObvu/RMyoJq8+bNfOtb36Knp+ew1+vq6vjGN77BBRdcUPAFToZKbZzqjWb41uN7kDWdVS1+vrRhQdFTibphMBCTaKlysqjOaxbTFwBJ1ZEsAn2RDKFYFs0w0HUD3TAwAEHITcqxWoRDBCxYBSH3mmX0NQHzKbxCySga//ToLoaSMm3VLv75fScgWi3Hb0mj6bzeE+OZjhBv9SfGp9JsfTsAACAASURBVCoJ5Ea0bmgPclJrwIzOl4mhhMTWUbeA3YPJw2qBAebXuhlOSCQlDY/dyj9ubGd+GcboGqPNnRgwp9pFq9kgVVTc3pxgTSclc5x2iSiYmb9hGOzYsYPu7m50XaelpYXly5cjiuVPOVSiSJVUjX9+fA+9sSw1bhvf+cASfCUw2h5JyrhtVpY2+madX14xCQRcyKrOcDiFqhtoujH+/7mvdWRVR9Z0ZG1UxGKg6bm/T83Ivf/QLc9iyYnYnJjlsAitVciJXnOTLB17hpLc8pe9GAZcvKyBy9Y0T1qk9sezPNsR4oX9YeLZt7vOq1228ajpbBumUemkZY3tfXG29cT4W1+clKyNfy/gFPnKee1lqQ8ea5By2a3MrXbT4HOY+0GRCQRy5zkWyxzjnSaFYsrd/TfddBObNm3i9NNPZ9myZSxbtqxgi5upGIbB3a/00BvLYhXg+rPnl0SgpmUNg9wTtylQC49dtOQ15cYw3hax40LWOFTQ5v43JmqVUVGrGjqqNvo+DHQdxkJwBgYWSy4aOy5kJxC4JsfHCfVeLlrWwMNvDvLIjkFWtvg5OQ9BKWs6W7qjPNsRYufg2w/LggCrmv1saK9lVYvfjIBVKG67lTPmVXPGvGo03WDvcJI3h1IMJyQ+tLyhLKUYiqYznJSpdtmYHzTdWUxmH3krpkcffZQHH3yQ+vp6PvCBD3DxxRezdOnSYq5t2vPcvjCb94cB+NhJLbSXoI5J0w2iGYW51S7qvOaGVk4EQUC0CuTrGmQYBprBuIgdi8yOR2uNXERW0XLRWknTx9+n6DpZhXeXIJATSWYJwuT48IpGtvfG6Ypk+MmLXfxHa9WEpvk90QzPdITYvD98WPSt1mPnnIVBzllYc9yjk03Kg9UisKTBxykLa4Hy+CJnlVwTT4PPwXyzQcpklpJ3uj+TyfD000/z2GOP8fzzzyPLMvPnz2fTpk184AMfYM6cOcVe6zGppHR/dyTDzX/cjaIZnDwnwA3nzC+JCBhMSFQ5bSxp8E56FJzJsam0NJD2jgjt4aUH+ZcgaIdMMxIA4SgRWrt1dpQf9EYzfPOx3Si6wcYldVy3YeG4WJFUnVe6IjzTEWLvcGr8Z6wCrGkNsGFRLcsbfWZEe5pTruEdiaxKSlJpNRukykKl7fOzgYLVpAIkk0meeOIJHn/8cV588UVUVWXVqlVcfPHFfPzjH5/yYo+XShGpGUXjW4/tZiAhUee18+0LF5fkKTiRVVE0gyUNpTcjny1M980rnxIETTeQ3lGCcOh7JE3HbbPic048sWWm8KddQ/x6Sy8AX73gBNxWgWc6Qrx0IExGedsXusHnYH17kLMW1FDlMp00ZgqlFqmGYRBJKxhmg1RZme77/HSkoCL1UA4ePMgtt9zCM888gyAI7Ny5cyofNyUqQaQahsEdL3TyclcU0SLwjQtOYEEJukFz5s4KC2pdzKspjz3KbGA2bl6HRmcVTSeWURga9RQULQJ+pzhjIz26YXDbkx3sGEhitQiHRZxFi8Apc3JR0yUN3pKY/5uUllKKVF03GEnJOG0Ws0GqzMzGfb7cTLlx6lDC4TB/+ctfePzxx9myZQuapnHqqaeyadOmKS1yJvD03hAvd0UBuOLklpII1NxUKYV6n52WgDmdxqSwiBYBcTyaYyXgstHgdxJJywwmJKJZBUM38DttE9ZtTlcsgsA1a+dy06O7xutNmwNONrQHWTe/Bp/TrBM0mTrqaINUldkgZWJyGHnvsJFIhD//+c/88Y9/5NVXX0VVVRYvXswXv/hFLrroIhobG4u5zmlBZyjNr7bkPGRPn1vFxhNqS3LcWFbF7bAwp8plzpk3KQkOMTfooNbrIJrJzcEOpxUiGQWvw4rXIc6YyGKNx843PrCEVw5EWFbvYVGdx4xwmRSMQxuk5tW483IOMTGZLeR9NZx11lnouk5TUxNXX301F198Me3t7cVc27QiLWvc/vwBVN2gwefg709vK8mNTFJ1JEWnvc5DwKyFMykxokWg1mMn6LblRgumZEZSEgNxCafNgt9pOyQKO31Z3OBjcYOvLF3eJjOXhKSSyuYapObVuHHM0LIZE5PjJW+Reumll7Jp0yZOPvnkYq5nWmIYBj99qYuhpIzNKvD/nDOvJGlP3TAIpWRa/E4azXGKJmVEEAQCLhsBl40mv5PwaCnASELCahXwO23mDdjE5BDCaRldz021aq1yz4iHOROTQpO3SL355psJhULs3LkTwzCor6+ntrY06exK5y+7h9lyMAbAlae00lZdmrF5kbSC3yHSWu0yNziTisFtt+K2u6j3OginZYYSEtGsiqbp+Fwibps5ZtBk9qIbBsNJGadoYWGd2SBlYnI0jilSJUnipz/9KQ8//DBdXV2HfW/OnDls2rSJq6++GpdrdjbsdIXT3Pd6HwBnzq9mfXuwJMfNyBqaYTCn2mXWMJlUJPbRutW6sbrVZK5uNZaW8DqteO2i6SNqMqsYa5AKjDZI1ZgNUiYmR+Wo6ubAgQNce+21dHd3U1tby4UXXkh9fT02m42hoSFee+01br/9dv7whz9wxx13sHDhwlKtuyJIZlXufrUHTTdoDjj51GlzSvJErOkGkYxCW5WLep85/9uksrFaBIIeOzVuGwlJJZySGUrmygEcogW/U0Q0G/5MZjiSqhFKKdR77cwPeszggolJHkx4lSSTSa699lpisRjf+973uPjii4/4vieeeIJvfvObfP7zn+d3v/sdXq+3aIutJAzD4I7n9hNJK9itFq4/e17JJjyFUjI1bhtzql0zpoPaZOYjCLnaVL8zZ2EVTssMxiVCKQVBAL9TNKekmcxIkpJKwmyQMjGZNBNeKffffz+9vb3cddddEwpUgPPOO4+f/exn9Pb28j//8z9FWWQlcu9fu3mtO+eH+snTWmmtKk25Q1JSsQoCc6rd5g3dZNrisllpCbhY0eznxEYfQY+dlKQxEJNISipTnDFiYlIxhNMyGUVnQa2bhbUeU6CamEyCCa+WRx99lPe///2sXLnymB+ydOlSLr74Yh555JGCLq6SeW7vCJDzQz17YWnqUFVNJ5FVaalyEnSbdlMm0x+b1UK9z8GJjT6WNflornKi6gb9cYloRkHXTbFqMj3RDYPBhIRVEFhU52FutdnBb2IyWSZM93d3d/ORj3wk7w9avXo1TzzxREEWNR34pwuX8L/b+lhQVbqa0JGUTK0nN1XK7AY1mUlYBIFqt51qt52kpDKSkhhOyAwmZGzi6OhVs27VZJow3iDltPH/t3f/QU3f9x/An58khIQEQvihKL8UdN8quqLt2WKZ9RyUU4pCO7UV6OpmO629K1q6Yg+v3VoPtTfruqKrc9gbWuu5mwwtupYqG6PnurnWq9VRezq0+GsGUEjI78/3j5CUKFajST4peT7ueob3J/nklQTok/fn/WNMfBTiNZwgRXQ7bhhSRVH0KQg5HA7I5eFz+Tk9XoMZ4xNwwWAMyvNd6bdBFSFHmj5q2O6TTgQA2kgFtJEKJEWr0GWyuZawMtkgwjVuVc1hLhTCOEGKyH9umHYyMjJw+PDhWz7R4cOHMXbsWL8URd6sdidMVgdSY9WI5WV+ChOqCDlG61SYNCoaE5OikahRwmRx4PwVM3o5bpVCUJ/Fjm6jHck6FcYnahlQie7QDUPqnDlz0NzcjE8++eSmJ2lra0NzczMeeeQRvxZHrh5tg9GKpJhI7ipFYUkhlyFRG4kJSdGYNCoGaXo1RHFg3KrJBgfHrVII6DbZYLI5MDZejXGJWk5sJfKDG4bU0tJSZGZmYtmyZdi9ezesVut197Fardi+fTueffZZTJ48GcXFxT49udPpxM6dO1FUVIQpU6YgLy8PNTU16Ovr8/2VDFPd/TZoIxVI46B7CnMyQUBsVATGJWqRlRSD8QkaKOUyXOq14HKfFVa7U+oSKQw5RRGXei0QBGB8ghbpcfxdTeQvgvgt18wuXryIZcuW4fjx49BoNJg4cSISExMhl8thMBjw+eefo7e3F9nZ2aitrUV8vG+z3Lds2YKNGzfipz/9KXJycnD69Gm8+eabmDRpEn7/+9/7/GKcThEGQ3ACrk6nxr/PdOOCwYi4AA2K77c50Gu243sjtBjFXtSQoNO5lhq7cqVf4koIACx2J7oHtl7tNrtWA4hRRSBK6d9eLK3WNUGyr8/i1/NSaLvZ5253ivhfr4UTpIYZ/p4PvsTE6CHbv3XAzMiRI7Fr1y7s2bMHDQ0NOHr0qKdHVaFQYOrUqSguLkZJSYnPs81FUcTWrVuxcOFCPP/88wCA6dOnQ6/XY8WKFThx4gQmTJjg0zmHE6dTRLfJhpRYNUZyVymiIUUObL2aMLD16uVeCwwmG67026CJlEMbqeCGFxQQFrsTBqMViRrXBKloFcefEvnbTX+qIiIisGDBAixYsABOpxM9Pa4F7OPi4u7oiY1GI+bOnYvZs2d7tWdkZABwLYEVziHVYLIiVh2BNO4qRXRTCpmABI0S8VERuGq247LRistGCy5ctUAVIUOMKoKXYMlvjBY7es0OJOtUGBPHjVWIAsWnP/1kMtkdh1M3rVaL6urq69rda62OGzfO53MKwjfd9IGmUMihkMsRpVF6Lgn5S5/FDq0mEhNHxWAkL/OHFIXC9T+jYH2fke9iAaTBFSQMRisuXOnHFbMdMqcInTritgKFe3k9f/+sU2gb6nPvMlqBCDkmjYhBekIUIrh+77DD3/OhI6SuTxw9ehRbtmxBXl4eMjMzpS5HEnaHEz0mGzITNBjBy/xEt00TqYAmUoGkGBW6jFZcuGpGl8mKLqMNMWoFNEo5N8WgW+YUXeNPI+Ry/N/IGIzWqSBj7zxRQIVMSD1y5AiWLl2KlJQUvPbaa7d1DlEM3kBnnU4Nu8MBk9EKf07VunjVDH2UEjqFDFevmv14ZvIHDqj/blIDSNMqoVMI+F+fFV1XzOi0OqCNlCM6UnHTsMGJU+HJ/bn3XDXjcq8V0So5kmNUiJYBvb38/Txc8fd88N3WxKlgaWpqQlVVFcaMGYOtW7dCr9dLXZIkrpptUCrkSNOrEcldpYj8Si4TEBelhF4dgb4YFQxGCy71WXGx1wKlQoYYlYKXbsOcKIoQRUAcuG21O2F3OnGp18IJUkQSkPynbdu2bVi3bh2mTZuG2tpaREcPnaaHO6vDCZPFiYyEKOijuIwJUaAIgoBolQLRKtdQAMPAElZdRhsgADqVghNhJOIOiU7XFwP/AiJEOEXXbaerAc6B+wPwOjY4ZLqPiaIIceBcEFz/ChDghAgB39yWCYLra8H1fWKVySATwAlSRBKRNKTu3r0ba9euxZw5c7Bu3TooleEZzkRRhKHPipHRkUjWcaIUUbCoIuRI1qkxUhuJLpMNl/pcu1h1m2yIVoXXuFV3kBsc8txf45qQOHQQdIVJr8dfcy54rcoteBoGh0T3yAvBHRjdt4WB8Aj3vwJkEFyrn8hcbTJBgHwgYMoHziWTCZDLhIFzfxNCZe5zDpxfJnzznLKB8+t0KsgEATazjatDEElAspBqMBiwZs0aJCcno7S0FMePH/c6npaW5reVBEJdT78dmkg5UvVqKHi5kSjoFHIZRkRHIkGrxJV+Gy73WXHZZMX5qxZEKeVQRykhD1BI8SUcunsQMTgQDvG468LiwGOu60UUAIjfhEV3cIMnBLoMDomeEHmTkKiQDYREQYBsUEh0P35wSPTcHhwSPbcHP7fwTWgduB/cAXOg3Z90A1e1rljtfj0vEd0ayUJqa2sr+vv70dnZidLS0uuOr1+/HvPmzZOgsuCy2B2w2p343ggtYlQRUpdDFNZkggB9lBL6KCVGDSxhdanXggtXzVDKZbBZbABw8+CIb3oSvQkQv+USMwRABsErcMnc7YPCoQBALsg84VCAOxy62mUyeEKhXOYOekMHROGakCcM1OB+TgFDh8TrHhMmPc5EFDyShdTi4mIUFxdL9fQhwSmKMPTZkByr4q5SRCFGG6mANlKBkdGRsCvkuHClH90Wu3fPIQb1FgpCUMJhMHoQiYhCgeQTp8JZl9GGWHUEUvXqgF1KJKI7o4qQQ6dTIylGhZ5oE8MhEVGQMKRKxGR1QASQoldDo+THQBTq5DKBY8aJiIKIv3El4HCK6DHZMDomEiO04bmiAREREdG3YUiVwGWjFfEaJVJi1bxcSERERDQEhtQg6zXbESGTIVWv5sLQRERERDfAkBpENocTfRYHkmMjEa/hZX4iIiKiG2FIDRJxYLmpRG0EknVqqcshIiIiCmkMqUFyxWyHWilDmj4KEZwhTERERPStmJaCwGJ3wmx1ICVWDZ2au0oRERER3QxDaoA5RREGoxVJMSokxaikLoeIiIjoO4EhNcC6TTbERCqQqldDwV2liIiIiG4JQ2oA9VsdcIgiUvVqaCO5qxQRERHRrWJIDRCHU0R3vw2jo1UYER0pdTlERERE3ykMqQFiMFoRFxWBVL0aMu4qRUREROQThtQA6LPYIRcEpMZyVykiIiKi28GQ6md2hxNXzXaMjlVxVykiIiKi28SQ6meXjVYkapRI0akh8DI/ERER0W1hSPWjK/02qCLkSNNHQangW0tERER0u5ik/MRqd8JkdSA1Vo3YKO4qRURERHQnGFL9QBzYVWpkdCR3lSIiIiLyA4ZUP+jut0EbqUB6XBR3lSIiIiLyA4bUO2S2O2F3cFcpIiIiIn9iSL1DdqeIpBgVRnJXKSIiIiK/YUi9QwkaJdK4qxQRERGRX/H69B3QR0VAp5BBzV2liIiIiPyKPal3YGyCFgncVYqIiIjI7xhSiYiIiCjkMKQSERERUchhSCUiIiKikMOQSkREREQhhyGViIiIiEIOQyoRERERhRyGVCIiIiIKOQypRERERBRyBFEURamL8BdRFBGsV+PeBXX4vHt0K/i5hyd+7uGJn3t44ucefDLZ0FvLD6uQSkRERETDAy/3ExEREVHIYUglIiIiopDDkEpEREREIYchlYiIiIhCDkMqEREREYUchlQiIiIiCjkMqUREREQUchhSiYiIiCjkMKQSERERUchhSCUiIiKikMOQSkREREQhhyGViIiIiEIOQ+pt2LdvHwoLC/H9738fs2fPRkNDg9QlUYA5nU7s3LkTRUVFmDJlCvLy8lBTU4O+vj6pS6MgevbZZ5Gfny91GRQE//znP/H444/j7rvvRm5uLl599VUYjUapy6IA27lzJ2bPno3s7GwUFRWhsbFR6pLCGkOqj5qamlBZWYnc3FzU1tZi2rRpePHFF3HgwAGpS6MA2rp1K1599VXMnDkTtbW1WLx4MRoaGvDcc89JXRoFyZ///Gd8+OGHUpdBQfDZZ59h8eLFSExMxObNm7F8+XI0Njaiurpa6tIogHbt2oVXXnkFM2fOxKZNmzB9+nS88MIL2L9/v9SlhS1BFEVR6iK+S/Lz8zFp0iS88cYbnraKigq0t7fzG3mYEkUR9913HwoLC/Hyyy972puamrBixQo0NDRgwoQJElZIgXbx4kUUFRVBrVZDqVQyrA5zZWVlAID6+noIggAA2LFjB7Zt24a9e/dCrVZLWR4FyGOPPQalUok//OEPnrbS0lLIZDLU19dLWFn4Yk+qD86ePYszZ87goYce8movKCjAqVOncPbsWYkqo0AyGo2YO3cuHn74Ya/2jIwMAMCZM2ekKIuCqLq6Gg888ABycnKkLoUCrKurC//617/w+OOPewIq4Aorzc3NDKjDmMVigUaj8WqLjY1FT0+PRBURQ6oPTp06BQAYO3asV3t6ejoA4PTp00GviQJPq9Wiuroa99xzj1d7c3MzAGDcuHFSlEVBsnv3bnzxxRdYvXq11KVQEHz55ZcQRRE6nQ4VFRXIzs7GPffcg5dffhlms1nq8iiAnnjiCbS2tmL//v3o6+vDgQMH0NLSgnnz5kldWthSSF3Ad0lvby8AV2gZzP2XFyfRhI+jR49iy5YtyMvLQ2ZmptTlUIB0dnaipqYGNTU1iIuLk7ocCoKuri4AQFVVFfLz87F582a0t7dj48aNsFgsWLt2rcQVUqAUFhbi8OHDqKio8LSVlJRgyZIlElYV3hhSfXCz4bsyGTumw8GRI0ewdOlSpKSk4LXXXpO6HAoQURTx0ksv4cEHH0RBQYHU5VCQ2Gw2AMDUqVM9Y9BzcnIgiiLWrVuH5cuXIzU1VcoSKUCWLVuGTz/9FKtWrcLEiRNx9OhRbNq0yXM1jYKPqcoH0dHRAHDdMiTuHlT3cRq+mpqasHjxYowaNQrvvPMO9Hq91CVRgOzYsQPt7e146aWXYLfbYbfbPX+oDr5Nw4v7ytiMGTO82nNzcyGKItrb26UoiwLs3//+N/7+97+juroaTz75JKZNm4annnoKVVVVqK+vx5dffil1iWGJIdUH7rGo106U6ejo8DpOw9O2bduwcuVKZGdnY8eOHRgxYoTUJVEA/eUvf0F3dzdyc3ORlZWFrKwsNDQ04MyZM8jKysKePXukLpECYMyYMQAAq9Xq1e7uYR08mYqGj3PnzgFw9aAPdu+99wIAvvrqq6DXRLzc75P09HSkpKTgwIEDXgt6f/DBBxgzZgxGjx4tYXUUSLt378batWsxZ84crFu3DkqlUuqSKMB+8YtfXHfVpLa2FidOnMBbb72FlJQUiSqjQMrMzERycjKampqwaNEiT/uhQ4egUCgwZcoUCaujQHF3Mh05csTzhwrgWjMXAJKTk6UoK+wxpPpo+fLlWLVqFXQ6HWbOnImPPvoI+/fv91o3lYYXg8GANWvWIDk5GaWlpTh+/LjX8bS0NE6qGYbcS4wNFhsbC6VSicmTJ0tQEQWDIAiorKzEypUrUVlZiUceeQTHjh3D5s2bUVZWxp/1YSorKwt5eXlYs2YNent7MWHCBBw7dgy1tbWYMWMG7r77bqlLDEtczP82vPfee6irq8P58+eRmpqKp59+GsXFxVKXRQHS0NCAF1988YbH169fzyVKwkRVVRWOHDnCxfzDQHNzM2pra/HVV18hPj4eCxcuxM9+9jNOkB3GrFYr3nrrLTQ2NsJgMCA5ORkPP/wwnn76aV49kwhDKhERERGFHP5JSEREREQhhyGViIiIiEIOQyoRERERhRyGVCIiIiIKOQypRERERBRyGFKJiIiIKORwMX8ioltUVVV10+1Qf/jDH2LTpk23fM7y8nJ0dnbi4MGDd1reLXO/Du5DT0ShjCGViMhHq1atgl6vH/LYqFGjfDrX0qVL0d/f74+yiIiGFYZUIiIf5eXlISUlxS/neuCBB/xyHiKi4YZjUomIiIgo5LAnlYgoAGbNmoWcnBxkZ2fjt7/9LQwGA+666y5UVFTg/vvv99zv2jGpVqsVr7/+Og4ePIiLFy8iPj4es2bNQkVFBXQ6nedxnZ2d2LhxI1pbW2E0GjF27FiUlZVhwYIFXnUcO3YMGzZswKeffgqtVouysjIMtRv2hQsXsGHDBvztb3+D0WhEZmYmfvKTn2Du3LkBeoeIiL4dQyoRkY+uXr2Krq6uIY/pdDrI5XIAwMcff4zGxkaUl5cjMTERO3fuxJIlS1BXV4dp06YN+fhf/vKX2LdvH5544gmkpqbi5MmT2LFjBzo6OlBXVwcAOHv2LBYsWACLxYKysjIkJibigw8+wOrVq/Hf//4XP//5zwEAJ0+eRHl5OWJiYvDMM8/AZrOhrq4OVqvV6zkvXryI+fPnQxRFlJeXQ6fT4aOPPsILL7yAS5cuYcmSJf5664iIbhlDKhGRj0pKSm54rKGhARMmTAAAnDt3DrW1tcjLywMAzJs3DwUFBfjVr36FXbt2Dfn4vXv34tFHH8XKlSs9bVFRUZ4eU41Ggw0bNqCnpwd//OMfkZWVBQAoLS3FM888g7q6OpSUlGD8+PH4zW9+AwB47733PBO6CgoKUFxc7PWcb7zxBqxWK/bu3YsRI0Z4zldZWYlf//rXKCkpQXx8/O28VUREt40hlYjIR6+//joSEhKGPJaWlua5nZGR4QmoABAXF4d58+Zh+/btMBgMQwa/pKQkNDU1YdKkScjLy0NMTAwqKipQUVEBAHA4HGhpaUFubq4noAKATCbD0qVLcejQIRw8eBCZmZlobW3Fgw8+6LXiQGZmJnJzcz3DC5xOJ5qbm3HfffdBoVB49RA/9NBD2LdvH9ra2njZn4iCjiGViMhHU6dOvaXZ/ePGjbuuLT09HaIoorOzc8iQ+sorr6CiogKrVq3C6tWrkZ2djfz8fDz66KOIjo5Gd3c3TCYTxo4de91jMzMzAbjGq/b09MBkMnmFZreMjAxPSO3u7kZvby+am5vR3Nw85Os4f/78TV8rEZG/MaQSEQVIRETEdW0OhwMAPONWr5WTk4NDhw55/mtra0NNTQ3eeecd/OlPfxpy0pOb0+kEACiVSk+b2Wy+4f0G11NQUIDHHntsyPOmpqbe8DmJiAKFIZWIKEDOnDlzXVtHRwfkcvmQPbFWqxUnTpxAUlISCgsLUVhYCKfTiW3btmH9+vV4//33sWjRIkRFReHUqVPXPf706dMAXEMG9Ho9tFotOjo6rrvf119/7bkdFxcHtVoNu92O6dOne93v3LlzOH78ONRqtc+vnYjoTnGdVCKiAPn888/x2Wefeb6+fPkyGhsbcf/993stJ+XW3d2NhQsX4u233/a0yWQyTJ482XNbLpfjBz/4Adra2vDFF1947ieKIn73u99BEATMnDkTgiAgPz8fra2tOHnypOd+X3/9NVpaWjxfKxQKzJgxA3/961/xn//8x6uetWvXYvny5eju7r7j94KIyFfsSSUi8lFzc/MNt0UFXLP4Addl96eeego//vGPoVKp8O6778LpdHqWiLrWyJEjUVRUhHfffRf9/f2YMmUKenp6sH37diQkJGD27NkAgMrKSvzjH/9AeXm5Z3mrDz/8EIcPH8bixYs9m5sLXgAAAVVJREFUY2Gfe+45tLS0oKysDE8++STkcjnq6+uh0Wi8lqFyn6+0tBSlpaUYPXo0WlpacOjQISxcuBDjx4/311tHRHTLBPHbBjgREZFHVVUV9uzZc9P7tbe3Y9asWUhOTkZhYSE2bdqE3t5e3HvvvXj++edx1113ee577WL+ZrMZW7Zswfvvv4/z589DrVYjJycHK1asQHp6uudxHR0d2LhxIz7++GOYzWZkZmZi0aJF+NGPfuRVy+nTp7F+/Xp88sknUCqVmD9/PgDg7bffRnt7u9f53nzzTbS1tcFkMiE1NRXz589HeXn5DcfPEhEFEkMqEVEAuENqfX291KUQEX0ncUwqEREREYUchlQiIiIiCjkMqUREREQUcjgmlYiIiIhCDntSiYiIiCjkMKQSERERUchhSCUiIiKikMOQSkREREQhhyGViIiIiEIOQyoRERERhZz/BwgvoWzG/SUAAAAAAElFTkSuQmCC", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9gAAAHnCAYAAABDmfUgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAD1GElEQVR4nOzdd5xU9bn48c8509v2hYWlL7CoVBFQRFSkGGs0ttiNxmvUGE1iyc3P3Jhi1Hhvit4kN1FjiTF2RWNFATtNmor0trBtyk7v5/z+GHZlZYFd2N0p+7zzIsLszOwz7cx5vuV5FF3XdYQQQgghhBBCCHFY1GwHIIQQQgghhBBCFAJJsIUQQgghhBBCiG4gCbYQQgghhBBCCNENJMEWQgghhBBCCCG6gSTYQgghhBBCCCFEN5AEWwghhBBCCCGE6AaSYAshhBBCCCGEEN1AEmwhhBBCCCGEEKIbSIIthBBCCCGEEEJ0A0mwhRBZ9cILL1BbW9vhn3HjxnHCCSdwww03sGrVqmyH2iMWLFhAbW0tDzzwQLZD6dCXX37JHXfcwcknn8zYsWOZNm0aF198MU888QSJRKLddevq6qitreX666/PUrRdc8cdd1BbW8u6desOet3rr7+e2tpa6urqDni9/b2fJ02axGmnncbvfvc7wuFwdz2EbnPZZZdRW1tLIBDIdihdUltby9lnn33Y9zN//nxmzJhx2K/N/j4Da9as4YMPPjjo9boqlUrxf//3f8ybN49x48ZxyimncP/993f4Ou7YsWO/x9ra2lri8XjbdTdv3sy3v/1txo8fz5lnnsk777zT4e+/6KKL+P73v39Iseu6zrvvvssNN9zArFmzGDt2LMceeyzXXnstixcv7vA2s2bNora2tt1lF198Mffdd98hxSCEED3BmO0AhBACYOrUqUydOrXdZYFAgDVr1rBgwQIWLVrEY489xjHHHJOlCPue1157jR//+MfYbDZOPvlkqqqq8Pv9LF26lF/96le8+OKLPP744zidTgCKioq48cYbGTFiRJYj75zZs2dTXV1NRUVFt9/33u9nTdMIh8N89tln/OUvf+Hjjz/mH//4B2azudt/r+g6r9fL3XffzY9+9CMcDsdh3VdHn4FFixbxve99j9tvv50ZM2YcbrhtNE3jxhtvZOHChVRXV3PBBRfg9Xp55JFHWLRoEY8//jhlZWVt1//yyy8BOO200zr8jBoMBiCT+N5yyy00NDRw0UUXsXLlSr7//e/zwgsvMGbMmLbrL1y4kNWrVzN//vwuxx4IBLjttttYuHAh5eXlHH/88fTr14+GhgbeffddFi9ezNVXX81tt9120Pu6/fbbufjiizn99NM56qijuhyLEEJ0N0mwhRA5YerUqfudCfnDH/7An/70J+6//37+9a9/9XJkfVMoFOLOO++kurqap59+ut2Jejqd5uc//znPPPMMf/zjH/nP//xPIJNcHOpsVjbMnj2b2bNn98h97+/9/Itf/IInn3yS+fPnc9555/XI7xZd89vf/han08k555xz2PfV0WfA6/Wiadph3/fXvfTSSyxcuJBJkybx0EMPtQ10LV68mGuvvZb77ruPe+65p+3669evB+A//uM/2iXKX7d27VrWr1/P7373O0477TSi0Sgnnngizz77LHfeeSeQScL/8Ic/cNpppzFq1Kguxa3rOj/4wQ/46KOPuPDCC/nJT36CzWZr+7nb7eaqq67i4YcfZtCgQVx88cUHvL8JEyZw4okncuedd/LCCy90KRYhhOgJskRcCJHzvve972EymVi5ciXRaDTb4fQJy5YtIxQKcdZZZ7VLriEz0/WTn/wEk8nE22+/naUI89O3vvUtIPP8iuxraGhg/vz5XHzxxRiN+TXn8O9//xvIbHVoTa4BTjzxRI4//njmz5+P1+ttu3z9+vWYTCZqamoOeL+t2yBal2LbbDaGDRvWbnvE66+/zsaNG7npppu6HPcLL7zARx99xIwZM7jrrrvaJdcAFRUV/P73v0dRFP7v//6PZDJ50Pu89NJL+fzzz9stwxdCiGyRBFsIkfPMZnPbCeTXT7Y+/vhjrrrqKiZPnszEiRO58MILeeONN9p+vnHjRmpra7n99tvb3W79+vXU1tZy0kkntbtc0zSmTZvGJZdc0nbZrl27+K//+i9mz57NuHHjmDRpEueeey5PPfVUu9s+8MAD1NbW8vHHH3P++eczduxY5s2b17avc/ny5VxxxRVMnjyZ6dOnc8899xCLxbr0XLz22mtcdNFFTJw4kUmTJnHRRRe1nWjvrba2ljvuuINPP/2Uyy67jEmTJjFlyhRuvvnmg+4jhszeToANGzZ0+HO73c7//u//cvfdd7ddtr99pTt27OCHP/wh06dPZ9KkSXz3u99l8+bNzJkzh8suu6zteq3P37Zt27jvvvuYMWMGEyZM4KKLLmLt2rVomsbf/vY3Zs2axcSJEznvvPNYsmTJPrFt3bqVH//4x0yfPp2xY8cye/Zs7rvvPoLBYLvrdbQHO51O89BDDzFv3ry2/advvfXWQZ+vzmpdhtvR8vDPP/+c66+/nmnTpjF+/HjOPvtsnnrqKXRdb3e9WbNmcdlll7F582auu+46Jk+e3Pa8ti4D3ltdXR0//elPmTlzJhMmTOD000/nkUce6TBxaWxs5LbbbmPatGlMnDiRb3/723z88cftrtNdr9OKFSu48cYbmTFjBmPHjmXKlClcddVVfPLJJ+2ud9lllzFr1iwWL17MrFmzmDBhAj/4wQ/2+xw/+OCD1NbW8p3vfKfdvuKOPP7446TTac4888y2y771rW8xbty4fW577rnntn2+9/brX/+a2tpadu7cuc9n4I477uAnP/kJAL/5zW863Me/ePFiLrjgAsaPH89xxx3HT37yk3aJ8f7U1dVhNBo7XBZdW1tLOp1uV7ti/fr1DB8+HJPJdMD7LS4uBiASibRdFgqF2o7B6XSaBx54gG9+85sMHTr0oHF+3XPPPQfAddddh6IoHV6npqaGO++8kzvvvHOf939Hjj32WCorK/n73//e5XiEEKK75ddwrRCiT/rss8/w+XwMHDiQoqKitstblyyWlZVx2mmnYbfbeeedd/jBD37ALbfcwnXXXceoUaMYOHDgPiftrf+ur69n586dDB48GMgUI2ppaWlLvOvq6jjvvPOIRqPMmTOHAQMG0NjYyJtvvsnPf/5z0uk0l156abv7/vGPf8yIESO47LLLCIfDOBwO3nvvPa6//nrMZjPz5s3DYDDw4osv8uqrr3b6ebj33nt55JFHqKys5IwzzgAy+zt/+MMf8sUXX3Drrbe2u/7nn3/O5ZdfzuTJk/n2t7/NmjVreP311/nss8947bXXDrgHePLkyVgsFt566y2uu+46LrjgAo499ljsdnvbdU488cSDxrx9+3YuuugiWlpamD17NoMGDWLhwoVcfPHFaJpGVVXVPre5+eab8fv9nH766dTX1/Pmm29yzTXXMGvWLBYtWsS8efOIx+PMnz+f6667jjfeeIP+/fsDsHr1aq688kpisRgnn3wygwcPZtWqVTz88MMsXLiQp556ipKSkv3Ge8cddzB//nxGjhzJhRdeyLZt27jpppsoLy8/6GPtjNYlrHPnzm13+eLFi7nxxhsxmUzMnTuXsrIy3n//fX7+85/zxRdf8Mtf/rLd9evr67nooosYNmwYF1xwAVu3bmXhwoWsWrWKN998s23VwYYNG7jsssvw+/2cdNJJDB8+nKVLl3Lvvfeyfv167r333nb3e8UVV1BSUsK5555LU1MTr7/+OldffTXPPvvsPonc4bxOCxYs4KabbqKsrIzZs2fjcDjYuHEj7733HkuXLuW5557jiCOOaPtdPp+Pm2++mVNOOQWn07nfWdjHH3+cBx54gKlTp/KnP/0Ji8VywNfjtddeo7a2lsrKyrbLZs6cyWeffcann37KcccdB4Df728biFm2bFnb5QDvv/8+NTU1DB48eJ/kefbs2QQCAd555x1mzJjBxIkTKSoqaitC9umnn7Jo0SJOOukkLr30UpYsWcILL7zA+vXref755/ebgEJmkEbTNNLp9D5Jc+tg0u7du4FMsrxz506mTp3KXXfdxeLFi3G73dTU1HDVVVdx1llntd12zJgxWCwWHn30Ue666y4+/vhjNm/e3Dbo+PLLL7Nz504efvjhAz63HQmFQqxcuRK73c7RRx99wOvuPch5MKqqMn36dObPn4/P56O0tLTLsQkhRHeRBFsIkZN0XScYDLJy5Up+9atfAXDDDTe0/byhoYFf/OIXjBgxgieffLLthOqWW27hyiuv5A9/+AOzZs1i9OjRnHDCCTz99NNs3bqV4cOHA5kE2263E4lEWL58eVuC/f777wO0Jdh//etf8fl8/P3vf2f69Oltv//SSy/l/PPP59VXX90nwa6qquKxxx5DVTOLhNLpNHfddRcmk4l//etfjB49GoBrr72Wb3/72516PpYvX84jjzzCkUceycMPP9yWQHm9Xq644goeeughTjrpJKZMmdJ2mw0bNnDrrbdyzTXXtD2n11xzDR988AGffPIJM2fO3O/vKysr45e//CU//elPWbhwIQsXLsRkMjF27FiOO+445syZw5FHHnnQuH/zm9/g9Xr5wx/+wKmnngp89RqtWLGiw9sEAgFefvnltsGUH/3oR7z66qu89dZbvPbaa21JWnV1NQ888ADvvPMOF198Mel0mttuu41EIsH//d//tXt8999/P3/729+477772s267+2TTz5pqyb95z//uW0A4sknn+QXv/jFQR/r3pYuXdquMnwkEmHt2rUsX76c6667jhNOOKHtZ9FolDvuuAOXy8UzzzzDoEGDgMxAzc0338wzzzzD7Nmz2w1o7Ny5k0suuYQ777yzLQm78847eeaZZ3jzzTfb3ld33XUXfr+fP/7xj21Jfev74KWXXuLyyy9vlziPHTuW//3f/21L2MaNG8dvfvMbXnzxxX0S7EN9nVpfD5fLxUsvvdSuyNzf/vY37r//fl5//fV2CXYkEuGqq67ijjvu2O9z/tJLL3H33Xdz9NFH85e//AWr1XrA12jHjh3U19dz/PHHt7v8xBNP5E9/+hMff/xxWyK9dOlSNE3Dbre3W95fV1fH1q1b+c53vtPh79g7wT7hhBO48sor2547yAwc3H///W0z6Jqmcd555/H555+zbt26A37Gxo4dy4YNG1iwYEHbgBtAPB7no48+Ar5KtDds2ICu6yxZsoSWlhbmzZuHz+fj3Xff5dZbb20bSAIoLy/npptu4v77728bADz66KO54IILSCaTPPjgg1xwwQUMHDgQyLyfDjQQsLfGxkZ0XWfw4MFtqzm6y9ixY3n55ZdZtmzZPgNYQgjRm2SJuBAiJ7Qu62z9M2bMGKZMmcK1116Lz+fjjjvuaFcUav78+SQSCW666aZ2sxVWq5WbbroJTdN48cUXga9mWluXdqbTaZYvX84555yDyWRqd8L8wQcfUF1d3Va456yzzuLuu+9ul1wDjB8/HqvVisfj2eexzJkzpy25hsysal1dHeecc05bcg0wZMgQrrjiik49P60zn7fddlu7PdFlZWX86Ec/AuD5559vdxur1crll1/e9m9FUdoSu127dh30d5599tm88MILnHPOObhcLpLJJCtXruRPf/oT55xzDtdff/0Bl7J6vV4WL17MMccc05ZcQ2bm7cc//vF+b3fuuee2W6nQOtN1+umntyVtkHkN9n4sK1euZNu2bZx++un7DB7cdNNN9O/fn1deeWWf9mKtWpfa33zzze1m9y+55JIuV0ZfunQpDz74YNufRx55hGXLlmGxWEgmk+1qCbz77rt4vV6uvvrqtuQaMrNy+3ttAb773e+2S2xa3+etz0dDQwPLly9n+vTp7RIORVH44Q9/yI033rjPKoZrr7223WzorFmzADrcVnCor5OmafzoRz/ivvvu26eC+7Rp0wA6/Fwd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Zz/7GR9++CF/+ctf2tUs2J/Wz3c23tNCCLE32YMthMhZFRUV/PznPwfgnnvuaTfD0tqjde3atfvcbtu2bdx77728++67bZe17mv86KOPWLVqVdsy4smTJ2M0Glm6dCkffPABxx57bNuJZiAQYPHixYwdO5a77rqLo48+ui1prKurIx6Pd2qWqXVp+KeffrrPz1pPhA+mdelmR4XBVqxYga7r++wlPRwmk4nm5mbee++9/V6ndca0dWb464466igURWHNmjX7/GzTpk3dnmC3zlp29DxrmsaKFSuw2+1UV1fvN15N01i9evU+P+vs69QZrYlA63L91vdyR7+jpaWFX//617z88std/j2t99vR879y5UomTpzIn//85y7f7+H65JNPcLvdXHLJJXznO99hzJgxbYM4mzdvBrq2wqJfv35UVlZy/PHH841vfIO1a9fyxBNPHPR2rZXDW1da7K20tLRthnrFihWUlJS0PZ9Tp05tq/69957p/elsAbCuevzxx9sGa/aWSCRYtGgRlZWVbceNBx98kCuvvLKtiOPeWo8pHW1hafXoo4+iaRpXX301QNvWmL23yMTj8U491nPOOQeAv/zlL/u9zqZNm/joo4+w2WxMmjTpoPcJX72OX986IYQQvU0SbCFETpszZw5z584lGo22JduQKT5mMBj4/e9/T3Nzc9vlqVSKX/7ylzzyyCO0tLS0XT5ixAiGDBnCU089RTAYbJs5cTqdHHnkkbz66qs0NTW1m40ymUyoqkogEGi3ZzkWi7W1Teqol/DXjRs3jpEjR/LKK6+0S/6ampp45JFHOvU8nHvuuQD8z//8T7s9hl6vl/vuuw/IFCXrLq0tcn7+8593mKBt27aNxx9/nH79+u1ThblV//79Of744/noo49YvHhx2+WJRILf/va33RZrq8mTJzN06FDeeuutdr8P4I9//CP19fV84xvf2O8S5nPOOQdFUbj//vvbzbr/+9//7rYEe+fOnbzxxhuYTKa2xGzOnDk4nU4eeughtm7d2u76v/3tb3n88cfZsWNHl3/X4MGDmTRpEh988EG7xKq1T7Wu6/t97XpS6wDW1wuZ7d69mwcffBD4qg97V/3kJz/B4XDw+9//nvr6+gNet7Xg4KZNmzr8+cyZM9m4cSMLFy7kmGOOaUsep06dSjgc5umnn2b8+PH73erQqnX5eGeOFV0xZswY/H7/PttkWo8RV199ddssfmuRwf/93/9ttxpjy5Yt/PWvf6W4uLhdJfK9tbS08Oijj/Kd73ynbVCovLyc4uLidn22V69ezbBhww4a91lnncXEiRP58MMP+dnPfrZPv/Ft27Zxww03kEwmueGGGzq9RLy1FkfrQIgQQmSLLBEXQuS8//f//h8fffQR77//Pq+++ipnnHEGw4YN49Zbb+Wee+7hjDPOYNasWRQXF/Pee++xefNmTj755Ha9XSFzwvyPf/yjbf91q6lTp7YlkXvvv7bZbMyZM4c333yT888/n+OPP55IJMLChQtxu90UFxcTDAbRNO2Ay1EVReHuu+/myiuv5IorrmDevHk4nU7efvvt/e5j/bopU6Zw1VVX8fe//52zzjqLk08+GYCFCxfS3NzMd7/73Q6Lex2qqVOncscdd3Dfffdx4YUXcswxx3DkkUdiMpnYsmUL7733HmazmYceeuiAe25/+tOfcuGFF/K9732P2bNn079/fz788MO2QYKDLePtClVVueeee7j66qu57rrrOPnkkxkyZAgrV65k1apV1NTUcNttt+339hMmTOA73/kODz/8MN/85jc56aSTaGhoYMGCBQwZMqRLSe7X23RpmsbOnTtZsGAB0WiUm2++uW2mraioiF/96lf8+Mc/5pxzzmH27Nn069ePZcuWsWbNGsaNG7ffNlAHc9ddd3HppZfyH//xH8yePZvq6mo++eQTvvjiCy6//PIOC9D1tMmTJ1NdXc3LL7+Mz+djzJgx1NfX884772CxWFAUpd3gWFf079+f73//+9xzzz384he/OOAM/ZAhQxg+fPh+28WdeOKJ/PGPf2TXrl3tqv23VjoPBoOd6gXfWlH9qaeewu/3c9lll3XlIe3X1KlTmTNnDs899xwNDQ2MGTOGlStXsmLFCmbOnNmuj/SsWbM444wz2o6fs2bNIhAI8Pbbb5NIJHjggQf2u3XioYcewmQy7dOR4Nxzz+XRRx/FYDDg9/tZvXo1999//0HjVhSFP//5z22Vyt9++21OOukkSktL2b59O4sXLyaZTHLppZe2tTXrjE8//RSDwdDhdhUhhOhNkmALIXJe//79ueWWW/jlL3/J3XffzQknnEBxcTFXXXUVI0aM4JFHHuGtt95C0zQGDx7MHXfcwSWXXLJP4aHWBLu2trZd0app06bx0EMPUVtbu8/ywrvvvpuqqioWLFjAP/7xDyorKxk3bhzXXnstr776Ko899hhLliw56N7ZCRMm8NRTT/H73/+eRYsWoSgKc+fO5Zvf/OY+fbT354477uDII4/kySef5JVXXsFoNHLEEUfws5/9rEf6vl511VVMmzaNf/7znyxbtozPPvuMdDrNgAEDuOiii7jmmmuoqqo64H2MGDGCp556iv/+7//mo48+IpVKceyxx/K73/2Os846a5/9oIfr6KOP5rnnnuNPf/pT26DMwIED+d73vsd3v/vdg7YHuu222xg+fDiPP/44zzzzDFVVVfzqV79i/fr1bVW/O2Pp0qVtBbwgM4tZUlLClClTuPDCC5k9e3a763/jG9+gqqqK//u//+P9998nGo1SXV3N9ddfz9VXX33IbY1qa2t59tlneeCBB/jwww8JhUIMGjSIn/zkJ+0Spt5kt9v5+9//zv3338+KFStYvnw5AwYM4KyzzuKGG27g2muvZfny5YTD4UN63JdddhkvvPAC7777Lm+++Sbz5s3b73VPOeUUHnroIbZv375PRe+jjjqKyspKmpub25JqgJqamrbLO7P/esqUKVxyySW8/PLLPPnkk0yfPn2fCuyH6r//+7/5y1/+wmuvvcby5csZNGgQt956K5dffvk+A1+//e1vmTBhAs8++yz/+te/sNlsTJ06lRtuuGG/Ay1ut5t//OMf/OAHP9hnMPCHP/wh0WiU+fPnY7Vaufnmm9u1HDuQsrIynnrqKV599VVeeuklPvroIzweD06nkxkzZnDppZcyY8aMTj8PiUSCZcuWMX369IOuKBBCiJ6m6F0tJSuEEEJ0Quus7cCBA/cpGrZz505mz57Nt7/97XZL/4XoTfX19cyZM4err76aW265JdvhiEP02muvccstt3R7oUAhhDgUsgdbCCFEj1AUhW9+85uceeaZ+/TdfvjhhwHazQwK0dsGDBjA2WefzYsvvtjte6RF73n22WeZMGGCJNdCiJwgS8SFEEL0CEVRuOiii3jkkUc466yzmDlzJgaDgU8//ZRVq1YxY8aMtuJLQmTLD37wA95++22efvrpTm/XELlj2bJlfPLJJzz11FPZDkUIIQBZIi6EEKIHaZrG888/z7PPPsvWrVtJpVIMGjSIM888k6uuumqfpeNCZMNLL73Efffdx9tvv33I+91Fdlx0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CLptiCazQxrdlUgrsFklhAMOiCJHchFNJCYpvxc7Pz1g4laxmWATERER0UmJooBI0AGbxYRE+r33Vio5DYqiIRJwwG41jVOERFRKvC4LnHYzkhO4is0Em4iIiIhOyWbJj+5SVf2Uo7t0XUcsqaDCZ4PfbR3nCImoVJgkERUeG+TsxK1iM8EmIiIiovfkc1lQ6bMjnjz56K54SoHLbkLY74AgcGk40UTmdVlht5qQGmaDxHLBBJuIiIiI3tPg6C6XBbHk8UvF8/stgUjQCYtZKlKERFQqzKZ8R/GMPDGr2EywiYiIiOi0BkZ3SZIwWJlSNR2JlIJKvx1ep6XIERJRqfD1V7GHO+avHDDBJiIiIqIhGRjdlZFzyOU0xBIyvE4rQj6O5CKid1jMEoIeG9ITsIrNBJuIiIiIhizosSPotaEzmoZJEhEJOmCSeElJRMfzua2wWU3IZE/eHLFc8WxIREREREMmigKqAk4EPDZEgg647OZih0REJchqlhDwWJGaYCO7mGATERER0bBYLRJm1PtQyaXhRPQeAi4brJaJtRebCTYRERERDZvZJHEkFxG9J6tl4lWxmWATERERERHRmPC7rLCaJWSyEyPJZoJNREREREREY8JuNSHgtiGZZoJNRERERERENCp+jxVmkwR5AnQUZ4JNREREREREY8ZuNSHgsSA5AfZiM8EmIiIiIiKiMRVw22CSRGSV8q5iM8EmIiIiIiKiMeWwmeF3W5Ao873YTLCJiIiIiIhozAU8NphEoayr2EywiYiIiIiIaMw5rCb43Nay7ijOBJuIiIiIiIjGnCAICHhsEEUBSk4rdjhjggk2ERERERERjQunzQSfy4JkWil2KGOCCTYRERERERGNi4EqNgDkyrCKzQSbiIiIiIiIxo3LbobPZUGiDKvYTLCJiIiIiIho3OSr2HboAHKqXuxwCooJNhEREREREY0rl8MMr8OCTLa8OoozwSYiIiIiIqJxJQoCgj47rGap2KEUFBNsIiIiIiIiGnduhxlep7XYYRQUE2wiIiIiIiIad6IgoNJnh91mKnYoBVM+3wkREREREREZisdpgcdpKXYYBcMKNhEREREREVEBMMEmIiIiIiIiKgAm2EREREREREQFwASbiIiIiIiIqACYYBMREREREREVABNsIiIiIiIiogJggk1ERERERERUAEywiYiIiIiIiAqACTYRERERERFRATDBJiIiIiIiIioAJthEREREREREBcAEm4iIiIiIiKgAmGATERERERERFQATbCIiIiIiIqICEHRd14sdRLHpug5NK+2XQZJEqKpW7DCIxgSPbypnPL6pXPHYpnLG45veTZKGVptmgk1ERERERERUAFwiTkRERERERFQATLCJiIiIiIiICoAJNhEREREREVEBMMEmIiIiIiIiKgAm2EREREREREQFwASbiIiIiIiIqACYYBMREREREREVABNsIiIiIiIiogJggk1ERERERERUAEywiYiIiIiIiAqACTYRERERERFRATDBJiIiIiIiIioAJtglTtM03HbbbVixYgXOPPNM/NM//RMOHz5c7LCIRq2vrw/f//73ce6552LhwoW47LLLsGXLlmKHRVRwBw4cwIIFC/Dwww8XOxSigtmwYQPe//73Y+7cufjABz6Av/3tb8UOiWjUcrkcbr31VqxevRoLFizApz/9abzxxhvFDosMhgl2ibvrrrvwwAMP4Prrr8cf/vAHaJqGK664AtlsttihEY3K1Vdfja1bt+Lmm2/GQw89hFmzZmH9+vVoamoqdmhEBaMoCr75zW8ilUoVOxSigvmf//kffPe738WnP/1p/PWvf8VFF100eE4nMrK7774bf/rTn3D99ddjw4YNmDx5Mq644gp0dHQUOzQyECbYJSybzeKXv/wl/vmf/xmrVq1CY2MjbrnlFhw5cgRPPvlkscMjGrHm5ma8+OKLuO6667B48WJMnjwZ1157LUKhEB555JFih0dUMLfffjtcLlexwyAqGF3Xceutt+Kzn/0sPv3pT6O+vh5f+tKXcM455+CVV14pdnhEo7Jx40ZcdNFFWL58ORoaGvCd73wH8XicVWwaFibYJWzXrl1IJpM4++yzBx/zeDw444wz8OqrrxYxMqLR8fv9uOeeezB37tzBxwRBgCAIiMViRYyMqHBeffVVPPjgg/iP//iPYodCVDAHDhxAa2srPvjBDx73+C9+8QtceeWVRYqKqDCCwSD+/ve/o6WlBaqq4sEHH4TFYkFjY2OxQyMDYYJdwo4cOQIAqKqqOu7xUCg0+DEiI/J4PFi5ciUsFsvgY0888QSam5uxYsWKIkZGVBixWAzf+ta38L3vfe+EcziRkR04cAAAkEqlsH79epx99tn4+Mc/jmeeeabIkRGN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whdOGndHR8dpvzciIqJSxwSbiIiojPT29p7wWFdXF+rr60/6/HA4jOuuuw4/+MEPsGvXLjz++OO499574ff78a//+q8QBGEwST5WZ2cnfD4fAMDv9w/u2T7WQFIN5KveAHDjjTdi0qRJJzz3ZEk8ERGR0bDJGRERURl57bXXjkuy33rrLbS0tODss88+4blbt27FOeecg+3bt0MQBMyaNQtf//rXMWPGDLS1tcHhcGDOnDn429/+dlyn73g8jmeffRaLFi0CAJx11lloaWnBm2++Oficnp4evPHGG4N/nz9/PsxmM44ePYq5c+cO/jGZTLj55pvR0tIyBq8GERHR+GIFm4iIyACy2exxCeu7DYzeSqfTuOKKK/ClL30JyWQSt9xyC2bMmIGLLrrohH9zxhlnwGaz4Vvf+ha++tWvoqKiAi+99BJ27tyJz372swCAb3zjG1i/fj2+8IUv4FOf+hQURcE999yDbDaLr3zlKwCAiy++GL/+9a9x1VVX4etf/zpcLhfuvvtuaJo2+LX8fj+uuOIK3HrrrUgkEli2bBmOHj2KW2+9FYIgoLGxsYCvFhERUXEI+rGzPYiIiKjkfOc738Ff/vKX93zOhg0bcMMNN0DXdZx11ln4zW9+AyDfROxb3/rW4B7p22+/HXfccQd2794NADh48CBuuukmvPbaa4jFYpg0aRIuv/xyXHrppYOfe/Pmzbjtttvw1ltvwWKxYPHixbj66quPa0rW09ODG264Ac899xwEQcAnPvEJtLS0oLu7ezAWAPjd736HBx54AM3NzfB6vTj77LNx9dVXo7q6umCvFxERUbEwwSYiIioTl19+OQAcl9ASERHR+OEebCIiIiIiIqICYIJNREREREREVABcIk5ERERERERUAKxgExERERERERUAE2wiIiIiIiKiAmCCTURERERERFQATLCJiIiIiIiICoAJNhEREREREVEBMMEmIiIiIiIiKgAm2EREREREREQFwASbiIiIiIiIqACYYBMREREREREVwP8PgUX5PvuSjXIAAAAASUVORK5CYII=", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -380,14 +315,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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0KFD9dYtKiri6aefZsKECQwcOJDJkyfz6quvUl1dXW/d6upqXnvtNaZOncrAgQMZP348Tz31FCUlJQ2+Ho8++ihjx44lLi6OBx54gOPHjzfilfzd/v37Xa9PbGwss2bN4r333qs3BOLmm29m8uTJ5Ofn88gjjzBq1CgGDx7MjTfeWGc89anUjsfOyso65c/773//O++//z7BwcGuZQ2NczcYDLz66qtMnjyZQYMGceWVV7JmzRr+8Y9/1Lkg2r59OzExMfz88898++23zJw5k9jYWGbMmMHPP/8MwOrVq7nyyisZPHgwF110EV9++WW9uKqqqnjllVdcP5OxY8fyyCOPkJ6eXme9U/WESExM5LrrrmPIkCFMnDjxlOPhz4WiKGg0Gtfd6ZM19ryrHRdfUVHBU089RXx8PLGxsVx55ZWsWLGi3n6NRiPz5s1zjbufPHkyzzzzTIM9PcxmM2+++SaTJ08mNjaWmTNn8tVXX9VZp6l+Tk31GfVHmzZtcvXgOFOCbMOGDaSlpXHZZZe5lr388svExMSwbdu2Ouu+9NJLxMTE1LszX9sj5/vvvwfqvgcWLVrElClTXK9JQ31F0tLSuP/++xk2bBhDhw7lzjvvJDk5+bRxA66kwODBg+s9Vvu+2r17t2tZY5MQ/v7+KIpCTU2Na1l1dbXr9xnA//73Pzp37szs2bPPGOcf/fTTT1itVm688UYCAgIaXEen0/Gvf/2LF154oc7ny6n4+fkxadIkvvnmmzpxCyGEO8hwDCGE2xw8eJCysjI6depU54vWd999x7/+9S9CQkKYNWsWPj4+rF69mrlz5/Lwww9z77330qdPHzp16lTvS3Dt//Py8sjOznaNKd+/fz/l5eWu5EROTg5XX301RqORadOm0bFjRwoKClixYgVPP/00drudm266qc6+H330UXr27MnNN9+MwWDA19eXDRs2cP/996PX67nooovQarX8+OOP/PLLL2f1WmzcuJH333+fSZMmER8fz/r163n55ZdJTU3lpZdecq23fv1615216dOnExISwsaNG3n66adJSkriueeeq7ffVatWccUVV1BcXNzgl/FaDz30EBs2bCAhIYGpU6dSXFzM0qVL2bRpE4sWLaJnz54AHD9+nOuvv56CggISEhLo1asXycnJfPTRR2zZsoUvv/wSHx8fwHmxe8MNN5CamsqYMWOYPn06OTk5fPvtt2zcuJFvvvmGiIgIAPLz85kzZw7FxcVMnjyZTp06sXHjRu66665Gv46JiYnMnTsXjUbD1KlTCQsLY9u2bbzxxhts3LiRTz75pM7FrcFg4IYbbsDb25vLL7/c9ZzvvPNOfvzxR/r06XPKYwUGBjJgwAAOHTrEtddeyy233MKkSZMICwtzrdOY8fMWi4Xbb7+dffv2ERcXx0UXXeRKNHXq1KnBbT755BMyMzO5+OKLGT16ND/++COPPfYYhw8f5vPPP2fGjBkMHz6cxYsX8+yzzxIZGcnUqVMBKCsr4/rrryc9PZ0hQ4YwZcoUsrOzWbp0KevWrWP+/PmnPU++++47/vnPfxIaGspll12G0Wjkvffew9/f/4zPtTESExOpqKhgzpw5dZafzXlX6/bbb6e8vJyZM2dSU1PDkiVLmDt3Lh999BHjxo0DnAmI66+/nuTkZGJjY5kzZw5ZWVl89dVX7Nq1i6+//rrOxeXzzz+Pw+FgxowZaDQafvnlF5555hlsNlu9Ev7z+Tk11WfUH+3Zs4e//OUvBAcH8+mnn56x78Yvv/yCRqNh7NixrmUTJkxg/vz5bNu2jdGjR7uW137+7tq1q84+NmzYgKIoTJw4sd7++/Xrxy233MJnn31GVFQUF198cZ0hQCaTiTlz5tCjRw+uu+460tPTWbNmDXv27GHZsmX1qgROVvteb6gHS1VVFUCdJGdKSgpBQUF89913/PTTT2RnZxMeHs7s2bO59957XfvT6/X079+fRYsWMWvWLAwGAytXrmTEiBGAcxjIjz/+yCuvvIJWqz1lfKeyceNGgAb7UpwsISHhrPY7btw4li1bxqZNm5g+ffpZxyWEEE1GFUKIZvDDDz+o0dHR6rx58+osdzgcakVFhbpu3Tp16tSpanR0tPrdd9+5Hs/Ly1MHDhyozpw5Uy0tLXUtNxqN6nXXXaf27dtXTUlJUVVVVf/1r3+p0dHR6rFjx1zr3XvvveqQIUPU6OhoddGiRa7l8+bNU6Ojo9XU1NQ6227evLlOfPv27VOjo6PV6667rt62V155pWq3213LbTabOnnyZHXIkCGumFRVVTMzM9WxY8c2+Pz/KDs7W42Ojlajo6PVjz76yLXcYDCo1157rRodHa1u27ZNVVVVrampUUePHq2OGTNGzc7Odq1rt9vVv/zlL2p0dLS6bt061/La/a5evfq0MaiqqqakpKjR0dHqY489Vmf5smXL1OjoaPWll15yLbv77rvVmJgYde3atXXW/fTTT9Xo6Gj15Zdfdi17+umn1ejoaPWLL76os25iYqIaHR2tPvjgg65ljz32WL2fm8FgUG+66SY1Ojpavemmm077HKqqqtQRI0aoQ4cOVQ8ePOhabrVa1UceeUSNjo5W3377bdfy2v3ed999qsVicS1/99131ejoaPXVV1897fFUVVUPHz6sjhkzxvVaR0dHq7NmzVKfeeYZdcOGDarNZqu3TUJCgjps2DDX/z/++GM1OjpaffbZZ1WHw+Fa/tJLL7n2WWvbtm1qdHS02q9fP/XAgQOu5d98841r3ZN/Ltu3b1ejo6PVuXPnupY98cQTanR0tPrGG2/UiWvdunVqTEyMOn36dFfcte/jTz75RFVVVa2oqFCHDRumTpgwQc3Ly3Ntu3//fnXQoEFqdHS0+sMPP5z2Nas95xMSEtR58+a5/rz++uvqX/7yF7V///7q7bffrppMpjrbnc1597e//U2Njo5Wr776atVgMLiWL168WI2OjlYfeugh17I333xTjY6OVp9//vk6r/97772nRkdHq/Pnz1dV9ffPgYkTJ6pFRUWu9Q4dOqTGxMSol156qWtZU/ycmuIzSlV/P88rKirUw4cPqyNGjFDHjh2rpqWlqY0xYcIEderUqXWWWSwWNS4urk4MZWVlakxMjDpkyBA1NjZWNZvNrscSEhLUK6+8ss7/T34P1J4T9913X53jJCQkqNHR0eq//vWvOsv//e9/1zkvT+XHH39scHtVVdW5c+eq0dHR6m233aaqqvNzdPDgwWp0dLQaHx+vPv300+ozzzyjTp8+XY2OjlZvvfVW1Wq1urbftm2b63dNdHS0Om7cODUjI0NVVVX9v//7P/WSSy6pcz798edyOrWfKeXl5Y3eplbtuV/7e+NkycnJanR0tPrcc8+d9X6FEKIpyXAMIUSzevvtt+tMcda3b19GjBjBPffcQ1lZGY8//jhXX321a/3FixdjsVh48MEH65SYenl58eCDD+JwOFxN/mrvqm3duhUAu93Orl27uOKKK9DpdHXGlG/atInOnTu77mxfdtllvPDCC3Xu7oHzzrWXl1eDQwWmTZuGRvP7x+a+ffvIycnhiiuuIDo62rW8W7du3HrrrWf1OnXu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hHCbf/7zn2zZsoWNGzfyyy+/cMkll9CjRw/++te/8tJLL3HJJZcwefJkAgMD2bBhA2lpaSQkJHDZZZfV2c+ECRP44osvXP0gao0cOdLVof3kfhDe3t5MmzaNFStWcM011xAfH09NTQ1r166luLiYwMBAqqqqcDgcp+w0D867dy+88AK33XYbt956KxdddBF+fn6sWrXqrEu4/f39+b//+z/XvPfr1q0jOzub+++/3/WFMSAggH//+988+uijXHHFFUydOpWIiAh27tzJ/v37iY2NPee7toMGDeKiiy5ixYoVXHHFFYwePRqbzUZiYiJlZWWuL+EAzz77LDfeeCNz585lwoQJ9OnTh/T0dNatW0dQUBBPPfWUa92//e1v7Nmzh5dffpnVq1czaNAgCgoKWLlyJR4eHrzwwguu1/jhhx9m69atvPTSS2zatIlevXqxdetWysvLGzUO38/PjxdeeIGHH36YOXPmMG3aNEJDQ9m2bRupqakMHz6cu++++5xen4b4+/vzv//9j/vuu48nnniCjz/+mJEjRxIQEEB+fj7r16+noqKCJ5544rRf+m+77TaWL1/OBx98wO7duxk0aBBJSUns2rWLgICAUw7VOFd//etf+e233/jwww/ZuXMncXFxZGdns2bNGnx9fXn11VdPeWfa19eX5557jrlz53LNNddw0UUXAbB8+XJCQkIa1fm/Vm5ubp3ES23jyZUrV1JUVER8fDyzZs1yPX42593Z+NOf/sS6det477332LlzJ4MHD+bYsWOsW7eOQYMGnfVMN02hqT6jGqLRaHj66ae59tpree655xg9evRphxlMmDCBhQsXcvz4cTp16lTnsbi4OAICAsjNzWXq1Kmu86ZXr16EhYVRXFzMmDFjzjiMITg4GL1ez/bt23nxxReZNm0aw4cPP6vn1RAvLy/+7//+j+eff54rr7yS8ePHc/z4cVatWkWnTp3qnDOhoaE8/vjjPP3001x11VXMmjULvV7PunXrOH78OHfffXedIX0n27BhA7t373ZVJtS6+uqrue+++7jtttuIiorihx9+4Morr2xUD5KHH36YkpISFi1axJQpU5g0aRLdunWjoKCAzZs3U1paytChQ8841O1ktcnyxlZOCCFEc5FKCCGE20RGRvLwww8D8MILL7hKsG+//XY++OAD+vbty8qVK1m4cCEeHh48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oN599913euKJJ3T99ddr8ODBZscBamX69Onq3r37ee8aA56qsLBQkvTYY49p+PDhev3119W/f3+NGzdOa9euNTkdUDsHDhxQcHCwXnrpJS1atEi33HKLJk+erD179pgdDWh0bGYHwIX5+/tLqlob4qc/S1JZWZkCAgLMigXUm88//1yTJ09Wjx49lJaWZnYcoFaWLVumTZs2saYJvIqPj48kadSoUbr55pslSZ06ddLu3bv1xhtv1HhUFPAEx48f16RJk7RgwQL16tVLkpSQkKADBw4oIyNDc+fONTkh0LgwE8JN/TSl9z9X7D158qSioqLMiATUm3feeUcPPvighgwZopdffll+fn5mRwJq5f3339eZM2c0ePBgde/eXd27d5ckPf300xo9erTJ6YDa+ennjPbt29c4Hh8fr+zsbDMiAXWybds2VVRU1FiTSpISExOVlZVlUiqg8WImhJvq2LGjmjRpovXr11c/q5afn6/du3dr5MiRJqcDau+nbWdTU1P15JNPyjAMsyMBtZaWlqbS0tIax66//npNmDBBv/71r01KBdRNly5dFBQUpG3btlW/ayxJ+/bt4/l5eKTo6GhJUmZmprp161Z9fN++fYqLizMpFdB4UUK4KV9fX40cOVJpaWlq1qyZrrnmGj3//POKjo7W9ddfb3Y8oFYOHjyoZ599VsOGDdP999+v06dPV7/m7++v4OBgE9MBV+9iM9OaN2/OrDV4LH9/f40ePVovvfSSoqKi1K1bN3300UdavXq1FixYYHY84Kp169ZNPXv21GOPPaann35a0dHRWrZsmdauXav33nvP7HhAo0MJ4cYmTJigyspKTZ06VaWlperdu7dee+216mc1AU+zYsUKVVRU6LPPPtNnn31W47Wbb76Z7Q0BwE2MGzdOAQEBmjlzpnJyctSuXTtlZGSob9++ZkcDrprFYtG8efM0a9YsPfHEEzp37pzat2+vBQsWKDEx0ex4QKNjOJ1Op9khAAAAAACA92NhSgAAAAAA4BKUEAAAAAAAwCUoIQAAAAAAgEtQQgAAAAAAAJeghAAAAAAAAC5BCQEAAAAAAFyCEgIAAAAAALgEJQQAAAAAAHAJm9kBAABAlccff1xLly696Ovh4eFavXr1FV0rIyNDc+bMUWZmZn3Fu6jU1FRJ0ttvv93g9wIAAJ6NEgIAADcSERGhOXPm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", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -407,24 +342,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 15, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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BQF4/PiZIUIjIiIiHeTyQq2yJ0+eQSqVl0E09CaVp2tvb1+5yG1lNub2wYMHiIqKwp07dzTKnz9/DgCoVq1aWYRFRERERG+xMktuJRIJvvnmG2zZskWj/MCBAzA1NUXLli3LKDIiIiIieluV2bCE6tWrIyQkBJs3b4aNjQ1atWqF+Ph4rFy5EiEhIWjYsGFZhUZEREREb6kyHXM7ZcoU1KxZEzt27MDq1atRs2ZNjB8/Hp988klZhkVEREREb6kyTW7NzMwwcuRIjBw5sizDICIiIhLtbbiRwbusTG/iQERERPQ2eVtuZPAuY3JLREREJJJCIde6kYFCwWXQyhMmt0RERERUYTC5JSIiIqIKg8ktEREREVUYZbpaAhER0duIs+WJyi/23BIREemBs+WJyjcmt0RERHrgbHmi8o3JLRERERFVGExuiYiIiKjCYHJLRERERBUGk1siIiIiqjCY3BIRERFRhcHkloiIiIgqDCa3RERERFRhMLklIiIiogqDyS0RERERVRhMbomIiIiowmByS0REREQVBpNbIiIiIqowmNwSERERUYXB5JaIiIiIKgwmt0RERERUYZQquVUqlcjKykJBQYGh4yEiIiIiKjW9ktt///0X48aNQ8uWLdGpUyfEx8fj9OnTCA4ORlxcnLFiJCIiIiISRXRye/v2bQQHByM2NhYdO3aEIAgAAFNTU/zzzz8YMWIEzp8/b7RAiYiIiIhKIjq5XbRoESwsLHDgwAF8++236uS2TZs2OHDgAGrUqIFly5YZLVAiIiIiopKITm5jYmIwaNAg2NnZQSKRaGyrWbMmBg8ejKSkJIMHSEREREQklujktqCgAFWqVClyu5mZGfLz8w0SFBERERFRaYhObps2bYro6Gid2+RyOfbs2QNnZ2eDBUZEREREpC/Rye1nn32GU6dOITw8HDExMQCA1NRUHD58GB9//DGSk5MxfPhwowVKRERERFQSqdgd33//fXz//feYPXs29u/fDwD4+uuvIQgCKlWqhClTpiAgIMBogRIRERERlUR0cgsAffv2RdeuXXHq1CmkpKRAqVSibt26aN++PapVq2asGImIiIiIRNHrJg45OTnYu3cvfHx88Mknn+DTTz/Fs2fPsH//fjx//txYMRIRERERiSI6uU1NTUWfPn0wc+ZM3Lp1S11+7tw5zJo1C8HBwXj48KFR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X2P48OGYNGkSunTpAjs7O50TR1q3bm3QAImISH9SqQmUhfnISLltlPp13YI1/Z9rRrlVas0GjpCaVTJ4vURUMYn+FEpLS8PTp0+xf/9+HDhwQGu7IAiQSCQat+QlIqKyk5FyG1u+n26UupWCoFW29YeZMDHCahlD/jsDtZ2cDV4vEVVMopPbmTNn4smTJwgLC4Ojo6NR/jonIiIiInodojPU69evY+zYsRg5cqQx4yEiIiIiKjXRsw1q1arFtW2JiIiIqFwT3XP7ySefICIiAr6+vmjcuLExYyIiem1cLYCI6N0kOrm9cuUKJBIJevbsifr166NGjRowNdW81SBvv0tE5YVUagJBISAr9bFR6te1WkDWncdGmY9Qo25VoybqREQViehP4SNHjsDU1BS1atVCYWEh7t27Z8y4iIheW1bqY+xacdoodSuVCq2y31bFwMTEVMfer6fP6Hawb2Br8HqJiCoi0cntjh07UK1aNWPGQkRERET0WkT/ztWnTx8sX77cmLEQEREREb0W0cnto0ePUKNGDWPGQkRERET0WkQntz169EBUVBSysrKMGQ8RERERUamJHnNrYmKCGzduwNfXFw0aNICdnZ3WurdcLYGIiIiIypLo5PbkyZPqCWX5+flIS0szWlBERERERKUhOrmNjo42ZhxERERERK9N79XGFQoFkpKSkJqaCnNzc9SuXRsuLi6lalwQBGzcuBHbtm3DvXv34OjoiJEjRyIoKKhU9RERERHRu02v5PbIkSOYMWMGMjIyIAgCgBfjbB0cHDB9+nT4+/vr1fiqVavw448/Yty4cfD09MTx48cRHh4OU1NTBAYG6lUXEREREZHo5DYuLg7jxo2DnZ0dJkyYACcnJwiCgH/++Qdbt27F+PHjsWnTJrRo0UJUfYWFhVi/fj0GDRqE0aNHAwDatWuHpKQkbNmyhcktEREREelNdHIbERGBunXr4tdff0XlypU1tg0ePBj9+vXDihUrsGbNGlH1mZqaYvPmzbC11bylpJmZGfLy8sSGRURERESkJnqd2wsXLiA4OFgrsQUAGxsb9O/fH4mJieIbNjGBs7MzatasCUEQkJWVhdWrV+PUqVMYOHCg6HqIiIiIiFT0nlBWFIlEgsLCwlI9988//8T48eMBAH5+fujZs2cpYwCqVrUs1XOJSD+FhdofH1WqWMLMzKwMotEm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vn37oFQqu33YRq7Onz8PAANmvnRHXl4eUlJSoNFokJ2dLet36f4/vV6PhISEbsd5PnnyJAAMiFVLAIaVyi7nzp0DAFhbW4ueSUxmZmZYtWoV8vPzDWNtbW3Q6XTw9vZ+bFZuuS2hh6KiopCYmAgLCwsEBgbi8OHD2L9/v+wP4t912Ju7Pf3001CpVHB1dZUgkbgUCgXi4uKwfPlyxMXFYfbs2SgpKcH69esRHh4u+7eoLS0todVqsWXLFpibm8PLywvFxcX429/+Bq1WazhiiNxduHABgwcPlv0TGv2koaEB77//PqytraHValFaWmp0+ujRo2X9+29paYnXXnsNWVlZeOKJJ+Dq6ori4mJs2LABc+bM+Z/PDXLi4uKCoKAgvP/++7h58ybGjx+PkpISZGZmIiAgQPaHAlQqlXj11VfxySefwMrKCjY2NsjOzsbVq1eRmpoqdTwDltsemj17Njo6OpCTk4O8vDzY2toiNTV1QPyVloFuxowZUKlUyMzMxJIlSzB06FBERUVhyZIlUkcTRXx8PEaMGIH8/HxkZWVhxIgRiImJGRCfGO5SX18/oI6QQMDx48fx448/orq6Glqtttvpa9askf0hoRITE/HMM89gx44dyMjIwMiRIxETE4OIiAipo4kiLS0N69atw6ZNm9DQ0ABra2ssWrSo27F/5WrZsmUwMTHBxx9/jObmZri6umLTpk1wc3OTOpqBQvi5j/wTEREREfUT3HNLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRNQDO3fuhKOjI3bu3Nkn19/c3IzGxsY+uW4iIjliuSUiekyVlJRAo9Hg4sWLUkchIuo3WG6JiB5TFy5cQF1dndQxiIj6FZZbIiIiIpINllsiol40depUJCUlYffu3Zg5cyZcXV2hVquxdetWo/PduHEDCQkJCAwMxPPPP4+goCB8+OGHaG9vBwBkZGQgMTERALBgwQJMnTrVcNl//etfWLx4MSZNmgQXFxf4+/sjKSkJP/zwg+E8CQkJmD59Ov773/8iPDwc7u7ueOGFF/Dee++hra3NKEttbS3eeust+Pn5wdPTEy+//DKKioqMznPt2jW8+eab+NWvfgVXV1eEhoZiz549vXrfERH1BlOpAxARyc3x48dx4MABhIeHY9iwYdDpdFi1ahVsbGwwefJkAEBsbCxKS0uxYMECWFlZ4ezZs8jKykJTUxNWr16NadOm4fvvv4dOp8PSpUvh6uoKADhx4gR+//vfY8KECYiJiYFCocDJkyeh0+lw48YNpKenG3I0NjYiIiICGo0GISEh+OKLL7BlyxaoVCq8+eabAICmpiaEhYWhqakJWq0Wtra2KCwsRHR0NNatW4egoCDU1tZizpw5EAQB8+fPh4WFBQ4fPowVK1agrq4OixcvFv9OJiK6F4GIiB5Zfn6+4ODgIOTn5wuCIAhTpkwRHB0dhbKyMsN56urqBEdHR2H58uWCIAhCfX294ODgIGRnZxtdV0JCgrBw4cJu13369GnDWEREhDBlyhShvb3d6LJhYWGCp6en4fv4+HjBwcFB2Lx5s9H5NBqN4OfnZ/h+zZo1goODg3DmzBnDWFtbmxAUFCS8/PLLhuvy8fERamtrDefR6/XC8uXLheeff16or69/sDuLiEgEXLklIupl9vb2cHJyMnw/fPhwDBs2DPX19QCAIUOG4Mknn8Snn34KGxsb+Pv748knn0RycvLPXveGDRvwww8/QKVSGcauX78Oc3NztLa2dju/RqMx+t7JyQn79+83fH/06FG4uLhg4sSJhrFBgwYhKysLgwYNgl6vR1FRESZNmgRTU1Ojw5Kp1WoUFhbi5MmTCAkJeYB7hoio77HcEhH1MktLy25jKpUKer3e8O9Vq1Zh5cqViImJgUqlgo+PD9RqNUJDQzFo0KB7XrdSqURVVRXS09Nx6dIlVFZWora29oGz3J0DAKqrq43283axt7cHADQ0NODmzZsoKirqtg+3S01NzT1vn4hIbCy3RES9zMTk5z+rO2vWLPj7+6OoqAjHjh3DqVOncOLECXz66afIy8szWpm928aNG7FmzRrY29vDy8sLarUa7u7u2LJlC/bu3fvQWW7fvg2FQnHf0wEgODgYr7766v88j62t7X1vg4hITCy3REQia2lpQVlZGZ577jm88soreOWVV9DR0YG//OUv2Lx5M06cOPE/V1Pb29uRkZGBSZMmIScnB6amPz2E3/1BsocxatQoVFZWdhvftWsXiouLkZSUhMGDB6OzsxMvvPCC0XmuXr2K0tJSDB48+JFum4ioL/BQYEREIrt48SK0Wi127NhhGFOpVHB2dgZwZ+sB8NOqa9c2gra2Nvz444+ws7MzKrZlZWX497//DQDo7Ox8qCwBAQH4+uuvUVJSYhi7desWNm7ciJKSEqhUKgQEBODYsWP49ttvjS6bkpKCqKgoXL9+/aFuk4ioL3HllohIZO7u7vDy8kJaWhpqamrg6OiImpoa5ObmYuzYsfD19QXw037Zbdu2ob6+HrNmzYK7uzt27twJc3Nz2Nvb4+LFi8jLyzMU4ZaWFlhYWDxwlqVLl+LgwYNYuHAhwsPDYWVlhc8//xzfffcdcnJyAABxcXH48ssvodVqodVqMWrUKBw9ehRHjhzB3Llz8dxzz/XyPURE9OhYbomIRKZQKJCZmYl169bhyJEj0Ol0sLCwgFqtxrJlywz7bX19faHRaHDkyBGcPn0aarUa6enpSE5ORn5+Pjo6OmBtbY3IyEiMGzcOb7zxBk6fPo3g4OAHzjJ06FDodDp8+OGH+Oyzz9DR0QEnJyfk5OQYSvbo0aOxfft2rF27Ftu3b0draytsbW2RmJiI+fPn98l9RET0qBSCIAhShyAiIiIi6g3cc0tEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREssFyS0RERESywXJLRERERLLBcktEREREsvF/oiHeogIsR/YAAAAASUVORK5CYII=", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9gAAAHnCAYAAABDmfUgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABbwklEQVR4nO3dd3RUdcLG8WcmISQhlNCLghST0Ak11BD6IqiIuyABRQFpCqso4CqCdJAmvQgCAkqTIk0By6J0WEDpJYReAyQQSpK57x+8GRkTIBNuMkn4fs7hnJs7d+4885vJkGdusxiGYQgAAAAAADwRq6sDAAAAAACQEVCwAQAAAAAwAQUbAAAAAAATULABAAAAADABBRsAAAAAABNQsAEAAAAAMAEFGwAAAAAAE1CwAQAAAAAwAQUbAAAAAAATULABpGkTJkyQv79/gn+lS5dWtWrV1K5dO61YsSLFHv/XX39V8+bNVbZsWVWrVk1bt25NsceCa929e1ezZs1KkXXXq1dPlStXTtZ9t23bJn9/fw0ZMsTkVEnn7++vl156KcUf59KlS1q6dGmKP46rXL9+XTVr1tQPP/zgMP/MmTP67LPP1LBhQ5UtW1aVK1dWy5YtNWXKFN26dSvBelLr9TBD/Gf4hg0bHrvskCFD5O/vr23bttnntWnTRiNHjkzJiABgKndXBwCApKhfv75Klixp/zk2NlYRERFau3atevfurRMnTui9994z9TFv3Lihnj17Ki4uTq+88oqyZMmi4sWLm/oYSDvatm2rsLAwvfXWW6av+/XXX9e9e/eSdd9ChQrpnXfeUfny5U1OlXTvvPOOcufOnaKPcfXqVTVp0kRBQUFq2bJlij6WqwwbNkyFCxdW48aN7fN27typjh07Ki4uTiEhIWrYsKGio6O1d+9ejRs3TosXL9aCBQuUP39++31S4/UwS9WqVfXOO++oaNGiybp/nz591KZNG73wwgsqXbq0yekAwHwUbADpQoMGDfTKK68kmN+hQwe1aNFCM2bM0L/+9S8VKlTItMc8ceKEbt++rebNm+uzzz4zbb1Im65evZpi627fvn2y7/vMM8/o3XffNS9MMqTG49++fTvRrbUZxfbt27V8+XLNmTPHPs9ms6lv377KnDmzFi1apCJFijjcZ9KkSRo/frwGDRqkSZMm2ee7+v3gjGrVqqlatWrJvn/58uUVHBysfv366bvvvjMxGQCkDHYRB5CuPffcc6pfv77i4uL022+/mbru+C2Ovr6+pq4XwNNn2rRp8vPzU1BQkH3esWPHdPr0aYWEhCQo15LUrVs35cuXTz///LNiYmJSM26a0rZtW+3fv9/0z3gASAkUbADpXr58+STdP77xQWvXrlXr1q0VGBioihUr6o033khwDHX88a0LFizQ+++/r3LlyqlWrVoqXbq0Xn/9dUnS3Llz5e/vr759+9rvt2/fPnXr1k3VqlVT2bJl1bRpU02dOjXBbsD16tVTu3bttHTpUtWoUUOBgYEaPny4zpw5I39/f02ePFk//vijWrRooXLlyqlevXr66quvJEm7du1SmzZtVKFCBdWrV08TJkxQbGysw/ojIiI0YsQI/eMf/1D58uVVvnx5vfDCC5o6darDsvHP87vvvtOSJUvsx5XXqVNHI0aM0O3btxOM64YNG9SuXTtVrlxZ1apVU/v27bVjx44Ey23ZskVvvvmmKlWqpAoVKqhVq1Zat27d4142SX8dn3n48GENHjxYQUFBqlSpktq3b69du3YlWN4wDH3zzTf28apSpYq6dOmiAwcOOCz33Xffyd/fX2vXrlWHDh1UtmxZhYSE6PTp0wnWGf9anD17VlFRUQ6vdbt27VSvXj39+uuvqlevnsqXL6+ePXva77t8+XK1a9dOVapUUZkyZVSrVi316tUrweP8/Rjs+HxbtmzRzJkz1ahRI5UpU0YNGjTQlClTFBcXZ182sWOw43NduHBBvXr1UrVq1VS+fHmFhoY6HL8a79SpU3r//fft78FOnTrp+PHjatiwodq1a/e4lynBMb/xr9vx48c1ZswY1a1bV2XKlNELL7ygb775JsH9V61apdatW6tKlSoKDAxUy5YttWDBAhmGYR+P+vXrS5I2btxof6/G+/nnn9WxY0cFBQWpdOnSCgoKUrdu3XTw4EGHx3F2XCIiIjR06FDVq1dP5cqVU+PGjTV27NgEW9Jv3rypUaNGqUGDBipTpoxq166t/v37J3mvh6NHj+q3335T8+bNHebH/44eO3ZMNpstwf0sFos+//xzTZkyxWF+YsdgX7lyRZ9++qlq166t8uXLq02bNtq9e7fat2+vevXq2ZeLf+9t375d06dPtz/3l19+WZs2bZIkLVmyxP6Z0rx580R/ny9duqRPP/1UwcHBKlOmjIKDg/Xpp5/q0qVLDss97BjsJUuW6MUXX1T58uXVqFEjffvttw8dv6CgIOXJk8f+2QgAaRm7iANI906dOiXpr6ItSV988YUmT56sQoUKqUWLFrJYLFq3bp3efPNNDR8+PMEfp5MmTZK3t7fatm2rY8eOqW7dutq3b5+WLVum8uXLq3bt2vZjwDds2KCePXvKarWqQYMGyp07t7Zu3aqxY8dq06ZN+uqrr+Th4WFf99GjRzVw4EC99NJLiomJUYUKFey3/fjjj5o8ebKaNGmiypUra+XKlRo+fLjOnj2rhQsXqk6dOnrttde0bt06TZw4UdmyZdMbb7whSYqKitK//vUvnT9/XvXq1VODBg0UERGh9evXa+zYsbpx44b69Onj8DznzZunI0eOqFGjRqpdu7bWr1+vWbNm6dKlSxo9erR9uWnTpmnMmDHKlSuXGjdurMyZM2vVqlVq3769pk+frpo1a0qSFi9erH79+ilnzpxq2rSpvL29tXHjRvXs2VPvvfeeunTpkqTX8KOPPtLp06fVvHlz3bp1S+vWrdMbb7yhqVOnqlatWvbl+vTpoxUrVuj5559X69atdfv2bfsXKdOmTVP16tUd1jt48GDlzZtX7dq105kzZ/Tss88meOxs2bLpnXfe0Zw5c3T37l29/fbbDsf7X7t2Tf/+979Vv359+fj42I/DHzFihGbNmqWAgAD7e2zHjh1atWqVdu3apXXr1snT0/ORz/vzzz9XWFiYmjRpopCQEK1evVrjxo3TnTt3HntOgVu3bqlNmzby8vLSyy+/rCtXrmjNmjXq0KGDli1bpueff16SFB4ertatW+v69etq0KCBnnnmGf38889q06aNbDabw7G9zvrwww917tw5NWrUSO7u7lq5cqUGDBggNzc3/etf/5IkrV69Wr169dJzzz2nFi1ayGq1auPGjfrss8907do1de/eXSVLltTrr7+uuXPnqmjRonrhhRfsr8G8efM0aNAgFS5cWM2aNVOmTJn0xx9/aOPGjdq6davWrVunvHnzOj0uly9fVqtWrXT27FlVq1ZNjRs31oEDBzR16lTt3btXX375pdzd3RUVFaU2bdroyJEjql69uho1aqQzZ85o0aJF2rRpk7799luHx0/M6tWrJUm1a9d2mP/8888rT548+uOPP9SuXTuFhoaqVq1aypYtm32ZpOxe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/MqVKw7zt2zZolWrVklSkteVkvLly6eaNWtq8+bN+vXXX+3z7927p88//zzFH9/Dw0OrVq3SF198keBEXfEnzYo/0Vb88eAPvmcfNs6HDh3S3LlzJSVvnDNnzqzGjRvr+PHjWrRokcNtU6dOlXT/ZF+ZM2dW06ZNdezYsQTXYN62bZtGjhyppUuXKnv27I98vOeff16nT59OcOK6Vq1aKVOmTBo3bpz++9//JrjflStXNGXKFHl6euof//hHouvOlCmTmjdvrrCwMIdrkNtsNn3++efJ+gx4lIIFC6patWr6888/tWDBAofbFi9erN27d6tatWoPPfa7adOmypw5s6ZMmeLwubFz585HfiEXf56H+C/2ACCtYhdxABlOUFCQ2rVrp6+//lovvPCCgoOD5eHhoQ0bNuj8+fNq3bp1kq4tmxgfHx8NHTpU7733nlq3bq2GDRsqV65c2rp1q44cOaLKlSurU6dOJj+jxDVv3lyzZs1Sy5Yt1aBBA8XGxuq3335TWFiYcubMqYiICF2/fv2x1+j9u+LFi+udd97R+PHj9dJLLykkJESGYWjNmjW6e/euhg8fLun+iaQ+/PBDDR8+XM2aNVO9evWUPXt2/fe//9Xx48cVEhKiF198MUmPef36dbVo0UINGzbUzZs39cMPP9h3C473yiuv6KefftIPP/ygw4cPq3bt2oqNjdXatWt1/fp19erV64l2Vc+bN69OnjypDz74QLVq1UpwdvYHNW3aVF999ZU+++wz7dixQ3ny5NHhw4f122+/ydfXV1evXk3ylwsp7eOPP1arVq3UtWtXNWjQQPny5dPvv/9uP1nU40409qTef/99de/eXS1atFCTJk2UPXt2/fnnn9q6dauqVq1qv6a6r6+vPDw8tG3bNg0bNkwNGzZUSEiIRo8erWnTpunEiRMqXLiwwsPD9fPPP9uPAU7uOPfu3Vu7du1Sv3799OOPP+r555/XH3/8oR07dqhBgwb2Y8P79Omj//3vfxoxYoQ2btyocuXK6eLFi/rxxx/l7u6uoUOHPnYM69atq127dmnfvn0OJ0gsUqSIRo4cqT59+qhTp04qW7asKlSoIG9vb506dUq//vqrYmJiNHr0aOXKleuh6//3v/+tTZs2acCAAdq4caNKlCihHTt26MSJE/L09DT9NR44cKBCQ0P12Wefaf369fL399eRI0f0+++/K2/evA6/t39XqFAh9enTRwMHDlSLFi3UoEED3bx5U+vWrVOBAgV06tSpRO+3e/duubm5KSgoyNTnAgBmYws2gAzpk08+0ciRI1WgQAGtXLlSy5YtU+7cuTV06FD179//idbdqFEjLViwQDVr1tSmTZvsW8B69+6t2bNnp8ru4ZL03nvv6d1335XVatWCBQu0YcMGFSpUSDNnzlSXLl0kyWGrpTO6d++usWPHqkCBAlqxYoW+//57lStXTvPmzXM4I/Wbb76p6dOnKyAgQD/++KMWLlwod3d39e3bV+PHj0/yWao//vhj1atXT6tXr9amTZsUEhKihQsXOlwKzWKxaPz48fr444/l5eWlxYsXa+3atSpRooQmTZqkt99+O1nPNd6HH36o559/XuvWrdOKFSseuWzJkiU1ffp0lS5dWhs2bNCiRYt05coV9ejRQytWrJDVak322JutWLFi+uabbxQcHKzNmzdr8eLFKly4sObMmSMpaSffehL169fXzJkzVaZMGf3888+aO3euLly4oO7du2v69On28ufh4aFPP/1U2bNn14IFC7R161bly5dPX331lYKCgrR161YtWLBAYWFhateundauXascOXJo06ZNydpNPF++fFq8eLFatWqlw4cPa+7cuTp37py6du2qsWPH2pfLmTOnFi1apLfeeksXL17U119/rZ07d6pevXpatGhRkr6sq1+/viTpt99+S3Bb06ZNtXr1arVr10537tzR8uXLNWvWLO3bt09NmzbVihUr1Lhx40euP2fOnPrmm2/UvHlz/fHHH1qwYIG8vb01d+5cZcmSxfTX+LnnntPSpUv1r3/9S8eOHdO8efN08uRJtWvXTsuXL09whvK/Cw0N1aRJk1SgQAEtW7ZMO3futF92MTH37t3Tjh07VKNGjSc+MR8ApDSLkRYOEgMAPJUmTJigiRMnatKkSQ7XA4c5bDabTp8+rYIFCyY44d/p06fVoEEDvfbaaxowYIBrAj5FOnTooOPHj+unn34yfYvyqVOnlD9//gRf7t27d08VK1ZU9erVNWPGDFMfMzWtWbNG7733nmbPnq3q1au7Og4APBJbsAEAyKAsFotefvllNW/e3OG4den+ce+Skn24BJzTtWtXnT9//qHXeX4S3bp1U82aNR3OxyBJc+bMUUxMTLp/jRcvXqzy5ctTrgGk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sDC1bt1aV69e1YgRIzRkyBCdPn1ar732mq5evZpKowgAQOrjGGwAANIYwzDUrVs3/fOf/5QkVapUSevXr9cvv/yi2rVra9euXfL09NTbb78tDw8PSVKOHDn0xx9/yDAMlShRQj4+PpKkChUqSJL27NmjkiVL6osvvrDfVqNGDf3+++/atm2b3n77bfvj+/n5adiwYfaf9+3bp3Xr1km6X/4nTZqkBg0a2Au1JN2+fVurV69WTEyMJk6cKC8vL82ePdv+WNWrV1eDBg305ZdfcvI1AECGRcEGACANCgwMtE97eHgoZ86cio6OliRVqVJFY8eOVbNmzdS4cWMFBwerVq1aCg4Ofuj6atWqpVq1aikmJkbHjh1TeHi4jhw5ooiICOXIkcNh2fhSHi9//vy6ffu2pPtbp69evaqGDRs6LNOhQwd16NBBkrR161ZVrVpVnp6eio2NlST5+PiocuXK2rx5c7LGAwCA9ICCDQBAGuTp6enws9VqtV/XOjAwUNOnT9fs2bP11Vdfafr06cqdO7e6dOmidu3aJbq++F2+58+fr+joaBUoUEDlypVT5syZEyzr5eX10Me+fv26JClXrlwPzX79+nWtWbNGa9asSXBbzpw5H/6kAQBI5yjYAACkQ7Vr11bt2rV1+/Ztbd26VXPnztXgwYNVvnx5lStXLsHy8YX8s88+U6NGjZQ1a1ZJ0quvvurU42bLlk2SFBER4TD/2rVrOnDggAIDA5U1a1bVqFFDb775ZoL7u7vzpwcAIOPiJGcAAKQzI0aMUMuWLWUYhry8vBQSEmI/rvncuXOS7m91ftCuXbtUokQJtWzZ0l6uL168qCNHjshmsyX5sYsVKyZfX1/9/PPPDvNXrFiht99+WzExMapataqOHTumkiVLqmzZsipbtqzKlCmj2bNna/369U/y1AEASNMo2AAApDNBQUHav3+/+vbtq99//12//PKLBg8erBw5cigoKEjS/S3NYWFh2rJli27cuKFy5crp8OHDmj59urZv367FixcrNDRU9+7dsx9fnRRubm569913tXbtWg0aNEi///675s2bp/Hjxys0NFTZs2dXt27ddOrUKXXu3FkbNmzQpk2b9O6772r16tUKCAhIqWEBAMDl2E8LAIB0Jjg4WKNGjdKsWbP0zjvvyGKxqFKlSpo7d679hGWhoaH6888/1alTJw0bNkydO3fWtWvXNHfuXE2aNEkFChTQSy+9JIvFomnTpikyMtK++/fjhIaGytvbWzNnztTChQuVP39+derUSZ06dZIkBQQEaP78+Ro7dqx69+4twzDk5+enSZMmqX79+ik1LAAAuJzFiD9rCQAAAAAASDZ2EQcAAAAAwAQUbAAAAAAATEDBBgAAAADABBRsAAAAAABMQMEGAAAAAMAEFGwAAAAAAExAwQYAAAAAwAQUbAAAAAAATEDBBgAAAADABBRsAAAAAABMQMEGAAAAAMAEFGwAAAAAAEzwf81XVHhDy0zyAAAAAElFTkSuQmCC", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -445,9 +380,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (dacbench)", + "display_name": "dacbench_migration", "language": "python", - "name": "dacbench" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -459,7 +394,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.12" + "version": "3.10.9" } }, "nbformat": 4, diff --git a/examples/example_utils.py b/examples/example_utils.py index efcf7960d..ce3f06579 100644 --- a/examples/example_utils.py +++ b/examples/example_utils.py @@ -2,13 +2,6 @@ import argparse import numpy as np from collections import defaultdict, namedtuple -import chainer -from chainer import functions as F -from chainer import links as L -from chainer import optimizers -from chainerrl import q_functions, replay_buffer, explorers, policies, links, v_function -from chainerrl.agents import DQN, a3c -from chainerrl.recurrent import RecurrentChainMixin from dacbench.logger import Logger @@ -212,102 +205,4 @@ def zeroOne(stringput): if val < 0 or val > 1.0: raise argparse.ArgumentTypeError("%r is not in [0, 1]", stringput) - return val - - -# Example model class taken from chainerrl examples: -# https://github.com/chainer/chainerrl/blob/master/examples/gym/train_a3c_gym.py - - -class A3CFFSoftmax(chainer.ChainList, a3c.A3CModel): - """An example of A3C feedforward softmax policy.""" - - def __init__(self, ndim_obs, n_actions, hidden_sizes=(200, 200)): - self.pi = policies.SoftmaxPolicy( - model=links.MLP(ndim_obs, n_actions, hidden_sizes) - ) - self.v = links.MLP(ndim_obs, 1, hidden_sizes=hidden_sizes) - super().__init__(self.pi, self.v) - - def pi_and_v(self, state): - return self.pi(state), self.v(state) - - -class A3CLSTMGaussian(chainer.ChainList, a3c.A3CModel, RecurrentChainMixin): - """An example of A3C recurrent Gaussian policy.""" - - def __init__(self, obs_size, action_size, hidden_size=200, lstm_size=128): - self.pi_head = L.Linear(obs_size, hidden_size) - self.v_head = L.Linear(obs_size, hidden_size) - self.pi_lstm = L.LSTM(hidden_size, lstm_size) - self.v_lstm = L.LSTM(hidden_size, lstm_size) - self.pi = policies.FCGaussianPolicy(lstm_size, action_size) - self.v = v_function.FCVFunction(lstm_size) - super().__init__( - self.pi_head, self.v_head, self.pi_lstm, self.v_lstm, self.pi, self.v - ) - - def pi_and_v(self, state): - def forward(head, lstm, tail): - h = F.relu(head(state)) - h = lstm(h) - return tail(h) - - pout = forward(self.pi_head, self.pi_lstm, self.pi) - vout = forward(self.v_head, self.v_lstm, self.v) - - return pout, vout - - -def make_chainer_a3c(obs_size, action_size): - model = A3CLSTMGaussian(obs_size, action_size) - opt = optimizers.Adam(eps=1e-2) - opt.setup(model) - agent = a3c.A3C(model, opt, 10 ** 5, 0.9) - return agent - - -def make_chainer_dqn(obs_size, action_space): - q_func = q_functions.FCStateQFunctionWithDiscreteAction( - obs_size, action_space.n, 50, 1 - ) - explorer = explorers.ConstantEpsilonGreedy(0.1, action_space.sample) - opt = optimizers.Adam(eps=1e-2) - opt.setup(q_func) - rbuf = replay_buffer.ReplayBuffer(10 ** 5) - agent = DQN(q_func, opt, rbuf, explorer=explorer, gamma=0.9) - return agent - - -def flatten(li): - return [value for sublist in li for value in sublist] - - -def train_chainer( - agent, env, num_episodes=10, flatten_state=False, logger: Logger = None -): - for i in range(num_episodes): - state, _ = env.reset() - if flatten_state: - state = np.array(flatten([state[k] for k in state.keys()])) - state = state.astype(np.float32) - terminated, truncated = False, False - r = 0 - reward = 0 - while not (terminated or truncated): - action = agent.act_and_train(state, reward) - next_state, reward, terminated, truncated, _ = env.step(action) - r += reward - if flatten_state: - state = np.array(flatten([next_state[k] for k in next_state.keys()])) - state = state.astype(np.float32) - else: - state = next_state - if logger is not None: - logger.next_step() - agent.stop_episode_and_train(state, reward, done=terminated or truncated) - if logger is not None: - logger.next_episode() - print( - f"Episode {i}/{num_episodes}...........................................Reward: {r}" - ) + return val \ No newline at end of file

Ls^*a~~_hBCMC-T{0bNDwrr;$5i?l}KsH3WTXATysU^52Kn z7reEQqui%xEV#H1RA#hd{$dOMlM9mk7iwRbk*CWcw^^RwGj|Y%HKgN#hU1*m!OtL< zYEU>QEDtWm4B;E@z0Z7*GU4kyHico`vc&E73hs294tF4a0^e|FJex6MB4hV&{WjjF6XDw(QlOy>bC&mO!W zX%_?WThB)F%*hI`Iy>Q()(HHa*9awEN_bP~#jx-+W+G37p-Zj+%w6l4m-j|67AJaO znx+Ez)-6GmpUIQW=aj%R;TxK|J%{(H7w}wZFE;xpf$hXB+>j+t$H%AR%FQaUXV z2yRDMq(}#b4-_2g?tv|dt`M@v8ix#9!cKb~fUEaZ;R~Nz(0imFD(6Vkw2hbXopumA zO7%J(e18Pm#N`=PyD#iLi5IA_c?vpc#(|M#I_#_t6j;o7578fh&gjg-JuOc##_S?a z*DHr9$9c5;X&=+x>P=(SELg7*0*tx$7G>Urps1oAyw5r1!AfBMDAM7D9`$B6)Bp9o=eLnfud!VA(VVbkichsJEPLW2Y8v*un?54@0QK zgCm79uB%aVb||y_h$7Wu#})Z3Jx_P;c@2JF-(z*!c@+O;g(+>*$Oz9doZNQ?7rkhQ zqHh{dd+`*z-rIl{td667dAra=`!?(i3Wv4Fnqbj1GguSw73a3e!Lm8`UqiF%QIJyF#0wkS3Q^npc@h(h*%kg5*{qAcpkG~!8nH>(KCO=3 zPR7vZU#BrL^P|CDPnj+$T?O6e5+KKCIWwSGiuWw|aAx`n7&|W#B43r`#F-;#n8znn zvMz<%V->jVjVk)zh(LbIWZXR_jV{zH#F0OCaH=!iA;?^um?@ax_B2KOg*&R5k zxsCZ2ooJ~pKebSMPcYqE{|RFi-hj&TR6J1~%!b|0Vt3x0#eVk`Bi&a5nC*S-)NWxX zhU`8L&$@2nyGzqbKz8oCR>#OO8(08bp)Bj%;4vCN}J+HTXxjVEX5K z&|9H`=g*2WrDm7e{NFv$_pOZ0ZntGitA;WP^b2z`d^S?E%OI_O0xR9GBYDf>>EEZ| zV5R{|b$i3-J8>XmCkfiY8_?ymDB0z>A73^-ht1bl!G|^Xv2%e0bzW}@=^0O0ckyT( zaXJIaTZhq)jYDbqD`mLsA!ey8NMqwI&V#YG77a6+0KfK&V`*M0JdU5h>{9*$ILE2#+xy;e#Nv-6EK0*5@fPR8(1a=GV2z+h2||?xMP+KeN@O}LQ9@ufZ&wC zze<@JCC`IZ7REVo&u?j5a6v%ub^Q>G@BGX2F^Y;W`6AtU~jy>jv7gm;iy8k zWoXb7W{G+W+P?h&id#z1qf3^Aoc;!%BeIz9lPsCd)5I`hry@ByIb3ilrUG(nJYmts zO1v;_Bh+PzlLH4AW6#I_g4=WMLELs*RNEp+c(0|f<5?-%tmd$Nx^Ny(+zX{45_lG? zaboagTzNVS5-&;673!XlJ?l5#-8Efs;8TZ?YX%$`5yu*CC}0v33ZZR^1oZdDfwaFS zsy%**4UZP1XOAWm@j;FZ)&GG#E3@J9s9{)ku?vn{tpdaP6X269Nha?Wr6Vm0nd>L& zdFGKXAWiBU+;q)B=aOJ{Sx+OJGqM1c6e+3}-Nzg_GK#fr-3R>y&yx_Hm zC48u<#F-M0!P+g5E869XcWa!5zQd`I*eXS9W_vSjhS4}T(uNiq6|<{kw$pu|6=?Q_ z0yt_p1teCifn(W+KxtMmyz0JKc*kCXX6hb?%Nu?%-wlG{YW_D?FH@s%z0E;bx!Dnn zf2+`Oy2ml4NS;64zz-dqmHD^i-=Xh`)sXySGpB2yPlHvrK(cZcL_V!15A6?e=WLW| zh(jefr7DoLDM~D_XAD7bme1H;97b1J?}stt9$>uxa;S{|h93gms7&N$9FTLN z+@L*O86bz2b5`K=HSfXJCx<-wx`YJH7|VC7OQu=!r(wGPDK_s>3*HN7h?j;PSnfK- z$+XLp=$%cNS#b+IXWb>6vZfMDVCaUg&dlsSL$Whw1LbWiXGCr`Qd7f|;4bM?^yJn& zw7!r}Vt5maW-Q1j78@0)?UN^<{^LTCNnv^aHGozKxS&JzyTQ9F}-I z#G~nRAny2O6nuQnuzQt3;)x!)S7U)&oPL8xJc1oH-iVPw>9q9}QUY*;yr9yp}}F<%GZ`1nBF zyeASxCl3&-=~C1psRUydJ%#RO3)auvnw-gIV<40PwU~$uTmU*D@QC|EMO&tc76iLk{_%4VREi6 zJGyumlOiQer^{-x+cG0De104=50vOPvAIlo@OR$YeO~MWu`t|`$Xa@i%|w}$73kwM z$Xr>NjV)M$6WmfEGkYc;yQdCH#hUo*%NI=f)yi6YDaEG}IXImtQN!J?IE)t$cwPWq zsW~k8i_(I+$M9h2VQ}lY4V}Ah!;1P4=;VC?&d-cht>dtzaxs6FgD$8W9;aXL2IG+p zznM!f(io%L#<I?P9wb`wSV)L{UWMrn|u^N88&PjQD@mRWk% zE0fK$a+&B*J2Dt5OP0;PMN9e$ATUpkWHwpRE|VJ=pRd4u*06wmZ{3PESSLWw1TE5~ zHK(XHI*b?&_AxfcFJbQBg(B-WrQCQO6=HGlBrd+02ZM2w&=WN|`57OXR-21ZV}6#X zosgjuEMv*rBX@CwTneEnlfl35G+XdhjxHDaGRBEq;3?HAk)fp-;E^RuBgk7^+Y%?Z z8<7jKLoQ?1o^e?Btd6-D%tNomF0f$s6SQk7#~kfPtkI%yyjSZC?=J+Qb>;>(Uorq^ zFvr+o^HRV%R~@5M<*8gy9_D2PA-#M89Ta9`S6w>$Rlx$xwumw+7mi}}-ie@ToPwj@ zc?o`6#(?JDBd}rMCnh(h0=0bxkA&8UVt@#Bx>^WiPY@<7cVQ$Z?S*IwDcT}XXM!3Y z2qGp$!>D~?pf0%{c9hu**VugAaA+MI)OE_&>WzU^^*nToyvy9jL3aGX!>r;VLrA%? z28-)=LF}U2Sj01d+%0oK*DMF^ugg&f{x&9i-D`{`NsPS+}7_4Ir}a{_^=4(X}mgEJ6WK9lq*!5bqf}__2V!R5jv1ojIufff=QXzu=7PE zJ{o=%*XGI)dG%EoH(P~%PaNdAW_KZdr$85oO{8hV^kLyK3wBHNLg>0?Y*}kD51llB zF=L;;#Ayv@;l`{suzG%pIj7mmF6|wGtfC?=&ANpObv5|4H39eWvOzYN$DEcFr(=gF zfXTtL@WHj7(R+RbcX#Gk{i;6IK7Ivy$7%?D*K;A#OB{zq56ANZk+?5d zp6l4k!Mm!jFm<*M8~#Ox+3`6ZtR%lNdd|6IZoU#f(0&qs#a10+Ywy7BSTdCfNU0%b zp4=yni<&Xrp&o-z-G`;gJ#L<1i})shx6V=6<|T)ql>FKBZo zFZ9F788U@+mXmRv&>k%*^2e(CkBDh%AgV9w1}7^XH|I++<#}uIpT_i}rIj+h_j@Fs zvQy^(^E9CchQ-bH-M^ss4_B46k0eb5M#;(z&g9HKg^@cYsaP>U((7x4wg9<5?> z&85jE^KXoKjw9n`I*ZX+9uBQH9C)?6ui{Yhnz5aWnEO(M$(i1Xy%()uMbBG=qY_kK zB$Jn$q)0^4wQ>J1M`l5X81+ne!Q0C|V%QxL)YNS<>>uNZ9ZC0imyGAKm)46C^CUkI z5uS;JNp-NNyQ*M%zz>|`CPKZM=dwCZDkNreK1z24p_1xLaB|4QgL8hNoq-Ywe6<^L z&jrAkKH)pvUY$$pd&$eJYK4WTTHvk8=={amlgWwZ#b`KXC0XLtNuI<_<$uo}f|i3H?0FgxH0h`-!MJU0v{ zg={t4Z?)#K9;@Q%i+ec!oQI%N`-+(61Q7p;wM6rP7}=egh%evg()HIlnnX^Jcz!xm zaX~QY!36khQ&0Qk8VU7jLjS67r19ca7MEK{Q3hTAV()cc9acWo8uB{vHFqLRqJSHdKdF2Rgp zU%_DBA{c8tNuVOQg%+V5_*%6E#p~+Ox6K!S#^htOTBD#%_f3iVvIHJxaNny{L+9?lcCz1MR3&=QF`@U5*|B{i3No^bc5ppRO-pX;l&MTU2gsSk|LYm`1ZUD#*7-yejTGhS5*Cky|)$!_XbTu`)w#@ z>{tlQMok{it_D&JhSN_L3}|N6!rbd3lqy|-@vp9+=Xy0fGXudV;xSBWS%lB>H0a>X zN|+UX0(#fpz+~+=_^~DdxRKI`Ga_-#Cv948@)#o1vl#pDN7&6JGE{$SFWkHyVK%k}iM#0h3n^MVACg*x|nt+)LZB z*mMM}-)@AxE6SO^womL~?_B(<7tAi-Yr-5CS;Y9n3}9quJBX}ZOGL#LnN1;jMM)=W zKrB?1#x9TMczI_Euk2k3qpg-fZEGqc6a59>_$kp)(XFtuCXs}C)xo;cI=E%i7&c*n zSz*trX!`DVGo-#3Kz-0ry6(0d(G1N%m1S4)OH=`#mmT1z{APLA)#h^9iThE1lsH+x zQl6CE$i#fMoFCZJMb1^uPMtlY##j5)@Y z&ekSX7N1da)kiGxi-pKbZS1Z-Z8|WfhT;8ujN?smL0fz%>sWP)?D;LqKQT~&?kcsQ zA$-sDNVvhcu5+-zKZ8AaD~$6V8^g{XnZ`85-@&}F8Kh#F2pKgh9V}I+6p6P@?A& z1P-Myv361>R4({Q6EaQc!NgM5@=Xp2(0K-3`r<@BIuEyt9U=o}@9~ZMb=Ek&00VyB z!bmxJ7`~(%cDP-I-6^pUFN|3^dTsz^<+|}s;Sy%Z$TU>i_ytTt6JfrYA3itJgU<0i zus5|IEOOw{ z2HP@2iK*vZCbwAzua9#gzC!yz!+jWkM~OZ^@Vzg;<9rFcnD?ipU`iJ1i4wG0%jUke4Fj!{1qOOB-%uoj8c{4pZ~a#XdBMrS>JQzqBn`q z)bBclpXSMt5K~qD;G!(BE7stTZGH{nHN&CW+nw{`t8vOlrttUe4TQAg@}zD}9|pKe zaT(h<+AQD5*me!$Pc^E-(3PD;^VtyM)vLwNGunkm;>W?`Xk{4vpWC)Jyg&UK8^DI})L5-{Xc~?8au%oU66!W_An$b1jUueb$CIHHP!TCAt z3EsM?X$)T=L67I&V)eo<795$Nij4-p8Q!gI#-qKNu{0P(ZB*az0vz9ibATe5lb*IU9>reRT?lw4((FP{d4d|%66EJB_K1MZt1>#h4q zc1ay&OC*MqC|!Lz+AJJx){US}6DrVBa2@kAs-e(;lCwYJFoj&A<*S-8bDtt9kd^bY5_DFh7}UfcLY!p7g*(ydhEnXKpRRC)-uIZ@Cx9P2EfA zd0`~&(HqKt%5?l|+`{WS=KNp8FPi@UiC@gvl?OiGk1{`U&oL=hMzetCKotRlFp3|NASDJ10jT zc}-#rZDpy4pcYmw2*FS3Z-us;4wsnJLZ=nJW8x*N*?WyI^J^@o!&EB`y6)&wP=DTr z>pa64=CA_y@nSN-$E`%wW(k%jT!4VJpXo^Z!;ISm1-9C#l5xMQ$Q}KPSlC-kn+(+` zDpb(L4$0UgeuoV)P{h#I&1B4ypLF-<3^bn(bbqQUCpj3(%y^M%PnzI|-({978pi1V|>*pw6HP>QDqX_ptQ-sLeIR%oU)ztZh8n@Mc z18mxC$WF<-$p*ErXT^?PW?^6_$j`onkFj9X;D+a0B-vDZe^T}97j0??#2W{8F{ZmzxGLuZnDV#+ zk~NmHpO_);&%?FMd@f$fl4{o?ii#(sehHXFTnA_d3Yv&Iz zH-5!x*lZ`s{+Fr421`7&GZMav$#UBVcY%og0oFtAJ|h{XMn%GhlhZHjsUpq86^~rl zuj3TCQ}ZObZ#SP3>0KXSJue)NcpO6YksZRb?Mil1Z6;jG^ky=nM{pGirF3!7JB;{} zQ;@n_m8$FeF`L88A#jHTjJIvWpF3r7N~;KW-6sa36YWTQ_6er<^9*>jS(#f{+|MgH z)6eWPe*k9|8gOBcGT_sgHhQG}6U=iQ(Zs{KH7jBxrZBb zKT|J_6j=3AhJ-e@v)iUdL&er-Y{ANxbejV*D0&x*&wZq8?S^ovY7hA8Iel>L(PK>Q zJj#gZ*bAn#9>p-nNc`pzj!$c~Igd%DG?X_Q(5Qvy*A|P}P9=hC%1KZ$Z5R97v?7ppgYbp2(AL z+Y4#bwtI}ntU6ZjXBs>e8KBcc0zua|i%xFZhIJdh(D&+wcuna0_6U54ojT6MQuaCZ zhWyI9VyPDd=%ah9B0N=$}wr6fkl!OJvTZHQRs~cOdqo$v9Ayo!yn)K% zS#aps240k1vOp@ikKSG(VCTMDz_`kaa2IW4xNR;e{MIw^;IfK?n8gOXDdW%Jds9n+ z_0Sm9lz-22wb$p~H`meAnzH2i=oy%9GZA~d4_VBez7XTqSitr-cCde82Wy+9!sWM* zhL2(^$>w|3`G<#}f{aD)sAl3m*cxXK5f+p1=)EU2=&UW;%=t`pSKWlF@#QqGR2-V@ zQ{mx-Y{=fYl^l6rO1X;(@Y!q@dt$X7XRn+N6Zh1j!xxqnKe-rHw=BZAp<)~xoGhr< z+hcjb<|kF@(&1zlen8M1LPWwj` zJk%5J<1<*h@x!Mb?A$n7cI5>CWe4I9t($DEP7sKZ;)fpPiPl zJNY8&^W?b#bV9nq0w%O}(r8I3E?G;JKUpIT_Un%$*CbBz-oG1wBH{aEN3<8VRY>55 zx;HfPstgxj+YRPT{>(RK_$PGS$0p`MTOV`M-xfWmG|{80heKqTC^znRxG*k9io0AH$ILL@g-sdl=+Nau zZoO-!ZZAa%dq)?>b!%}Q&J#%PnT1G)DJfUo{bt{b?iBhMwYg(qDx8C1FwC(kHZPvu#0ug} znT^gj(0tWlh&qyjFV~slCsu_U^+ue!IBz4;1sXV>yhomA34K{}hi&d{W@GkB(T*v@ zxoz23Fg^bl&A(Fy_e*cnMGMD*?vmqB6cUV8Dr<@9t0H=+y#t!2nKJ2|DA#Pa4ZAN# zL!0U`C?EX+bsch;P%6vmbx^c7JO*WqC?_kX%N>^dK*B}Of!Nqv@XK!s-bp*p`q%>d zd7T6qT=9X086Rj{aSdI*P>Kf0Tj6QPIWUGP-s=a5_JeV@_ZRfvqpM_xd=O|`k^vLol1sEb3Dsn48Qk^j*7AsyxskU3U*$Ar6%|B zrEQBK=IdS(cOr*+Z!N;TW17(B$XIT*qY?dMXC0B$I-e&mBJ!vHZ+4c#-}9Z!=FOJ* z?|i4YL?v#*j!~RW?h@|Gm|)JVU^Msh{%UTu%_=VY=LN3ehAWrrK9<|rww9aWwTjyl zF@sC~sKbr@y!~IfY8LZMUoygct3UPs%t2X1`oB5+I}vi;Z1F!NOyvID$&*WNtAyE% zB7f>KYtcWK|IW$%&vZwXKOg+9{4+!MpXmS0rBnJFk`sQ*f1;;M{U`Q6^U3~>y)4Wb z{u_4MKe7L51OFXcEBOzs@jtQuX$Srt>on;fSd)KZ|8q|K9eZx_Kd`3%#Qvu)|BfxS z{0G+TpVN3q|}X hLfoIUXc2$-^IJsZ&&SKGC8hrSEhGH-)Bmr&{|{WGsr>)| diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/config.yml deleted file mode 100644 index b796a4594..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k15/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/dqn.txt deleted file mode 100644 index 9bd6cdfe1..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -804 -1019 -1192 -984 -1179 -791 -1206 -983 -1122 -1377 -936 -1170 -821 -879 -1160 -1359 -1122 -896 -893 -469 -1412 -797 -1332 -990 -850 -1105 -965 -959 -878 -1079 -1226 -888 -1289 -1280 -939 -1078 -752 -1113 -964 -915 -975 -1334 -917 -1229 -1309 -776 -1618 -899 -694 -1021 -1480 -1061 -553 -593 -757 -1031 -1493 -755 -888 -1286 -792 -1015 -1003 -1002 -1392 -1892 -1092 -1114 -958 -525 -981 -998 -940 -804 -709 -1070 -1002 -1260 -646 -790 -1103 -928 -1566 -797 -1049 -1124 -1467 -1050 -737 -1080 -785 -872 -564 -852 -912 -889 -648 -933 -749 -949 -1724 -999 -1287 -783 -988 -739 -620 -939 -759 -858 -693 -1191 -1124 -654 -982 -721 -808 -845 -927 -1380 -874 -898 -1213 -1240 -1588 -1162 -980 -577 -1169 -1180 -985 -757 -1144 -1334 -856 -1010 -1137 -913 -933 -925 -1050 -654 -1169 -569 -870 -878 -856 -851 -1030 -998 -651 -1192 -742 -1410 -1067 -1044 -797 -1426 -1387 -724 -1216 -1168 -1012 -1370 -1005 -1274 -1027 -1420 -959 -1168 -956 -677 -885 -1179 -1008 -1965 -1334 -1196 -810 -1412 -1008 -1133 -552 -907 -1233 -712 -1287 -1001 -704 -1218 -1069 -1020 -896 -858 -1089 -1119 -967 -1044 -790 -745 -1083 -1341 -1132 -900 -997 -702 -1748 -1281 -870 -1061 -890 -990 -1175 -884 -963 -1326 -1161 -1320 -820 -882 -1286 -1011 -1243 -1418 -1125 -1228 -888 -1304 -911 -1254 -1155 -854 -787 -1201 -854 -1102 -951 -719 -1165 -818 -528 -921 -853 -850 -1327 -1116 -824 -839 -983 -1171 -986 -839 -847 -979 -1149 -810 -1195 -739 -829 -790 -1115 -1757 -897 -676 -1291 -1686 -774 -865 -1515 -714 -1274 -1070 -1273 -913 -1006 -971 -1322 -1795 -759 -848 -581 -657 -1187 -962 -690 -770 -1183 -1270 -753 -1140 -560 -1159 -1199 -987 -916 -1232 -675 -1496 -1203 -783 -1071 -983 -606 -1108 -840 -1230 -1070 -1133 -1027 -863 -1273 -1066 -938 -681 -876 -995 -807 -892 -799 -1628 -1135 -817 -1109 -1097 -798 -1136 -1411 -700 -998 -950 -756 -1135 -1035 -1098 -1234 -731 -847 -1225 -972 -1287 -1131 -754 -1258 -676 -1360 -1312 -1072 -931 -1063 -877 -937 -1263 -860 -1106 -1071 -1287 -526 -1176 -1056 -816 -892 -1228 -841 -809 -903 -869 -823 -822 -1131 -736 -1292 -804 -872 -1004 -1095 -1122 -1214 -919 -856 -1151 -1013 -986 -806 -1086 -1073 -803 -964 -1199 -932 -1014 -876 -1244 -895 -819 -873 -1432 -968 -532 -980 -1355 -834 -916 -1434 -514 -966 -1098 -980 -840 -1180 -1037 -923 -688 -1116 -1150 -946 -733 -1927 -1443 -1055 -1170 -815 -1486 -1528 -854 -922 -822 -1255 -1105 -1096 -788 -987 -809 -939 -1207 -868 -1177 -1049 -1003 -1038 -1073 -914 -947 -1122 -747 -830 -1244 -944 -976 -1287 -1355 -1192 -919 -1245 -926 -662 -878 -579 -1203 -574 -1477 -1467 -576 -1098 -848 -884 -931 -1387 -840 -1163 -907 -896 -1430 -1094 -1630 -1378 -770 -803 -915 -1263 -1343 -912 -1305 -476 -916 -1444 -742 -836 -991 -1123 -1022 -691 -1213 -1025 -1401 -990 -1286 -1147 -749 -877 -942 -827 -1341 -1222 -1421 -559 -885 -912 -803 -1311 -1241 -701 -600 -1115 -621 -1166 -1208 -1140 -997 -1123 -712 -1120 -605 -625 -867 -1091 -870 -1203 -921 -1344 -1004 -662 -854 -718 -619 -807 -1397 -787 -900 -1175 -1050 -597 -1697 -948 -1075 -1191 -725 -455 -1183 -548 -1390 -811 -874 -799 -1567 -697 -1049 -777 -602 -1232 -1416 -860 -1170 -540 -1148 -1385 -827 -1026 -1189 -1189 -1248 -942 -1272 -1073 -1080 -942 -996 -793 -1056 -1160 -573 -649 -947 -1066 -829 -884 -957 -544 -970 -1025 -860 -751 -912 -675 -1281 -780 -775 -1027 -731 -1149 -845 -1089 -790 -1056 -1256 -745 -1061 -1134 -680 -632 -1216 -982 -763 -1468 -1394 -696 -1763 -600 -1020 -795 -1150 -826 -723 -824 -787 -1144 -1437 -1193 -1658 -746 -632 -645 -1238 -1081 -1630 -902 -1297 -924 -1210 -1476 -1036 -952 -1127 -1169 -1333 -742 -751 -913 -1282 -700 -938 -1264 -1267 -1062 -932 -1378 -842 -1330 -1524 -946 -859 -747 -1225 -1050 -945 -946 -1392 -1098 -1299 -878 -678 -1131 -893 -1107 -721 -1020 -1083 -919 -1006 -961 -1076 -971 -1698 -797 -597 -531 -1199 -759 -779 -1469 -984 -1690 -792 -1032 -842 -1014 -1097 -748 -900 -692 -1219 -1178 -876 -610 -838 -1257 -728 -967 -1008 -528 -1156 -986 -717 -831 -1589 -858 -1203 -1298 -831 -917 -1002 -1390 -868 -1170 -1010 -903 -942 -883 -838 -1053 -816 -1303 -1080 -1611 -731 -1134 -643 -1470 -1183 -1046 -1036 -513 -557 -867 -1026 -1319 -852 -993 -930 -820 -705 -1425 -1321 -959 -1105 -1048 -1068 -1001 -629 -1097 -1033 -701 -545 -1018 -1486 -1312 -874 -585 -976 -795 -1081 -576 -910 -1304 -923 -1117 -886 -820 -869 -1112 -1083 -1077 -910 -1017 -890 -1240 -1035 -1110 -1255 -1100 -1050 -759 -942 -914 -610 -1235 -948 -1173 -713 -1343 -1598 -848 -791 -785 -1080 -1125 -1230 -1311 -1129 -715 -994 -1240 -872 -863 -1010 -1030 -815 -1211 -844 -1520 -1038 -1343 -1351 -1011 -1273 -1344 -1272 -954 -923 -748 -1137 -1260 -780 -929 -653 -909 -1113 -1093 -1067 -939 -928 -1057 -1600 -1114 -701 -1132 -842 -893 -984 -1086 -843 -1015 -974 -1009 -1059 -1133 -1001 -810 -1298 -1310 -607 -985 -679 -875 -992 -732 -1062 -1005 -1217 -938 -989 -840 -868 -1084 -950 -1280 -1161 -614 -1172 -803 -550 -980 -941 -972 -858 -1349 -582 -1274 -992 -1457 -956 -677 -1107 -844 -965 -875 -1085 -1215 -1106 -1064 -1139 -931 -1172 -1025 -709 -967 -576 -954 -1389 -1368 -1029 -1030 -1159 -1248 -1016 -876 -818 -895 -557 -987 -1239 -1077 -948 -1173 -1270 -966 -1319 -926 -1293 -1462 -912 -807 -952 -941 -743 -1000 -1003 -1344 -991 -713 -1141 -911 -1316 -803 -897 -848 -594 -1329 -1223 -983 -524 -572 -1024 -553 -839 -1228 -1328 -846 -1148 -727 -1340 -678 -787 -778 -1161 -1150 -1065 -1258 -1093 -920 -873 -640 -899 -980 -1181 -735 -797 -986 -1141 -1017 -745 -963 -508 -880 -1215 -689 -915 -933 -1149 -811 -1007 -1556 -785 -1318 -844 -1113 -811 -817 -925 -1184 -632 -487 -1006 -999 -828 -1302 -1308 -1127 -878 -954 -975 -1224 -730 -1037 -695 -894 -920 -870 -1304 -789 -787 -717 -1499 -1713 -1559 -1152 -1000 -930 -971 -957 -491 -1567 -1009 -993 -1079 -873 -952 -982 -773 -952 -782 -977 -1388 -1202 -1194 -1030 -1057 -1233 -886 -688 -758 -1150 -1417 -988 -454 -964 -837 -1221 -914 -914 -771 -816 -1542 -925 -1008 -841 -1581 -780 -1082 -1212 -590 -1393 -956 -680 -1300 -1064 -1511 -720 -1128 -771 -709 -950 -989 -467 -1197 -1002 -1134 -839 -956 -1409 -1148 -969 -888 -895 -921 -1048 -805 -1162 -1061 -934 -1105 -783 -952 -1038 -1002 -996 -945 -1038 -1056 -782 -764 -664 -982 -1206 -1145 -504 -911 -778 -713 -805 -1227 -1006 -806 -1130 -898 -886 -892 -1077 -964 -806 -805 -768 -1381 -1183 -830 -1048 -573 -1520 -729 -1328 -1068 -663 -1185 -931 -771 -1225 -877 -796 -1106 -999 -914 -1169 -975 -743 -818 -681 -938 -748 -1225 -921 -697 -1101 -1207 -669 -1752 -1028 -773 -1250 -662 -1182 -676 -861 -933 -1550 -1593 -1086 -846 -784 -1311 -419 -896 -1039 -771 -1038 -863 -1384 -1194 -648 -879 -1607 -1221 -952 -699 -1475 -867 -1052 -1196 -1460 -1030 -672 -784 -926 -651 -1165 -1165 -886 -731 -928 -940 -603 -1180 -763 -977 -618 -1084 -540 -863 -1296 -729 -843 -1095 -1375 -1647 -1092 -1105 -1060 -1359 -649 -796 -787 -832 -1018 -1242 -934 -1088 -797 -1405 -1191 -1750 -1068 -819 -1198 -495 -963 -1825 -1000 -1139 -947 -889 -846 -935 -1285 -527 -1229 -703 -750 -1032 -950 -971 -1330 -589 -968 -714 -1097 -867 -843 -1174 -1148 -1169 -1426 -721 -545 -1319 -1189 -1330 -668 -1100 -892 -756 -1180 -656 -1021 -927 -1095 -730 -633 -1022 -1027 -984 -1175 -1252 -1292 -1002 -566 -1459 -839 -926 -836 -868 -696 -1007 -1232 -709 -552 -754 -965 -1053 -866 -1140 -1185 -1185 -1048 -1113 -886 -1357 -1055 -1479 -872 -1547 -1362 -740 -1141 -1335 -1316 -1257 -1112 -714 -964 -1318 -1239 -1431 -1109 -664 -695 -1172 -1237 -1108 -762 -1833 -1673 -870 -793 -824 -959 -830 -852 -1162 -856 -966 -940 -1037 -1085 -980 -866 -1078 -875 -751 -667 -1422 -777 -926 -1000 -1175 -543 -906 -889 -920 -972 -652 -1469 -432 -766 -1337 -983 -973 -1390 -1276 -1181 -494 -1301 -1387 -1069 -697 -838 -1202 -1089 -751 -780 -961 -628 -1125 -898 -1033 -905 -930 -1023 -1444 -1052 -771 -1157 -995 -1119 -1203 -1082 -992 -1087 -850 -1150 -743 -461 -1325 -988 -1126 -1167 -1723 -917 -733 -776 -854 -1185 -813 -770 -619 -1081 -557 -770 -1447 -1622 -992 -714 -697 -1129 -883 -879 -1294 -1470 -891 -854 -559 -810 -978 -927 -1186 -697 -1085 -858 -628 -668 -772 -712 -1256 -935 -916 -1446 -882 -951 -1283 -954 -750 -1127 -1198 -710 -769 -541 -1332 -748 -787 -1100 -1165 -1259 -1216 -824 -1032 -829 -470 -994 -1231 -905 -1592 -820 -994 -700 -1002 -1189 -841 -777 -745 -761 -933 -1525 -1510 -719 -1400 -831 -700 -998 -1023 -917 -585 -577 -1129 -894 -876 -1004 -960 -689 -1167 -1263 -990 -1710 -846 -1466 -1110 -790 -815 -1013 -1510 -856 -867 -857 -783 -705 -967 -978 -763 -916 -877 -737 -1020 -1345 -893 -758 -1204 -1642 -739 -919 -1232 -1330 -1147 -833 -1197 -739 -1347 -670 -1038 -1139 -881 -1111 -1271 -1283 -918 -927 -886 -893 -1274 -1023 -1349 -1148 -440 -1011 -874 -1349 -920 -858 -917 -1401 -1290 -653 -764 -760 -933 -1182 -1144 -1285 -1110 -948 -602 -1080 -889 -687 -1244 -1359 -912 -1297 -989 -1025 -1321 -1293 -1187 -1905 -1100 -964 -565 -1020 -644 -1081 -945 -952 -1124 -914 -605 -916 -1889 -1040 -978 -1081 -1125 -968 -771 -1000 -1024 -1274 -1366 -1172 -860 -1781 -556 -623 -801 -937 -1491 -792 -916 -1019 -1078 -1300 -682 -1326 -473 -1383 -1212 -1137 -1168 -1165 -1122 -852 -1478 -882 -1284 -957 -1134 -893 -1099 -968 -1100 -637 -977 -523 -998 -1082 -1174 -1008 -973 -1168 -1232 -736 -971 -1010 -913 -841 -912 -1169 -1269 -817 -910 -677 -925 -703 -412 -785 -1162 -1110 -785 -813 -1353 -1075 -1149 -870 -1132 -1173 -1456 -1645 -589 -1286 -1099 -1081 -1040 -993 -1027 -1305 -1107 -994 -789 -1096 -1288 -1007 -1354 -933 -1082 -1451 -984 -1161 -937 -1587 -928 -1009 -888 -1054 -1000 -1260 -931 -754 -1025 -916 -824 -936 -1050 -946 -1052 -1264 -703 -1030 -773 -984 -1066 -776 -1072 -658 -1149 -1116 -1325 -998 -1399 -695 -730 -652 -1047 -1071 -926 -709 -1233 -770 -1087 -755 -1071 -1059 -668 -732 -1028 -588 -649 -1422 -1187 -1119 -804 -796 -810 -1158 -941 -1034 -1350 -894 -935 -930 -686 -530 -1211 -577 -1204 -851 -697 -838 -1325 -452 -725 -868 -992 -416 -691 -879 -1455 -953 -1056 -1200 -1182 -917 -1415 -603 -1269 -879 -841 -639 -1488 -967 -744 -1238 -634 -468 -778 -1074 -777 -1001 -804 -1467 -1125 -768 -936 -1119 -817 -921 -1279 -1177 -798 -862 -877 -734 -1054 -1095 -877 -1246 -1143 -952 -988 -1165 -1438 -697 -1200 -859 -797 -1026 -1049 -1068 -853 -828 -1064 -1289 -933 -1120 -1122 -1481 -1052 -1301 -1131 -1296 -652 -1109 -978 -713 -1228 -1215 -1048 -866 -1150 -1248 -991 -1084 -1676 -819 -1401 -1457 -715 -741 -744 -629 -1005 -1133 -824 -752 -747 -778 -1202 -925 -875 -958 -1257 -866 -809 -870 -526 -1009 -758 -1216 -763 -971 -1115 -1246 -1383 -875 -1060 -645 -820 -1045 -751 -965 -910 -495 -693 -1047 -655 -1193 -640 -834 -1017 -995 -977 -1057 -886 -1144 -714 -1257 -1110 -701 -827 -1206 -1354 -891 -1101 -1067 -742 -531 -905 -1316 -997 -934 -943 -762 -1061 -753 -576 -965 -1049 -721 -1231 -534 -943 -602 -1080 -609 -1088 -714 -809 -826 -1092 -921 -985 -1368 -1040 -662 -1464 -951 -1164 -1068 -817 -1236 -1176 -1532 -1368 -603 -932 -870 -706 -907 -1327 -1104 -784 -905 -853 -1500 -1243 -1115 -946 -906 -1328 -858 -1253 -842 -852 -994 -970 -496 -912 -1109 -1047 -707 -1362 -1044 -1577 -1004 -1412 -1001 -1396 -1049 -1737 -1176 -1250 -757 -1016 -903 -1192 -1025 -1355 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/optimal.txt deleted file mode 100644 index 5eeae7e5c..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -666 -590 -1538 -1336 -1481 -799 -885 -1408 -1164 -728 -850 -876 -751 -1091 -798 -946 -796 -671 -1413 -922 -1273 -648 -935 -729 -947 -1061 -716 -550 -604 -459 -827 -730 -825 -937 -534 -814 -1621 -1006 -693 -1105 -1009 -1114 -1144 -612 -1005 -933 -658 -1190 -725 -1041 -1183 -764 -526 -783 -809 -620 -1240 -1033 -1176 -1376 -1246 -814 -1299 -619 -540 -862 -1097 -1260 -1106 -973 -1119 -1224 -969 -670 -895 -861 -1095 -721 -1102 -945 -784 -992 -1801 -1303 -1165 -884 -1169 -852 -717 -1533 -1149 -645 -1105 -1357 -720 -811 -1245 -1033 -1204 -879 -1046 -1108 -1361 -1064 -1161 -841 -1031 -1159 -654 -553 -1058 -861 -657 -757 -940 -1080 -1394 -1274 -890 -1252 -1162 -948 -1165 -1160 -839 -758 -1029 -789 -460 -1020 -1291 -1108 -1001 -941 -1710 -867 -567 -1187 -1228 -913 -1140 -640 -713 -789 -1411 -579 -937 -989 -1165 -1105 -778 -1214 -919 -1402 -1144 -624 -960 -1144 -744 -871 -1181 -892 -739 -1152 -776 -1181 -1008 -797 -1186 -965 -1075 -1050 -1275 -1371 -829 -1091 -865 -587 -1296 -938 -548 -893 -750 -861 -804 -719 -660 -932 -969 -760 -891 -1034 -983 -883 -1271 -991 -897 -832 -780 -920 -788 -1363 -1003 -704 -865 -751 -900 -795 -1194 -941 -997 -843 -947 -951 -1079 -595 -949 -1191 -1025 -933 -729 -864 -1148 -638 -1310 -829 -1121 -687 -619 -813 -976 -1103 -813 -897 -620 -868 -637 -1115 -1000 -695 -641 -1093 -1196 -676 -1065 -1034 -1024 -1278 -1101 -734 -558 -901 -1067 -746 -721 -1217 -927 -1065 -1109 -1423 -786 -878 -1175 -942 -1108 -1407 -840 -968 -714 -1024 -1199 -944 -1012 -570 -1054 -753 -982 -1288 -964 -1028 -1041 -649 -1170 -1314 -777 -711 -938 -983 -1028 -1124 -1063 -1071 -821 -1267 -812 -1133 -1087 -1264 -718 -1229 -1169 -873 -1153 -1093 -1224 -595 -782 -751 -1446 -1159 -1139 -1039 -1289 -1089 -1172 -704 -747 -1271 -1068 -640 -1038 -989 -913 -1040 -697 -1201 -1319 -746 -1160 -1437 -904 -737 -1376 -1133 -950 -753 -1218 -787 -1070 -982 -1355 -1237 -695 -1186 -574 -1241 -828 -760 -1215 -984 -810 -1316 -792 -914 -1348 -939 -554 -627 -937 -874 -1056 -783 -850 -1238 -1176 -1301 -1048 -801 -969 -751 -1140 -1119 -734 -1003 -701 -809 -953 -1165 -1353 -1195 -980 -1223 -890 -1117 -1260 -1592 -831 -1579 -1202 -912 -1148 -835 -975 -1034 -922 -1510 -1141 -1151 -696 -823 -1078 -745 -858 -1221 -946 -809 -1143 -976 -1006 -870 -1112 -1062 -688 -1076 -961 -774 -1005 -636 -1469 -1062 -907 -874 -651 -957 -1060 -959 -935 -905 -912 -846 -1204 -1587 -1186 -846 -939 -643 -1098 -788 -1373 -1297 -1029 -1271 -805 -769 -1156 -1001 -924 -701 -1046 -895 -1082 -1086 -1162 -1383 -1237 -908 -1291 -1285 -1042 -1030 -946 -740 -1107 -779 -800 -865 -976 -1301 -943 -807 -1199 -812 -965 -845 -1396 -751 -897 -1153 -637 -937 -1013 -1115 -1025 -763 -670 -450 -529 -804 -1583 -1756 -1642 -807 -909 -1189 -1351 -894 -962 -1115 -740 -1355 -851 -755 -1102 -835 -732 -622 -782 -842 -1088 -1439 -529 -1132 -1003 -1294 -692 -544 -1028 -1207 -1014 -1028 -1266 -1009 -1027 -1117 -826 -1139 -749 -920 -900 -1464 -1040 -733 -868 -1049 -905 -1478 -1061 -973 -766 -1570 -695 -1190 -955 -1727 -858 -1105 -928 -716 -1315 -650 -655 -717 -801 -1124 -1129 -1176 -1000 -1111 -1043 -917 -857 -891 -689 -1059 -1198 -927 -1168 -1017 -796 -1126 -748 -964 -1186 -738 -618 -667 -1083 -1206 -842 -1037 -1337 -921 -1184 -1036 -1224 -869 -1191 -1048 -920 -1093 -899 -541 -684 -1031 -1094 -871 -995 -929 -1053 -1498 -705 -1028 -892 -1013 -1034 -1096 -789 -1160 -808 -1483 -989 -933 -1172 -1508 -960 -773 -893 -612 -804 -1326 -1335 -814 -1160 -1379 -1373 -969 -800 -1154 -1060 -706 -1320 -1540 -690 -1206 -1223 -1063 -1051 -963 -812 -1531 -1159 -793 -890 -800 -1175 -1191 -1167 -720 -1117 -941 -1381 -875 -1279 -443 -1250 -855 -640 -846 -1312 -838 -1250 -1129 -1338 -835 -1128 -1192 -581 -1022 -617 -1447 -989 -680 -697 -692 -1506 -1245 -488 -1218 -894 -968 -1288 -1116 -1429 -828 -951 -928 -1144 -1060 -970 -1595 -785 -1093 -998 -724 -732 -817 -854 -765 -835 -793 -1433 -990 -887 -1383 -901 -991 -980 -752 -1111 -983 -1164 -1443 -561 -1569 -952 -952 -1187 -746 -468 -488 -872 -796 -522 -1033 -935 -1022 -792 -1257 -879 -1357 -1094 -1180 -773 -533 -860 -1159 -789 -1099 -510 -1079 -965 -733 -968 -899 -1267 -806 -1106 -1124 -1136 -1179 -935 -915 -436 -1115 -498 -1133 -977 -1214 -535 -1207 -854 -771 -831 -1027 -1166 -988 -923 -712 -920 -1243 -990 -864 -1152 -1024 -967 -1182 -1107 -613 -944 -1079 -782 -1350 -901 -978 -1215 -1063 -658 -1195 -1440 -1357 -1094 -841 -1518 -843 -878 -928 -1124 -706 -688 -1197 -891 -1114 -1443 -907 -1032 -549 -605 -596 -828 -1152 -962 -850 -1274 -675 -760 -730 -858 -1298 -799 -1158 -968 -982 -1341 -1042 -1054 -731 -1060 -1201 -1202 -1489 -786 -1125 -855 -1186 -1164 -1138 -1136 -599 -1371 -866 -980 -1089 -1510 -1021 -565 -967 -862 -834 -1766 -714 -1031 -765 -1006 -1202 -802 -1544 -665 -976 -1008 -1031 -1152 -629 -1247 -1180 -657 -862 -942 -1459 -889 -1290 -1116 -674 -703 -879 -873 -1435 -1466 -775 -839 -1142 -1374 -1226 -1269 -961 -910 -606 -1465 -1490 -901 -823 -1095 -985 -1078 -959 -1097 -1172 -1347 -963 -679 -888 -1043 -1075 -848 -857 -1078 -1522 -1289 -784 -1299 -1231 -1149 -981 -1495 -984 -846 -637 -1018 -1605 -1094 -1009 -1326 -1157 -1028 -1185 -1396 -1253 -756 -1065 -771 -684 -1108 -1175 -871 -1105 -1069 -1555 -950 -1583 -1100 -675 -1129 -737 -581 -877 -987 -927 -1203 -1224 -714 -760 -780 -947 -722 -1376 -1085 -1420 -962 -1166 -1085 -1013 -774 -748 -1074 -1371 -1221 -1158 -686 -601 -1258 -1243 -1303 -1083 -909 -1292 -1135 -931 -1061 -516 -771 -1094 -805 -860 -975 -1427 -728 -1018 -1165 -1264 -827 -1088 -989 -949 -1027 -984 -678 -1081 -787 -1074 -1256 -793 -467 -1127 -1410 -1171 -844 -925 -823 -1336 -687 -1167 -1013 -608 -728 -1051 -879 -989 -1087 -841 -1030 -670 -1066 -816 -1000 -750 -699 -1072 -1160 -862 -627 -824 -581 -992 -620 -1209 -1044 -1369 -818 -598 -1122 -894 -1455 -1348 -771 -934 -771 -728 -1555 -982 -945 -666 -820 -1083 -1263 -1039 -1031 -534 -953 -1151 -850 -896 -491 -878 -1478 -1050 -772 -1278 -1098 -1141 -1662 -871 -1285 -1143 -1189 -878 -1348 -1051 -1104 -1424 -1056 -1190 -901 -1227 -1551 -961 -989 -870 -1110 -1190 -1170 -1105 -1183 -944 -740 -1391 -1322 -1045 -1262 -711 -1116 -597 -1045 -1044 -741 -606 -632 -1061 -917 -1335 -847 -418 -1032 -1031 -1033 -862 -641 -975 -756 -998 -519 -1337 -1210 -783 -1010 -870 -921 -1177 -1203 -1078 -1503 -905 -1024 -700 -1272 -1144 -1079 -1110 -1183 -842 -1054 -1057 -815 -989 -801 -939 -750 -1303 -1235 -1201 -1088 -1068 -578 -1036 -1203 -792 -944 -1337 -1141 -1033 -1729 -1986 -765 -614 -1388 -1153 -1402 -1290 -1303 -1001 -989 -1498 -1469 -601 -1051 -1013 -1036 -1256 -827 -1155 -753 -896 -702 -1462 -747 -806 -363 -1351 -1125 -853 -1078 -1049 -648 -809 -1041 -890 -1001 -1165 -479 -1197 -986 -735 -906 -956 -883 -1124 -700 -1116 -827 -1008 -1183 -719 -827 -824 -965 -1310 -969 -1043 -1699 -877 -1241 -1016 -1636 -967 -1158 -954 -892 -765 -780 -948 -1166 -1628 -300 -563 -635 -552 -1164 -1103 -1233 -1309 -1000 -683 -991 -998 -1215 -1535 -1179 -957 -963 -984 -977 -1439 -819 -956 -1419 -743 -1098 -768 -1016 -906 -763 -946 -1178 -1105 -988 -1618 -1235 -877 -842 -1219 -1096 -635 -906 -1060 -809 -1022 -876 -1324 -754 -564 -1216 -782 -1301 -826 -913 -755 -300 -678 -768 -740 -1465 -1013 -1531 -976 -1030 -1285 -725 -1118 -644 -675 -1172 -922 -1120 -1079 -1312 -1044 -921 -1019 -701 -971 -971 -777 -1067 -1371 -1061 -837 -1025 -1475 -807 -1451 -741 -968 -1241 -1103 -1001 -678 -712 -978 -871 -1068 -799 -654 -680 -1399 -982 -806 -1300 -1179 -1069 -700 -980 -773 -673 -1172 -1470 -677 -840 -1227 -971 -1248 -641 -984 -778 -1421 -1314 -518 -863 -1831 -801 -865 -1216 -810 -849 -1306 -911 -1184 -1191 -849 -1147 -774 -844 -1079 -563 -902 -770 -1219 -1067 -728 -969 -579 -1389 -931 -872 -1552 -871 -521 -638 -1127 -1242 -909 -514 -1148 -634 -784 -854 -1091 -1122 -951 -883 -712 -875 -972 -980 -824 -785 -1205 -753 -1034 -1366 -995 -684 -918 -807 -962 -943 -1124 -986 -1285 -1361 -382 -831 -661 -982 -391 -1227 -1011 -1220 -1045 -628 -765 -757 -1074 -992 -850 -1281 -659 -1016 -1103 -993 -695 -854 -783 -1417 -1115 -708 -943 -1097 -1248 -1198 -947 -1081 -957 -1041 -807 -731 -790 -1070 -714 -985 -866 -1211 -1036 -1471 -896 -664 -828 -1065 -1220 -838 -1337 -929 -1080 -1485 -970 -748 -1420 -1230 -701 -1103 -1132 -1109 -778 -1182 -993 -951 -893 -1174 -1010 -1674 -1061 -1070 -898 -900 -1563 -550 -1134 -939 -795 -958 -826 -858 -844 -704 -730 -885 -994 -1226 -991 -767 -1064 -1157 -543 -1255 -949 -724 -1622 -1119 -1249 -1024 -1140 -978 -1292 -760 -1161 -1129 -737 -932 -1427 -630 -920 -1249 -1078 -740 -1365 -1245 -1354 -1014 -1005 -1302 -1784 -1279 -1241 -799 -542 -1138 -657 -1113 -1196 -1234 -1477 -708 -1384 -894 -959 -971 -1092 -985 -1132 -1115 -1245 -874 -1186 -992 -954 -777 -1381 -1082 -1441 -427 -1070 -716 -704 -1159 -703 -604 -1170 -437 -984 -927 -545 -897 -901 -975 -1314 -819 -857 -1351 -906 -652 -786 -1402 -1175 -878 -678 -785 -1143 -939 -765 -965 -778 -911 -762 -1380 -1244 -807 -1000 -556 -590 -874 -1433 -696 -812 -1211 -971 -1157 -1138 -600 -619 -550 -930 -704 -1147 -853 -1246 -1109 -829 -916 -279 -869 -1032 -992 -1322 -1016 -884 -970 -1145 -1270 -1611 -963 -1429 -884 -893 -916 -906 -1193 -379 -561 -1302 -790 -501 -1014 -497 -708 -1189 -670 -1127 -1356 -710 -655 -946 -765 -830 -1187 -1287 -811 -1507 -983 -1039 -767 -693 -864 -1133 -641 -701 -982 -826 -921 -1125 -955 -1218 -1632 -1623 -986 -810 -1342 -797 -693 -1188 -1356 -912 -1386 -741 -1184 -916 -1031 -1145 -540 -1327 -518 -457 -848 -1005 -861 -1043 -1158 -925 -1022 -1186 -693 -1048 -639 -694 -1111 -1266 -824 -1045 -941 -1201 -827 -1258 -1091 -838 -1058 -1238 -860 -1156 -1210 -797 -691 -740 -895 -741 -956 -750 -900 -1300 -828 -623 -1103 -1227 -1130 -985 -770 -958 -809 -1130 -1248 -1019 -832 -1317 -1001 -1071 -921 -571 -1071 -913 -1168 -1268 -807 -1248 -967 -561 -930 -1010 -919 -1159 -1002 -1230 -954 -743 -1160 -1553 -820 -1120 -799 -910 -1623 -951 -915 -858 -1040 -1270 -1176 -852 -1106 -1678 -1068 -664 -974 -808 -1129 -827 -730 -1163 -1246 -1326 -610 -1374 -860 -1187 -1284 -1051 -1153 -763 -735 -1220 -1027 -1129 -1220 -478 -1028 -598 -1340 -798 -1443 -509 -854 -993 -466 -1149 -954 -1259 -820 -396 -1000 -502 -989 -1064 -863 -725 -695 -1002 -1370 -1203 -1246 -1304 -405 -781 -635 -1254 -964 -1399 -1267 -618 -905 -1204 -1435 -1287 -1158 -1132 -804 -1446 -904 -741 -1125 -671 -976 -588 -877 -842 -1180 -887 -1018 -1275 -1237 -1092 -1140 -969 -791 -595 -822 -848 -836 -1016 -971 -903 -1037 -599 -578 -825 -498 -590 -694 -757 -907 -860 -862 -739 -588 -1063 -1666 -892 -926 -1002 -991 -1183 -1218 -989 -1413 -1123 -946 -1373 -596 -629 -657 -1595 -410 -1274 -892 -1326 -647 -800 -975 -1053 -1056 -796 -790 -1030 -1076 -955 -666 -1043 -1212 -1264 -1294 -1070 -1108 -642 -977 -1050 -1131 -1168 -861 -615 -901 -598 -1306 -1478 -1011 -1159 -538 -869 -970 -987 -718 -1365 -854 -860 -945 -1113 -859 -811 -873 -795 -627 -967 -551 -785 -1462 -1113 -1128 -930 -808 -918 -1156 -1354 -1186 -1341 -1143 -741 -1412 -1114 -668 -992 -679 -980 -1253 -969 -806 -695 -1230 -1239 -939 -854 -1054 -1094 -1146 -856 -712 -1105 -500 -756 -1049 -1543 -1514 -890 -645 -1324 -1006 -1412 -944 -548 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/random.txt deleted file mode 100644 index 3da5200f8..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -13769 -12150 -8036 -13715 -17820 -10440 -11808 -6866 -13863 -14858 -10631 -10347 -13062 -8815 -11562 -8868 -7408 -9229 -7754 -11090 -16737 -3714 -12558 -11448 -8860 -9254 -15227 -16953 -8838 -17775 -13220 -9882 -14478 -16385 -8713 -9312 -11640 -14207 -7370 -14674 -10170 -13109 -7318 -12759 -10283 -7158 -12428 -12524 -14032 -8541 -8763 -11739 -11642 -8055 -15428 -12791 -7055 -10017 -11299 -12595 -11870 -13836 -12158 -10514 -11929 -20400 -11551 -11178 -18447 -14769 -5589 -16230 -19622 -9683 -12844 -12224 -5672 -11965 -9292 -11818 -10259 -13345 -11502 -7226 -22720 -10078 -14145 -12130 -12384 -14850 -8548 -6744 -17258 -7837 -12902 -7119 -15681 -11150 -10894 -18362 -9701 -8543 -11520 -11926 -15380 -8873 -9794 -15347 -14665 -7050 -17471 -13347 -10827 -8166 -10068 -11889 -7325 -9255 -9961 -10749 -8785 -16235 -10943 -12362 -13454 -12573 -10853 -14499 -8713 -9863 -17092 -13483 -11687 -11218 -13530 -12105 -11025 -17632 -17144 -9886 -5547 -6162 -12050 -16789 -8292 -10533 -18030 -13082 -13237 -7360 -10761 -14851 -9377 -11948 -8344 -10294 -18305 -10968 -7288 -18016 -12396 -11232 -11263 -7410 -8580 -12884 -11172 -8214 -14020 -16338 -11787 -9944 -17429 -9671 -16769 -14458 -12443 -20398 -8376 -7361 -5765 -9075 -18019 -6992 -21705 -10634 -12105 -14484 -8898 -11159 -9709 -16486 -21475 -8713 -12366 -9729 -15105 -9049 -14653 -12983 -10568 -10925 -7859 -13132 -8460 -19211 -7475 -12833 -10666 -15381 -10011 -9902 -7817 -11614 -9014 -7836 -12380 -11501 -11513 -23191 -19841 -11397 -17590 -12322 -11476 -18343 -16650 -14609 -13621 -13789 -6860 -11710 -19813 -13364 -16989 -14885 -9194 -15228 -10440 -7452 -13562 -19624 -16974 -20781 -6623 -9645 -11812 -9714 -10775 -11864 -8993 -11376 -10168 -9166 -9464 -18130 -16252 -8000 -14953 -7135 -14824 -10437 -7758 -12157 -11839 -5252 -26822 -5533 -6676 -11520 -9174 -14090 -13592 -13823 -8157 -12600 -11573 -8493 -10021 -10618 -12387 -8780 -15456 -10004 -17424 -10567 -14624 -9810 -8558 -13890 -9330 -6719 -15660 -9313 -11375 -10460 -6279 -12026 -10796 -12789 -12610 -9569 -6311 -11551 -15268 -11455 -10683 -9621 -12611 -10844 -18163 -15129 -14358 -13608 -10245 -8314 -14068 -11604 -13253 -4155 -23272 -12514 -16671 -8803 -8577 -7506 -9284 -6979 -7544 -8482 -13299 -10404 -23861 -8069 -14301 -16477 -12760 -10013 -25566 -16156 -12930 -13058 -8377 -12868 -11604 -8900 -11478 -19051 -9563 -14309 -8704 -10080 -11721 -14035 -8766 -14382 -6526 -17283 -10564 -12883 -12514 -14126 -11308 -17748 -12365 -13090 -10250 -9594 -5711 -14889 -12905 -10911 -16939 -10335 -13593 -10791 -15194 -11283 -17105 -22462 -9137 -12767 -12116 -18461 -7111 -9958 -13184 -5536 -5779 -13529 -5797 -10681 -13702 -9111 -12255 -15087 -17449 -8544 -20026 -8685 -13214 -15697 -14082 -10507 -13743 -13126 -8185 -11372 -23235 -10005 -11420 -12247 -9810 -6413 -10848 -10718 -16472 -9874 -8626 -14347 -11459 -14347 -22707 -9782 -13132 -8149 -13036 -11479 -11897 -10808 -10891 -12055 -14819 -11255 -9297 -13160 -8772 -10743 -8783 -10063 -4082 -12445 -12351 -10585 -6726 -5295 -22039 -8152 -10440 -8270 -12632 -9059 -10502 -14503 -12721 -15798 -11130 -9187 -10126 -14558 -17936 -17832 -15968 -6761 -19236 -9723 -5925 -12759 -9142 -11563 -14766 -13978 -18131 -13764 -12914 -10277 -8361 -11247 -15318 -15881 -11673 -15455 -8506 -13411 -7522 -8985 -19411 -12062 -18757 -13868 -12243 -11024 -9806 -16201 -7049 -10085 -9962 -17357 -16027 -8346 -13934 -7120 -12675 -13283 -5432 -9481 -11734 -8390 -10777 -12772 -9635 -13035 -10663 -8166 -10471 -16846 -9603 -13642 -10447 -9947 -16941 -14267 -6722 -4985 -8292 -12485 -10920 -11394 -15234 -4309 -3540 -10612 -11729 -7530 -12005 -15337 -15894 -17694 -12271 -14592 -12764 -16369 -10257 -15966 -11625 -10784 -11731 -9099 -12342 -13396 -16660 -14850 -14729 -13977 -16132 -19316 -10832 -7832 -16434 -20252 -12738 -3100 -9047 -14165 -9633 -11521 -13190 -12409 -5778 -18598 -12754 -16489 -17274 -11073 -16668 -11121 -13182 -9600 -11745 -18040 -10714 -11729 -10531 -14510 -14441 -12195 -14600 -8102 -19657 -15677 -12799 -13133 -10153 -23211 -15293 -19784 -12665 -6081 -17588 -12732 -16269 -12533 -13483 -12361 -17003 -10934 -17966 -11566 -13730 -15261 -13345 -6834 -8450 -9062 -10393 -10295 -8658 -10187 -9978 -21174 -9347 -10934 -12274 -12794 -10929 -9125 -23674 -9427 -9930 -8433 -8324 -12694 -10671 -16682 -9822 -15383 -11247 -15382 -16211 -11906 -22168 -15299 -17409 -6706 -14508 -10960 -11889 -11821 -13272 -15925 -8100 -10127 -15636 -11981 -20254 -5096 -12067 -13899 -16882 -10267 -17226 -9201 -7042 -9873 -12775 -14703 -9438 -9887 -14533 -11606 -11880 -8702 -14805 -12067 -9257 -14451 -10786 -6173 -11467 -17725 -8298 -9324 -14077 -8234 -13711 -10845 -14063 -10815 -9383 -16716 -9328 -17658 -11317 -15771 -11643 -10856 -9080 -11838 -11007 -10566 -9977 -7479 -18715 -18298 -13587 -16596 -8044 -12406 -9991 -20249 -16857 -11295 -13175 -11707 -11598 -10104 -16883 -10089 -13201 -13654 -11815 -6951 -6801 -16247 -13732 -14862 -14045 -12400 -8571 -22005 -11658 -13070 -9564 -14673 -7251 -12784 -13853 -14962 -8481 -19605 -6009 -12714 -7973 -13971 -14817 -11845 -8699 -6496 -6386 -18390 -10771 -12290 -13746 -14611 -6528 -16157 -7652 -12388 -9387 -11745 -13102 -12807 -13963 -9239 -10999 -7014 -8694 -15149 -9267 -10435 -15901 -14045 -13808 -5753 -17436 -9440 -5451 -15665 -12041 -16477 -13560 -8081 -10400 -8613 -17304 -9410 -13768 -6168 -12435 -10833 -12434 -11096 -9607 -11100 -10989 -10765 -12154 -11554 -14962 -16703 -8270 -15700 -11773 -19051 -15583 -12748 -6777 -11781 -17819 -17287 -10267 -9782 -19528 -9619 -16929 -12414 -7573 -7199 -18244 -14627 -12833 -17738 -10234 -9045 -20696 -8910 -10721 -14585 -9139 -11942 -14131 -14357 -14030 -7057 -10413 -15173 -13844 -17301 -5961 -17906 -11604 -10695 -12133 -10900 -9242 -10047 -12898 -17188 -7697 -7186 -6640 -7569 -16028 -13626 -6526 -14930 -11865 -15438 -8923 -16082 -11083 -10762 -16375 -6348 -6379 -9690 -10625 -19987 -13894 -13996 -9442 -21267 -12715 -13768 -12010 -14760 -16093 -14372 -9615 -25563 -17978 -18803 -16277 -8516 -15828 -6985 -8827 -8439 -9634 -18332 -12172 -11433 -16676 -9265 -11736 -15020 -8974 -12741 -14128 -6942 -12340 -18844 -12931 -9687 -13978 -12139 -9120 -14312 -5161 -22144 -4624 -7089 -11664 -12831 -13089 -6265 -7354 -10685 -12511 -14762 -8176 -14092 -12085 -14862 -9576 -6863 -13501 -9474 -18439 -11540 -14303 -9927 -9187 -11742 -12646 -12193 -17166 -12225 -11972 -12213 -11055 -11958 -6318 -16510 -10817 -6024 -14452 -11868 -10056 -13935 -13590 -12969 -14854 -11421 -11746 -10931 -16438 -15560 -14172 -12899 -15455 -13341 -11469 -8871 -14392 -9981 -12741 -7750 -14767 -10356 -10086 -10756 -28039 -6786 -15424 -14945 -7054 -8756 -10430 -18265 -11894 -18268 -8773 -9835 -8932 -12346 -21859 -10451 -10404 -9937 -9887 -13801 -12521 -20902 -10606 -7447 -13634 -11759 -10018 -12133 -9916 -15589 -10549 -18479 -9938 -11975 -17616 -14889 -8579 -16370 -11644 -12127 -15377 -11772 -12665 -13439 -11649 -14820 -8019 -12279 -8457 -13605 -8693 -11925 -15383 -11460 -14623 -6380 -4438 -13798 -15029 -8162 -14549 -11256 -15581 -12666 -6969 -10121 -9031 -10575 -9015 -15651 -11090 -16103 -12706 -8855 -11625 -15811 -15619 -19562 -5087 -16440 -11745 -13292 -11604 -10887 -10379 -13057 -12579 -12641 -7404 -16176 -23496 -8059 -11395 -14276 -11558 -17071 -10403 -12280 -8821 -14398 -11034 -9358 -11089 -10087 -12228 -11027 -11329 -9271 -13105 -8793 -14081 -8506 -11005 -11304 -10481 -9853 -10966 -9623 -16992 -14118 -12867 -5435 -12679 -16328 -11673 -7351 -7911 -12757 -12384 -7768 -11664 -22749 -11950 -10469 -7071 -4799 -13249 -16454 -11346 -9606 -10941 -12064 -10599 -15089 -7206 -10730 -8475 -12207 -15052 -13275 -7533 -10607 -14266 -13240 -11091 -10811 -6269 -11252 -7655 -11639 -8622 -11145 -13136 -22139 -14907 -9726 -19599 -14619 -15106 -21445 -7968 -8711 -16870 -9220 -12100 -5473 -11074 -15132 -13478 -12197 -12510 -10922 -14923 -10929 -18505 -20265 -9197 -4371 -12011 -15073 -17140 -15245 -10970 -14566 -10763 -9787 -15289 -12093 -8339 -11648 -6740 -13209 -13764 -12580 -9079 -16649 -14488 -7530 -11060 -13185 -13824 -12837 -12944 -12820 -14336 -7913 -11061 -17416 -10921 -16445 -9815 -11201 -12224 -6680 -10091 -11645 -6959 -4194 -9172 -14747 -14418 -11227 -9134 -11470 -15810 -15857 -10848 -14755 -12824 -10409 -9627 -5562 -13049 -15532 -11443 -7184 -11717 -12689 -10512 -10908 -20728 -15096 -11885 -15677 -11616 -16630 -14403 -9918 -5510 -7813 -5512 -8966 -13763 -13939 -11290 -20789 -7411 -8977 -13405 -14271 -13566 -5975 -13720 -6764 -7210 -8183 -14878 -14334 -13479 -10722 -14497 -15343 -8979 -11638 -9462 -11848 -10164 -11870 -13634 -13174 -13793 -19811 -8393 -12848 -20582 -15644 -11474 -5640 -13791 -9650 -10353 -5437 -10072 -14838 -16739 -11266 -14119 -9973 -13886 -10809 -10740 -13047 -13528 -14937 -11662 -11831 -14398 -17518 -10245 -11315 -7914 -7895 -18124 -10053 -12839 -13110 -12091 -12621 -10878 -10879 -10190 -8245 -19088 -7672 -22044 -10536 -11943 -17029 -13549 -10013 -10847 -10668 -7786 -15069 -19629 -3958 -11634 -10145 -15256 -8862 -14055 -10358 -10572 -14443 -10055 -6825 -14195 -13573 -6903 -16058 -9170 -13633 -16279 -10597 -14626 -15752 -12540 -14454 -13045 -15612 -16681 -14236 -11571 -13773 -15975 -8423 -13690 -9074 -10697 -13694 -10202 -14248 -10221 -15584 -8473 -10608 -11459 -9341 -6899 -9308 -13163 -16030 -12444 -12256 -11115 -17287 -14255 -18875 -10224 -9529 -20462 -21249 -8732 -10804 -18349 -8118 -9918 -5224 -9712 -16701 -11283 -7759 -16260 -8399 -11921 -12650 -9759 -13971 -9646 -14488 -11484 -15915 -18095 -5505 -5293 -15074 -11308 -12526 -13863 -15134 -10380 -7561 -14587 -14093 -13702 -11127 -13501 -13114 -10652 -18643 -14208 -16015 -12846 -12642 -13137 -8808 -10667 -14624 -7350 -15241 -9612 -15200 -17568 -9737 -10929 -15638 -9354 -14935 -9020 -14166 -13262 -10966 -16840 -11827 -10420 -15613 -9395 -5670 -15681 -16204 -10329 -11176 -17846 -19216 -14346 -10874 -7401 -4938 -10466 -10180 -12708 -10738 -9423 -12464 -14226 -9340 -7115 -12844 -15846 -8099 -10547 -9346 -10617 -10550 -14760 -10398 -14723 -10214 -13058 -10794 -10705 -6571 -18463 -20681 -13083 -16871 -7139 -6960 -6346 -18317 -12123 -14170 -12579 -8826 -8299 -12652 -14186 -12243 -7168 -18037 -14091 -7959 -11019 -15594 -10933 -7475 -16187 -12332 -4328 -11712 -12233 -7605 -9237 -11559 -12425 -15005 -17302 -8862 -7208 -19397 -19624 -12588 -18137 -12349 -20998 -4949 -8668 -10304 -8368 -8631 -6461 -8042 -20061 -16212 -8692 -13096 -11382 -17068 -11655 -13245 -8714 -13931 -10957 -8497 -14357 -7014 -9592 -11960 -13012 -12216 -13146 -7098 -9848 -6992 -11921 -10975 -6153 -10290 -11253 -5894 -7826 -12355 -9191 -8707 -18080 -8535 -8887 -8258 -19434 -12923 -13395 -14762 -14018 -17418 -5682 -14221 -14335 -13586 -10233 -9753 -7509 -15069 -10378 -14917 -13038 -10936 -15369 -13025 -5366 -14321 -15767 -10275 -11497 -18802 -10098 -17739 -10146 -13385 -9519 -13018 -12613 -10759 -13636 -22027 -7287 -14609 -10573 -13029 -16280 -8213 -10065 -14777 -11344 -11005 -13801 -9120 -10652 -18613 -7110 -10163 -10697 -11761 -11366 -11636 -11865 -9681 -16440 -16914 -14266 -9515 -9813 -6865 -10122 -17559 -13923 -9763 -15271 -14075 -10135 -10402 -11704 -13030 -8750 -15034 -8258 -14790 -8973 -21271 -12073 -14484 -11181 -8424 -12942 -6050 -11741 -15927 -14470 -12355 -10717 -14352 -9633 -7288 -17000 -13335 -17689 -12806 -10513 -19695 -9288 -13346 -6918 -6981 -11394 -10315 -13644 -10180 -9997 -13328 -15814 -18859 -15022 -7233 -19088 -10436 -10619 -8013 -9119 -10859 -7335 -9738 -7366 -6648 -13380 -10415 -13132 -18656 -14794 -17568 -12263 -12786 -18232 -9453 -13420 -10179 -14363 -16777 -10472 -16149 -15300 -24681 -6243 -14595 -8667 -9520 -15911 -22818 -9544 -8589 -9230 -11127 -9885 -12519 -10040 -9848 -13268 -14869 -11908 -14754 -11954 -12842 -15298 -11232 -8657 -8046 -8095 -10274 -18108 -8748 -11326 -11669 -12840 -11549 -17668 -9598 -21077 -15332 -14174 -11593 -17315 -18821 -14845 -9334 -15649 -10995 -10242 -11035 -19159 -18168 -11190 -11779 -8056 -7750 -8754 -13801 -11131 -15508 -11835 -10252 -15274 -14509 -13054 -9872 -11744 -11709 -11075 -11341 -12920 -12828 -18041 -14266 -13033 -11426 -8325 -13094 -9752 -17773 -12104 -20134 -10942 -6265 -14122 -17718 -11431 -17288 -12665 -4277 -10529 -21244 -10526 -12204 -9644 -6562 -11607 -10771 -11097 -18255 -6133 -12336 -6131 -19327 -13528 -15754 -10568 -8056 -11504 -12897 -15508 -17206 -18509 -14025 -14246 -9505 -11783 -13929 -13069 -10079 -8467 -14153 -13113 -9301 -13157 -8198 -10033 -14355 -6310 -13170 -8616 -9995 -14292 -15214 -6124 -17351 -9978 -10436 -27602 -13113 -14030 -5765 -8721 -13607 -12755 -13428 -7873 -11282 -13757 -13064 -6807 -18786 -10435 -11513 -14093 -14102 -15975 -9813 -9596 -10362 -16778 -18826 -7910 -14105 -7987 -12197 -10516 -11370 -9591 -11836 -3997 -7709 -15310 -14488 -12361 -7626 -15515 -13240 -9088 -8312 -16866 -11577 -12128 -11254 -16336 -13183 -20457 -9949 -20814 -9397 -11763 -9982 -13345 -11752 -9269 -12250 -11282 -14706 -13247 -2378 -11416 -14497 -10297 -7033 -18657 -10369 -9881 -12092 -11096 -9800 -15654 -11762 -20040 -12745 -13179 -12489 -15278 -9576 -14313 -15015 -8078 -9012 -11075 -6279 -10546 -13145 -14262 -12355 -20222 -7713 -13432 -17899 -12755 -8190 -10516 -16038 -8861 -13801 -10488 -8546 -17196 -7487 -15028 -11066 -16584 -16086 -5488 -9641 -13481 -10749 -13032 -12507 -20612 -13050 -6216 -9038 -12016 -3586 -13597 -14017 -11240 -9439 -12750 -13418 -13144 -12948 -8657 -12273 -13279 -11612 -19133 -9632 -9056 -15380 -12414 -10713 -16677 -15926 -16660 -12218 -17944 -12156 -12201 -16521 -12627 -9596 -12309 -19904 -8003 -10760 -15988 -9254 -15020 -14295 -7450 -14047 -13203 -11298 -16634 -13815 -9905 -5002 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/best.pt deleted file mode 100644 index 3d6341661cb2cb7290f904288eff9c072c79008b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16919 zcmbun2|QKp_cv^wXBktZc@mm%_PUN#8WhbTO+=IiQ?o*)5Xw-<7zrtoAgUot!wYS*1Fa@OKij?L_}m{ zME+Y-5m6J_=;_I%Co_{X9H3 zt@m}^?z6*t{Vr2EFY$5X?4^Y$AK{T3H@kXC`~{J-_S~`2cllpC<-8>AMTN&0dr8@g z3%4#i{k)`YHu-wVEVU7_F|`p3_L8*`vk?vUk_&PF!$jWKOJSLpqWzy!{X@suW229k zlDqJ`+$G%ql4ath>@IC%>g%QQFBwO@RBc3$da3<|SNHWAvdl~4-=|~xU#Fw_HwmU* zTJF+|D`kDXwEv=E8tkPbWFw@Z`FZ@(ruW8G?ru+GO&9Ijhj_CSruD%=p zOcSq}{~B$xarVN!B3|bHUKan-#n_^>#i>1XS6p`k2$I6?c0Qf zPq)%s_i0@HnW)3cj7C_i*j3@F6P_ojpF7A7Vzf`XKAr=0NpLg zQqPAQh{&5508dZ8Wi^lcs#Qf2zCEGp$8t$0Gl5DuYV&j74dI4~d9V?7!8B<+3Vhxj zqz20rxY_1Qsk2cKDm+!<7SFWi94DUOFRM-4%!;x`j2mL&T z_62P`5>Ffw@6i_$&&aP|Y4oSAF6W`IPD)pl&_CmLO=;oj+ro?PPye6BjrseynOa+! z{eK>}{~F2tE#GlkaW1TAjAl|!M=&G$DZ48)4cCfXVp}q)8lAoF0hTYOU-dwcQvY z+t28DC8MXWH!pnAGU!**6L79CaH)bRyMTVh?&!T}yZ8=D@O4Kbmnq#lpQ+ z0B7c_bFq`txaTWXskP2LPW7l48|<8g%VbxQ@N!-9(&+?|k2Hl9gIYMuFAkEt_#CYm z&EpDHu-w@cdkd$+;u(2(cKB~(3(n)>Y1&kkyaG)Nb$V{D0^!F?)2H%!IP**vyec3( zmq(`|W=&y~TUJa~U6r6;NFA02=NcDO;1POXK-p z8IuXwg547Wz)b8A1hy1FO6L{$xHSnD_}#dnc6TJ7~e`GdtN1Cn5+ zx9~6}Qt}`;AAt^AUSj&NP*k!tW80^7!o6Ybxc`e7+)a4P%>BKPxuRGCIm_fomUBFO zC<=jd$+EOhMvlqo*T-PJG^k%9M!R*!<9F3W7SnzJne-LC181-jUN6!0cMV?huE4Tg zFL?^}iWsw_+hV-&4m4dQK`Qn(Vf#I4MtW8|Hm&~(rDBtqMg6+W?pq0{F>oG!P27P+ zqrc+9t1iI58HYwQpW)KIdKSmrdLdy%6>NPp4Gv6s1flPL;kf;L{O$1&r;Ly%BRf~J za-JM)SzZLDGGUlj`2^%_C;?<)7Zph-`jZ0IGHRiW(d;u#o{y_UUmCyJ(-*TKL6YrN8N z3v}(<$dXlUyyfqd=+(y#sG{}}12S)0sBBQ6xL{ zK@q5YHH^1HX*63@(1blt4xnw9A>C&+$jr`@p;k$Ipmr!9i{K4b_kM(p(-t$&F7)6k zTLm~$`T^B^RG1yU8{ylii7;80vq)2@V0>clHYjD(CXD_SYCr)C03$p;7r()BTuiR z5p+zv3NG)I$?vIQfTeO|xb{!nrI3k1&rKjL^9j%U({tSEua57%Z5askg+s^h3A7^j z!FG*qsIZYD&g)))-#!kl^-7_t(7w#RITd|%-Ix_A3Z&KYIZj&q9dD&PWmey>#1SR& zz&&e#pNC_9XX5-K5t{el zJ32W$V9%=+v%Ti6jOSn`q;EXPj-1WnoJ(rZsCofrWoy$@4-_c#brQDONz>n3oEg!{ zL5$i!4{o|IMm6_~&|i;7!XsN5_+|AP7MHd%l|N2Hy@xV6@koMZ^iDvQq~A`0$-N&eUU?M2;h8La^PEnS z!YVOmUj;e_%Ftb_L%9&h<|;qVh9gl{Tvwn7@qYUQf>Pbcm1{~w%XbFU>wja+_Da(a z{5^OsrGvU9yDKwJ4jqA1YCnj@wtnW?pHAd!oD9Z>GiI9_)vs#_ooN`3x56+(E0-E*um8 zf%Poe&R$k+0*RpGxcb)+obCRAX}J=H8~0pC(^KWl2uoWg%6|YWQmuH#4llCa9tf!A@a0Zz!A2B|&DtR^oW;zJ5BQmGBK`%*!n`x%DBeq&n# zZo!Lv<*>Ic3SFPu;RUffY+L3heDwSlCiF|u`Q{1is~^gA>Vs;y_o4=iTz=u6dAaad zxe0YGI$_f)Meh2SHyY zX8B2?&fpG|t=+`ANclm@@WAxxUh>oIgn)S~VAPWDbF*@SFnebZdAsKo zDcl!KB736BNLd#gdYVM^nhujvW)!)da*rge<&`p@ui%p6-Ebg7gy`oLmg`)MhMCnJ z%#4i}NZiH<1U=<~g4AGO#0VN@8N)cW)-Yi) z?}(ZGQSwva2$_9+0c6W<$25m1oQ5m7IBg|*^R5eS7fD8C2OyHG?dWIEG|cshB*|^A z;F6aIB^S?;gJW!Y5Pyj|mf*vU^sK{;RFkYqOeN*MjwE!E2YhhRr5PnlNaXQYbnFjA zx4ID|OiY5Ezdw%VdLb@!d=2xfq%F4$X5bG`DR3Fs58KBXlC*V7v}68c($K}H%YA<` zSw6X-t0BXQeM{t~Szf^d8&^}4(7E_BhJ~a|Lozhqi9B+jMIt&c;L0hf5b<^nliT={ zwjQg;ZY?dkB!37D_dZL=NkcG;xC4DFsxV5-0cTx5jWdlips3Ooh7RjszE64&5nWxl zvX+HOr)Q#Z@q1iVd>&1fl%b)oA!_te^yzeh39%nQWA_2vBr}N4C4&qd!$AyV3~Om0 zWOjzZk1tWMA}gE~1kQqqFA6|AB^tMfx5I}q!uh8^h>3@eW0_yFKy2_i+`Zfgua+s2 zGpCEoHk^~7BfCQ2b>bLy)T?Q{Gh5#Xwr!1M*ZD}2&pYFxwEaC}a&#_ac3a};iu%OViCS32uqc(VPV+~Jm9E+U$zaPa_2UTTA0DkcRGb}p7OLM zv5GYieS_B|H^E-x_aHE6$8YEEGAqjFB30;s{+>n*GB06A8&-h#-4I+@u0TRU#i_NH z8GK!S51luC5V*KT;%mKPrej_UTq>5LE3#&S4P7Aa|UV(u=yNDONe1h;P(;-vH|%+5te=8b7E!@=H$_iX&G14-Ac=v%T&W=|g<9CGN@h6vY z{6TeL|W>b=D=;wh|4Ml3v$^Co`7oA@x`mA31jao|hH}MF*rQa1PHn#g zpH3}DgXlJk)Kf{YuZ%`>%RtRHYoPYBgj_uEydr zCW>9O%bl+DyUOU4DiN=R*4H2PjJ4ps3T0mlH0h$t#&q47W$;2&1jY3p;P2X2-2Ypg z=J%}QmfhOJF=Q%TF++kg->=0EPF)L={f1-Vmr{^R41|kmw?K1F9tIe;!>Be>h*mg` z_3gJYS682!4R^v7Ln5L5<{dP6n82JJFSMs+?m+X85F9#kEY8Vf@ViPN%r+Z^{oNh# zrR7FhZow)rNw0u4T0#r|U^u$ESHP*;`RG#H4(qgzqS(@CNHht?(gO(?GQS9HZj8jK zTWcU{Z#mw(Rt(OTU*T5HPdxbk1-xrkN1gjwa3eDu!UIcq0>w*kwB-VtS}Kr7wMD4r zTEWviSO+TGBeCYC1U)gKfSuf5%ii{C1e4VTaN&|N7+Nf6emNK5o&6UeddzNi;E1Hf z!?E-6_EAal$=(46st>c3(-cVc?0C$R?L*PLtyptAip}qKgYfuj*n99S*lue8rP*DK z!09yD`%eZ({cCvlp%v6#9m1+jQ=*6Ld*H6R1WK=82y@PHX!JXj@v6~7as8v1qUMG- zQ!l|@g{R;*QIYIgCrL(4aD*Mt&f}c(^FguJ0xmSpT@{O!kv$Oi__Q0%-G5A;PLN=V6Aip ze=PWjjyaz}I-0}N+M%r9!36kvvQkHPt7BTjM^Csyq*G0T4lUOsIMAL`D*=(-WO?REn` zSX>FmtWLpC^@Dh-`n~zKjg=5tAjO1mbA->!KAbO*C6gX@VbHhPY~U^q)`&9Dd}?Z` zYr|M< z>1j25wdXo4IJFBKh1bl1l^58IjTI2~!wo)v>O{k7g;*BpgbT1~~E zK4~lV>=Wg-`3FJcUW9{czR zZI)ZZm&#ud6QEe``m_rYxG)Gk;zmz4OVA|;8cH45D0X16Kbx+3hMmyg02X3h)PHs* zbr)MrtzrmuY-z;#BZa=Ro*fJ(ijnRZ9?s^U!-8w~Eh4y^xHa+}vz4iW5H^wqOss;w zO)mw`GWA$$+lTuy6JU=1Lwt~T2uCcd5;QFy%G5mmi2nOB(DSSn&SNLTEABLSHJ8A} z_0eej@G=@#nBj3Hak_X*6Q+1P!w=OjVRZRYnD44W%)?Hw12 z>jdv_3!}<6X`^UTZycDz9e0` z%@wK}D%su}1ITBu!m3+E_;uhS`cG;DF^5!q_Noq6-fhAmXS!gv=rWu*=PE8u41z7i zMvTLn9Z<0Q38vZ&gSbLPIQQ`sTuFTc-G{$pb3qV15^{;JlcsNVUgEbDBe>>m3u#TW zpe0U$#;=!xVDGuGWByHsSN$1urbMCXm_&AJN$rpn_4&`xXIgeSDEC`Y{7x%lQ6i~6GEl)L2cD#CbL_aE-{QVn-DIJ z-ts3|*Ex&vroAX#u5cY*@4kXP)!*>RtW>t+xe8u2l_tkZg9JC2kvQpex$xS1f(UWQAih00ZuK0l zInt#s8LM>Rb+ucDp7Q>Ldvh4L^kEV%2yOu+yvHBU*Zt|&%VXl29c35^(6n$3H=_%Jsh+QdBAFIjri zi=anUCk~H#g;st-JM32^u2j!~H@=-bnN}5Q5>w7hc_{!B(|JN!7T6b`huehDk;TD^ zw4ZkecD233ufsLz=%rgA#QGiNhi6}ZCQ%3P&xk^1oCyt5?O=wz8Gr{H$I_}tYP6aJ zV89ngX2S8I_&(l{YhHeY)@XIY{#6^{RKy#w9+?jxrf*>M^wQaglPZGUzQ>_{z9@M- zw1n=p<=}R|Dq}Y1B;&Eq9agWjfFx%LdVS71h&YxGKNg%p?=2JPfzg3w>uzvp?(-ZY z&LzQ~N9)0T?G8cTpaK0J9RN3@bZF`n8LH@d;+p=vc0pwG2r9zVLeIce5WVvacH4E~ z@S3+!9d?b49{P!$*&c$miB`;6c@YxryB!}l#0qYgDN}I+Iht+PhtA0p=%>*|?B#rQ zsy~>7iv?3ax%ve_frcea=Y^x6(Fkz2xP%g$RiGyH3Jf(!!^z(-v6rpGnAMGLP+dQR z?oW4M9ZmchZP@_St2U&0t7=MPpG4q^{dKVCbd6ddHgB{- z^9Ms=S>Iv7IkjVOH@J)4Ca=%f@A!?%;WD7wl8TMe&p4VWdVbHxsN3ihLY_!{Ih}T}&qRkc_ zI6ZlXT`k)%&P|25FZ>Q!@f&$zhkG!ncO7ItY-7(hzCwwW)vQLkBGK-Tg0VXZdu+NQ zojd6yj<;=u=xT9dt?>)$o#G(v$9i_F%20a7R*6QK41q(1Q&1tHidTI~3Nx>^q7EC1 z6$dVY!>J%HXs9S%owbF?=>w6Ekz+TWXW_|y3Gyg>5O^`Kxth_=RP$N_;g8ru@#ew$d=~Z_ul~6XIX#bGb$}T)tL6rd%keBZf4>n<+uq@ynHbe|8<# zj@U`eUcJWNv2vtJ&I`o@mvhHuhd@}gBb~~M;HQnIMDX@0*d@3g#y_oeDC*|)qK(by}D0f?}UlC)Cuw9ML22mP&$p;Njx1i4vFC4LtW0&{-0R0t8lwPWbx1a5i zu6INW>q{0NeJh}CiVD5my@)A&SAr|;R^rlRIr_7v2&c|H440=Dg2bH5Fv|8e^KkfL za4YwN3Hz$RFl-_QNY=Eu|CopEgDE(+s}7^< zqG5$?B^+pN#w*vPiQ_G8rb}@(#`LU*#;p~QZtw^?<#eEm9s@^(+b~>Qi7sg9XOpGg z;8V$DJlv=Q0`D)FWKJ>MU=pT&um#^Ktti?)oX*@ckD2;y9ln+*gU{Dgh^`0+=Z)G} z?cg}feO&-U=j_2VqIH<7(t#1e`^x#W*D$<31Ft&wpa-N7)dx)p~Kc4a7Td6ab)IcYil>{X$^+Ra!j z+05mL9mD2H$+X}jvRZ?W@NHle<}SU?(b&&uaoUGyW@phU6~gsf^H6U7vctsFpoJV0 z+LF3eL1fYUBEbyxD7x^o0raYhQ->ciq_RVi@>V>+#^CGZ2|JD)I`^3gGmqzn`0I1a zCkuIu{)DSltN3+wMG#>>fYXe_`Nr?t@oB0g87eqU{N5kqVw*OA0U%x!V zJ)LTfV|_}<(CP9d;mdTgl3xgC4I?n7xR#i;wy>Yw#^DQfKjPyZ#YpM9(h4I69(+D8 zT*GYVzuR|D&^*gp;JzaTJ_U>fM02UlH}A*$DaqZ_|}nEz*n+^jrkGB?K@~nvSmi`#co;gskR6|VwDOV zelMB4i(JZY&deqIUzL)wTk?~di%9%L z8UCA<%H;9x^NelOXXaYUcbY#zlrFBANS0o?MBe62jp|H~~o8&y}A?w876VuimXfR|wX)FCj4h*`(%kCJsJ@FD5 zN$#Rdu?|Mqw4rW_9C4RQ;QZUOa6ea#<8wBWea=KkC|fek?gjrN6a~!HdgiMLFi~qW9)xPTGo9V zWoD$8Qf91hi2AqQ0#~OJTw~A+I}W~L=9w3RYF!D47>?#_dZIZkk25f${TMy8wH^lQ zzX9qm!Xdjh6WPVOBtQBRs{T?SCpImI_3J}u*rf{GyD^#$DGz3PpSwfJ3`y>cnIaW6 z*b29|HNlA;Ut!0<5Tb3Q1)>gDU}k4Ab?nQ4pGvVfraFR^)t7_!jS{rly#q_4M&d7_ z-(Wke1uNyRq1d`O*yWW&Wnzr5ZCHlj&h-`7sz;DV79jSruL#--x)bq%Gt-SX6OdNVNz`b7K-GC@b7nWQ#}P??2*AJWcn zbdNa6dTGLcESStU`L4w0uZV`b#E>{yPUb6VR+3p;a){q`DZX9kcf5Yqi2T?(2!Vyq zP;_HEcVc2Nq%kod_p6!28eAu-7v^ExuR&sxmjJaI5+vra2<<&5PWKyLi&mvd41F^cn^(&VBv;vk_l_K9=6wl3j}ss+@`bG#J_B^*3t6vOzz*ps#ha&| zuvZ_IV)339Ol%vC3YR{@teZDM>#;9P)oMcT-DcEpj|x#2^#_xe8BlCt#(E^!!{yj0 zyma3Q_q>xMUwm~ju9kzH<2&&B`oq}oH45uuOKIRK2^^aGg>3E+;hVbO5vbe$B4uHk z=&(bEKGO{6!sX4#L0eV+lM!0{6>dEwc3U2d@t96FJ)glJnpsX(e}6#a;5j)qJ`I=T zSrcu&H}K=N65aCrHW%t3PE?Mq#W(x9NtBE@e_`ollu=3{3r;DKNLYaHg)yEzwufkV zX)4zpJ&NR?t70sD+ws%`Npeu*7l}2^BX#E``AkwVFDm~NjClN!bsOA3-JZ(PrO%I& zU5eD?4OW^ z=dNvn?%&Dq65IqX^VZ^hlR~glk74JFmY|wP7LLu+q4U?|;-5S`l`)mEDq}@N{`CJT z5APrOi&Ot^@)tKRH~@Y#BFVb8mryF5f_e8<=>B)F@q_Yk{$Q5{eqE&oM~By-|F&|n zW2QWbE9`-jK8J~;SS4u*&LD3;UxST%j-gG?0O{H%MQl-*&bU_#-f3V z-42Hblt`Gp2T_RXK{K^%Xt9n$wrMC9x`{$~a5-MPYK`YJx`^WJ6zCVOdzdM!(Ti%c zF?_Wl7o}29w%l06f12})EVI8(3ZI0NU9W+!-&2884Ym1S%zFPdZu8&w#Q$I9FHZaa zlfRf=XTo+rOQPxK7jf$0OYD}Z%H$Y)$Hfsp=xeL7nEW{aOno+BTD~`RUg*I%wQR;Q z{X$>N_#th18%hiQ_s{1^?9ny(z>;rhbw-hw41rx2v zvouMVqv}4`P4h=Kp=y2!Z^}s>t}-;g?Ahh-^!%suY=T7vEO3pZYsc3@>B(gFV$BV_ zzta?oHY}bkNvF6m!6X*)AnotXIqYz z&u)T)RULTfSqfNtS-{J>3da0}2ytjAggHBs@nK3Gd+NdsY_Q{CrO=0)AB&8OB4v*+ zc*+D$yN%y+%BaGeVeq`J5N@8i05_+&K$y!h;`HG-eKlO4%Ns7v{jis(Bc&BsevT+N zkR}SfZK@o|orBwrN?;WdNc$GFLHzF{0_Du*O!)o)a0?OPzSev$HP_7p*Y)Y_xYnbz z>SzXL7#)VqsS7|W_Zdw(7DcOebTVtt|AsC#b#CGGr%Zx-A}oqIjN4+pu{^&EqUFNi z)xo=ErmQkG(a^wE0fi`8-OH34r(C=5MVB#2o?DRI2Rx~#d#s8lo| zXB&YMks&1c(;2FB$e5e^`WqD-{E6>VtuZ0Lk2amLWm7MIrl0FR^Nf}l;1JCqD$#d? z&1zL=##nw~5DZYg*$6`yJlZTyGM1V!mh&!y{;_Q2xJyv-MvkOse`YQpeh-!}YQZ*g zHcNts!?0|7=9AiG*fd&}Kt(C7jZ!4mnV(@pODF3oAA-uG0*Kneqttcg7aA0=$gQpQ zq_*E5vR7X#bDv*M#A`ovxy?eq-sjDCG!frI7tQ7|FPtXf@6L9de*ZY0WIodJd%-9( z7|b63n!xk)kD-Cx`|+T*1H7~f;Vqo>mS&tzq?6}tfEy~taC&Kv&}TfsUJ4Ik_Dq$b z?5rO4#PL+YJ4spUYpXaiH@8h-<_Lj35$b?2piW*W5@W=!0!_DoMjQaBCUW96HP}r`+yPfROyC*I&-ICDPS_%7-d}&(0bSp zX58*LtiKunDpO>s&e(3Iq%4i~DNcbkP2!|J)&|}$DyPyd;V_yhfXySraG?JTWBJ>c z;FLT%#88?mNxMNWxE-Y0L=|BDBrZsCpfz zsZyg|vEQk|qBI;3=Btn|_1Lblk6LWIEihCQ!@%?HtcJ#WI{La7U3z0JtXg*zLW6~C z0~RrG;lO8@k7@9t=O(K>>pb$pTd{wb9NB(Ygk$<;I_M8>ld@^Ti_ff6YbYkxzs3qT4o5nAkqx6$>6{meT!`!!y6V{++95KQJ!!4U z6)#T_m}C#-Dt9AWT^7Ld#|Bc%i*nS%HVUN_-{2<64qSIJkG>2D#NkFu;peg==qH~{ z_io*TH#XcyCOCqvCarY;obxn0MHQQecVOYhraKLd8+IOyl zT-WnZ`_>K>wGP56*#_RoN@0v#vW0!Hx{+1mFN2a19COml3}g~7&`0;C3jOo?vTtub zvhT)aqt^34;_7{jKB<-Fo@A(UU+gAONB>edk~5xj^1sYzcnsro-4*bLh7<1g^Q6I6 zcVUl%6`nPU5a!dBvw4rsQTN>k@e-2=?i&^XRQl8Dcc%eYoab0wFvblk^%aB|TxwASipJIvm*j?3$5U%J2G z{&88HJ}3v5&n443i9*m#2t~0DFSv94Io0t?rjI+)*;^wL1^o6dx^N=k;&>x;$npf= z+0tz2yV-C`dk`P@4}$E)*+P| zEI0}4n|k2uvNjme9S61+VPyK+lT>z&A(ykFi>B6I#kHm*nLQ$^oJ>YKJ5f}hn?FA5Yu;C<)tRU)66 zs`ZlI&atc)7hg<&8KZ*CRVF)MzeOaM;7RDqIJi?IzyQxKX#$xSNLLyt0=~*OOVld zwTuI4p-iF?>bMHu-}{L>E;-TT&n7YbZeMWv$&qUl7cLpk85^E4Y0EKgeIgNdXASF=}tNM71ea3lV zZn{9YrdmsNRu*Ebs3Ihm<*`YlGNGdX7!fSJLYrcBxgxVNS|s92o0wc^zc`w+%CG0` zbvEF}1a`0wE5G5yo$++6);#w3tHUT&ydS3A_>5W`8fo*PBdqMhN)(S&p+52l=*a2- zW=4(}ZLfXEo4?>0z4a!MN`xk%&dphP^~@ms)`WtHASqb;u^b`hD_dIEhLY~5@Q24~ zu-Pp~jU_BGzMp5YI$D$}_(>A?CTZ4Zt14-X>VnC2T`=cO5&g7c1*^CIB?R9M!kpLF zU{`n)`S3fEPMEF9otr1aT{iKgaPu=%99dl+gb*_5D zKFGceCzZvxUC9z`=h0iNNTnpGyL@4~H> z)gJ1N8XJGXIJE@kZcq;<%{aU1gAf2aR{)s1?gW+eZnmhG}q1G~z+qUY6Dn|O(N)r6h4N?_Ruy^SZGV??#RlXs~nL9tEWvN|gSNx8#u^7Sa+u#68 z%2c^UJ)v+Pg*N(_i&V0x3R3s#VD}wmXzN$R6`sR5vuj}x>3bb*zyCm~Mh_YpAPMa= zdU1K_5IE1&(@7N<=&(SKvijk@On>+by5a5w-fn#vdNyk)J(h8v>6`Qp11HPVW9{?U zU&k+?Nc#g(29Y9m?|m;}a$qmWE|sFsOwt7zJZqThPzo0C1FW3Om{-jc z1RtyRA}>}Njl0{Rb4DqZYZE8!eJ7Z>=kl<7JqJH;gpvO5Y1GKdm^)?MK(7Sk;OP_7 zU~{z*w|KJ~+pO`H>K#0aBNiUPHI1S4Lufh_>dZ!mD`M18nEMi^D$lJ<(n86|2dMh{ zA!hYv&_y?L*fsVcI7CYn9xZO6!w&e<60t_$>%PPgp=~s4vkWQBdkgDo&OwJl5^LLB z0qYx{p;oRF9uZ0tly^MV3`Q%?OBY4{u&rr^9tf!yD{ZrD^6LLOIK@OW&?BU z%5uujp_`sG9sc+X$(PTf4(g*g>uvHJyYn(~Hqp%H+ge;p6=5EJ{7Ua!jfFq)lzKO1 z*HmQ@kw5)^il>bFdtKvnYb%5QV_l<>!3R3gDu&xQ>Kr$vZ7s*|v*FTW9Jmjgow%0T zWUlkg8Sd~Ne=aY$fa@-|;8F|sbIU>$IPI}Bl>6a zziaycvs_x`&j){N|E%!;C;C5Yah3jtbypXe#Z|HS@hJ?h`FslwkJ_#4*bpVncs~3v+(}cJ`KdT^8H0#f+ Xh{&Ihm)J;3{dq4V{QGnKU&sD007BMy diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/config.yml deleted file mode 100644 index 0fe34aa78..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k20/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/dqn.txt deleted file mode 100644 index f71b9c63d..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -677 -1002 -953 -1310 -724 -1230 -937 -1299 -497 -778 -685 -1329 -1327 -859 -1661 -933 -1316 -566 -814 -1714 -861 -1310 -1254 -1108 -827 -1492 -1016 -806 -1225 -874 -950 -1535 -1560 -1453 -1032 -1037 -1112 -1318 -1425 -1253 -657 -979 -1367 -993 -1373 -820 -1404 -1497 -1417 -1073 -935 -1513 -785 -970 -1768 -1362 -1231 -1687 -1258 -1504 -1061 -1178 -674 -958 -1010 -1092 -1255 -1073 -745 -1042 -1224 -1147 -1390 -1565 -984 -1162 -1243 -1174 -1462 -1750 -1071 -1159 -941 -1022 -1513 -1188 -1205 -1420 -700 -2066 -1502 -1219 -1004 -1397 -711 -1450 -1238 -951 -673 -1658 -718 -1414 -1385 -834 -1247 -1495 -1454 -1038 -988 -972 -1704 -1357 -1705 -1084 -2069 -1082 -1319 -1411 -2082 -1260 -906 -956 -1035 -985 -1155 -1123 -894 -873 -1228 -1102 -1201 -1770 -897 -1370 -1652 -1201 -1305 -1346 -1600 -1527 -1481 -1112 -1477 -1276 -1013 -1722 -953 -1315 -1090 -1421 -1882 -1459 -855 -1195 -764 -1104 -798 -1259 -1144 -1281 -1757 -1232 -1291 -968 -1207 -557 -951 -993 -1050 -869 -1561 -1365 -1203 -1032 -779 -2166 -1149 -906 -2186 -1073 -904 -656 -1044 -1430 -862 -682 -808 -833 -1507 -1221 -1581 -1216 -433 -775 -1014 -1663 -836 -1253 -1041 -1199 -590 -1216 -1445 -1100 -844 -1172 -1383 -1863 -912 -1428 -1099 -1391 -925 -895 -1996 -1079 -1697 -908 -1488 -1191 -853 -897 -1470 -823 -1074 -951 -1395 -757 -1554 -1163 -1019 -1045 -1251 -1100 -705 -1173 -948 -1059 -1447 -1254 -1538 -1252 -1245 -835 -1401 -816 -1046 -1187 -1431 -891 -1308 -1117 -1560 -1547 -1283 -915 -1223 -1034 -1640 -1249 -778 -896 -999 -1019 -1251 -1565 -947 -1103 -866 -1461 -966 -1723 -1160 -1119 -908 -1142 -1091 -951 -997 -1582 -995 -881 -710 -1366 -960 -1460 -989 -1300 -950 -1010 -1804 -1017 -1005 -1101 -977 -1017 -1081 -1318 -1390 -1660 -1020 -1130 -1418 -1458 -1366 -850 -1334 -1358 -1245 -1679 -666 -880 -1202 -758 -928 -1024 -1120 -1127 -1339 -959 -918 -1641 -708 -1088 -1640 -1231 -844 -974 -973 -1187 -884 -1397 -1011 -802 -1095 -1101 -986 -1660 -1178 -1146 -1337 -1112 -1362 -862 -961 -1118 -1066 -1219 -1176 -1534 -1234 -1451 -1128 -854 -1467 -1047 -1366 -1719 -668 -939 -772 -980 -628 -1514 -1459 -1434 -1105 -1429 -1232 -1044 -1346 -780 -737 -1273 -1566 -1141 -1115 -1164 -1101 -1007 -728 -1062 -1339 -588 -1217 -1509 -701 -1030 -1358 -1578 -1133 -969 -1558 -1425 -1250 -822 -720 -1060 -1138 -1121 -911 -921 -1360 -898 -660 -941 -791 -1188 -751 -1118 -963 -1301 -1355 -621 -1305 -721 -1045 -1258 -1111 -1467 -1353 -1175 -1164 -1204 -1143 -707 -1159 -999 -1780 -569 -1546 -927 -1050 -1325 -1120 -1643 -961 -883 -838 -760 -1544 -1287 -1708 -1306 -859 -1287 -656 -1093 -1302 -1187 -1508 -720 -1010 -1121 -998 -1517 -1241 -1815 -940 -1096 -1549 -794 -1202 -818 -751 -1247 -981 -1430 -842 -1248 -1292 -1138 -921 -754 -1209 -557 -1500 -1401 -1283 -854 -876 -1403 -868 -1144 -1137 -1322 -826 -896 -1327 -1023 -857 -613 -889 -969 -1013 -1128 -1125 -1250 -819 -1010 -1129 -1019 -1242 -1201 -787 -1306 -1023 -1468 -1140 -1270 -842 -1168 -1067 -1080 -1153 -1040 -1413 -1259 -1037 -1715 -1458 -806 -1528 -1074 -750 -1569 -828 -940 -1156 -703 -1072 -1123 -901 -1157 -1356 -1590 -888 -1772 -1189 -449 -1341 -1163 -1123 -1777 -1145 -1186 -1404 -1378 -920 -1436 -789 -1582 -1010 -1327 -969 -1159 -1196 -958 -1317 -1150 -1551 -906 -1127 -1093 -1489 -1777 -1151 -1291 -1119 -806 -994 -1323 -780 -1125 -1335 -1312 -924 -736 -1091 -944 -1143 -1129 -1254 -1022 -1073 -1190 -1195 -1354 -1084 -1069 -1353 -1444 -703 -700 -881 -976 -935 -1633 -1692 -552 -928 -852 -929 -988 -1072 -1273 -962 -882 -929 -1578 -1202 -983 -1061 -873 -1686 -553 -1539 -692 -1547 -1394 -803 -1640 -550 -1299 -1444 -1230 -733 -1206 -1057 -1235 -696 -940 -1050 -1066 -971 -924 -1005 -974 -589 -919 -869 -1118 -1184 -831 -694 -1016 -1611 -1226 -1250 -1594 -1186 -1778 -1127 -1032 -1478 -747 -950 -847 -1287 -1346 -1015 -1379 -911 -1385 -1189 -837 -970 -1122 -497 -857 -1278 -836 -871 -1120 -882 -1528 -1133 -1794 -926 -649 -1115 -1305 -1628 -1055 -1190 -1404 -1413 -992 -1332 -1017 -835 -898 -863 -806 -956 -748 -1077 -1155 -1306 -624 -792 -953 -1219 -1389 -1034 -947 -625 -958 -1028 -1203 -1384 -736 -1211 -1165 -666 -818 -1053 -900 -1177 -1137 -1111 -549 -1326 -766 -1536 -1383 -834 -1138 -1151 -1046 -877 -654 -1205 -1496 -1320 -930 -1413 -1235 -1000 -856 -1531 -888 -1573 -828 -1320 -1047 -1328 -1247 -970 -933 -823 -1319 -717 -1027 -1494 -950 -851 -825 -809 -1113 -979 -1008 -1267 -779 -1136 -1566 -1106 -1413 -1334 -1068 -1301 -912 -930 -1695 -1362 -1459 -832 -1046 -690 -1262 -1678 -878 -942 -1136 -998 -1213 -1123 -1117 -1179 -813 -1179 -1107 -1398 -1176 -1321 -780 -1341 -1214 -1275 -1169 -991 -750 -1328 -1516 -1035 -1016 -1087 -901 -1216 -997 -840 -1055 -1039 -697 -1201 -1403 -1478 -895 -1495 -798 -1073 -1556 -1044 -801 -1249 -1332 -1448 -766 -644 -815 -939 -1497 -931 -1120 -1099 -1496 -1040 -1227 -696 -941 -1158 -1050 -1582 -1136 -1759 -939 -937 -1079 -844 -1378 -1170 -1365 -1049 -852 -1079 -1303 -1007 -1099 -960 -977 -1274 -1261 -1156 -832 -1272 -616 -1000 -1544 -687 -813 -1222 -862 -1047 -1613 -1756 -715 -1211 -1222 -1249 -968 -678 -1503 -959 -1181 -1530 -1505 -1157 -1429 -1424 -811 -868 -1648 -1300 -1291 -1004 -1420 -900 -1534 -762 -1330 -1639 -1471 -836 -1495 -1341 -1352 -1216 -1088 -1104 -1144 -825 -1233 -1275 -1171 -820 -1078 -1359 -1462 -774 -1095 -1018 -1530 -878 -1100 -1206 -1447 -1855 -919 -974 -1097 -838 -1146 -1636 -803 -894 -1195 -637 -1123 -683 -837 -1333 -994 -1017 -783 -1245 -1014 -846 -1967 -1562 -987 -879 -1160 -888 -1310 -1307 -1218 -1097 -855 -1505 -1232 -1647 -766 -1279 -833 -1091 -1247 -1013 -1469 -1557 -1056 -1026 -1496 -1436 -1469 -612 -1129 -963 -1101 -787 -675 -1718 -1079 -1439 -1137 -1812 -822 -794 -1081 -948 -884 -1219 -1206 -1324 -1678 -1307 -989 -1144 -1419 -1124 -1639 -1710 -900 -880 -1197 -1406 -754 -1249 -1122 -1513 -420 -925 -1181 -1006 -1266 -814 -1128 -1099 -1342 -795 -1998 -1230 -1962 -948 -529 -915 -1229 -747 -1155 -1231 -997 -1265 -1646 -1110 -894 -1227 -1221 -818 -888 -949 -1124 -1121 -862 -1452 -1162 -1213 -1054 -383 -894 -1081 -494 -1072 -823 -1483 -1601 -1214 -1426 -1095 -1218 -1074 -867 -899 -733 -1824 -1165 -1101 -1199 -1024 -1091 -813 -1510 -773 -1459 -791 -1010 -601 -1164 -918 -796 -993 -1064 -1024 -891 -934 -1047 -891 -1320 -1250 -904 -1157 -863 -695 -1395 -807 -849 -947 -1222 -1071 -1300 -727 -514 -1301 -1180 -1118 -1102 -1608 -684 -478 -1214 -1303 -1165 -1279 -949 -704 -1099 -995 -949 -931 -1366 -1224 -1103 -988 -971 -822 -995 -1745 -1101 -1077 -1063 -1256 -1493 -1876 -852 -1083 -899 -1076 -1356 -1484 -1121 -2068 -1095 -1390 -831 -898 -1174 -1158 -1458 -1026 -1156 -1163 -1060 -1037 -1347 -1179 -1135 -783 -1504 -1116 -604 -830 -866 -976 -1633 -1175 -951 -816 -958 -1105 -1415 -1265 -882 -1718 -845 -1079 -1434 -1134 -916 -1389 -1019 -883 -1248 -1109 -850 -1089 -598 -1823 -1706 -1208 -1175 -1381 -1250 -1610 -1260 -1530 -1172 -962 -1087 -1017 -1069 -1987 -1171 -1349 -1577 -1431 -1016 -465 -772 -1537 -1011 -1268 -1186 -1203 -1228 -1035 -1233 -1432 -852 -787 -828 -785 -974 -1069 -1010 -1505 -1794 -926 -1298 -1108 -793 -1700 -1082 -1123 -1074 -796 -810 -1557 -1160 -1267 -1117 -1396 -1026 -1586 -548 -1220 -1430 -1018 -1143 -923 -1138 -1177 -1461 -1216 -1538 -1244 -1331 -1784 -975 -1261 -583 -1217 -921 -1039 -688 -989 -1339 -556 -725 -689 -1084 -1148 -725 -823 -814 -997 -1350 -971 -881 -1012 -1311 -1190 -1480 -893 -1364 -1088 -1254 -1149 -1319 -1234 -1135 -1732 -993 -1203 -1169 -1113 -960 -1389 -927 -1079 -1260 -1686 -1417 -1017 -773 -692 -1084 -1605 -1275 -1333 -1120 -854 -1590 -1422 -1154 -1055 -880 -1043 -719 -1166 -1586 -1078 -963 -929 -818 -1013 -1493 -1325 -1210 -1400 -1641 -1216 -1135 -1028 -1107 -1716 -1338 -1073 -699 -819 -740 -787 -1440 -1482 -965 -1001 -737 -903 -1335 -1490 -983 -1973 -1004 -1031 -1499 -1560 -1055 -735 -830 -891 -1577 -1035 -1466 -1683 -1809 -1131 -933 -851 -950 -783 -1264 -1356 -1699 -1063 -647 -1042 -1428 -1211 -1054 -1148 -959 -1593 -1192 -1343 -1096 -976 -1379 -1117 -1008 -1019 -814 -1283 -1623 -936 -1049 -940 -1235 -1070 -773 -1386 -1036 -1057 -1654 -1204 -952 -822 -1343 -1317 -1290 -848 -1582 -514 -1562 -1350 -1210 -1110 -1290 -1416 -1226 -739 -1232 -1293 -876 -590 -1294 -962 -1143 -838 -1269 -1093 -942 -831 -855 -1441 -725 -966 -1686 -1261 -1060 -1223 -1113 -713 -1494 -794 -1323 -1448 -1532 -1160 -1139 -1121 -1171 -830 -860 -1867 -1773 -1006 -762 -1137 -848 -893 -1107 -1436 -1040 -1647 -1051 -1193 -1177 -1303 -1205 -1183 -1121 -1057 -949 -1344 -959 -1420 -1440 -765 -963 -676 -1340 -806 -1439 -944 -1384 -1089 -1643 -1328 -907 -613 -1033 -1191 -1014 -879 -1552 -1357 -940 -815 -901 -593 -815 -1687 -986 -839 -774 -872 -1226 -1055 -864 -459 -1191 -900 -1169 -893 -987 -1538 -709 -1350 -1494 -1319 -869 -726 -1132 -1339 -1476 -1524 -1214 -1279 -804 -777 -1386 -1373 -992 -1346 -1288 -911 -1146 -781 -970 -1408 -1448 -981 -1464 -1449 -866 -1074 -1128 -998 -1111 -1422 -1261 -1079 -1354 -992 -1143 -1156 -1634 -1750 -752 -1200 -1491 -1311 -1402 -1350 -754 -2012 -1144 -681 -1188 -731 -994 -1504 -1115 -1468 -955 -897 -939 -1532 -1020 -1116 -765 -1370 -978 -1315 -1765 -1658 -1113 -1865 -1233 -1090 -1258 -686 -971 -695 -1253 -1554 -706 -1206 -1344 -1368 -1042 -965 -1064 -1002 -1162 -1361 -1046 -920 -1121 -980 -1312 -928 -1377 -1019 -1319 -1159 -1505 -848 -982 -1067 -1100 -1122 -1425 -862 -1480 -1054 -1314 -909 -1311 -1097 -1479 -1024 -857 -1184 -1270 -1125 -1043 -993 -1172 -1734 -985 -2000 -793 -1225 -1242 -1389 -1426 -606 -719 -1244 -1257 -825 -1265 -1280 -928 -842 -740 -797 -1261 -1255 -911 -1301 -1566 -1023 -1590 -1199 -841 -979 -1676 -1268 -1080 -1274 -1275 -994 -1102 -1188 -897 -1040 -974 -1193 -1559 -985 -1112 -1278 -1009 -1335 -1208 -1385 -725 -1229 -890 -1429 -1371 -1220 -1368 -934 -1061 -1145 -1185 -1524 -1013 -1397 -880 -893 -1107 -967 -1201 -836 -1089 -1360 -1506 -1035 -613 -1407 -910 -1199 -1250 -1014 -813 -741 -1162 -1038 -965 -984 -946 -758 -828 -986 -1195 -1303 -931 -1173 -1062 -1166 -1206 -1007 -1202 -1372 -718 -1228 -471 -1000 -1275 -1041 -671 -823 -1227 -1124 -1797 -940 -814 -867 -1014 -1155 -1454 -1269 -1242 -1300 -1354 -1232 -983 -893 -1182 -1206 -981 -1696 -1597 -1157 -658 -923 -1423 -1131 -912 -894 -783 -1416 -559 -839 -1037 -1071 -1046 -1124 -1226 -1142 -1336 -1412 -819 -1529 -1451 -1342 -1205 -683 -623 -915 -799 -801 -1414 -963 -928 -1173 -404 -820 -1287 -654 -1482 -1965 -911 -990 -1476 -1030 -1034 -1061 -995 -1186 -743 -1397 -688 -1801 -879 -1128 -991 -1422 -1013 -1246 -1008 -1073 -859 -1329 -1040 -1139 -1534 -1131 -1296 -651 -1078 -961 -1484 -1071 -1212 -645 -1151 -1067 -895 -730 -1110 -1177 -1018 -1423 -664 -1311 -976 -969 -958 -1032 -1123 -678 -1341 -1313 -1171 -817 -1096 -1384 -907 -1423 -1265 -1261 -1294 -936 -1135 -989 -1197 -1139 -937 -1262 -1068 -1200 -1194 -631 -1411 -1001 -1038 -996 -999 -721 -1047 -1149 -2238 -1274 -944 -1309 -1128 -993 -1195 -1373 -946 -1639 -1215 -854 -1316 -1519 -796 -1498 -703 -698 -1138 -469 -1167 -1692 -1151 -895 -1005 -1081 -865 -684 -900 -1041 -1002 -1245 -1132 -1636 -1262 -1450 -982 -937 -957 -1017 -1303 -1203 -975 -961 -801 -1243 -673 -770 -1214 -986 -1203 -713 -1323 -569 -862 -1307 -1278 -1018 -1406 -1086 -1183 -822 -1181 -1138 -1829 -624 -1911 -1298 -1160 -872 -1310 -1356 -994 -1195 -1022 -1189 -860 -1281 -1275 -1100 -997 -1132 -1162 -1329 -707 -2061 -990 -1265 -1649 -920 -1485 -1463 -1048 -1351 -749 -1104 -1109 -1421 -1064 -1046 -641 -1109 -997 -715 -1197 -965 -796 -1545 -1099 -1156 -1625 -1055 -2114 -970 -714 -984 -1093 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/optimal.txt deleted file mode 100644 index 161c69e1c..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -791 -1002 -953 -1305 -724 -1085 -937 -1012 -497 -778 -685 -1277 -1327 -859 -1141 -933 -1316 -566 -929 -1005 -582 -730 -1254 -1108 -827 -817 -685 -1685 -1086 -874 -922 -1535 -1560 -1453 -1032 -1037 -1112 -1318 -1425 -1253 -1494 -900 -1321 -1437 -1111 -820 -1250 -1561 -1082 -1073 -879 -1513 -785 -970 -1768 -1362 -1231 -1599 -1258 -1586 -1357 -647 -674 -675 -1641 -1662 -1255 -1073 -745 -1042 -1224 -805 -1527 -1130 -1044 -1162 -1243 -1174 -963 -1135 -706 -1082 -941 -774 -608 -1442 -1205 -1420 -700 -1344 -1502 -1219 -1542 -1450 -711 -1681 -1969 -951 -673 -1157 -1490 -823 -1407 -1029 -604 -1495 -1308 -1033 -1073 -742 -1704 -1559 -757 -953 -1146 -1082 -935 -1160 -2082 -856 -906 -1603 -1907 -985 -1155 -1123 -1131 -873 -983 -1121 -1044 -905 -978 -1164 -1355 -826 -1165 -1346 -1600 -1527 -1481 -1112 -1191 -966 -1013 -1722 -953 -1158 -1090 -1421 -1362 -1002 -855 -1214 -764 -859 -1404 -941 -1202 -976 -1283 -880 -985 -1090 -1207 -557 -1316 -691 -1253 -869 -926 -831 -1203 -1032 -779 -1210 -1283 -906 -2186 -1478 -904 -891 -1044 -1204 -862 -876 -808 -833 -1507 -1221 -708 -1216 -960 -1282 -1142 -1663 -1278 -1418 -1041 -1199 -953 -1216 -1162 -1100 -1452 -1172 -1379 -1863 -1368 -1544 -1099 -1388 -925 -895 -1325 -1539 -1697 -1202 -1524 -1238 -956 -1268 -2116 -1734 -1173 -1088 -1395 -1556 -1554 -614 -862 -1045 -1251 -1100 -705 -1571 -948 -1220 -1240 -1254 -1028 -1301 -764 -835 -997 -1187 -1046 -1024 -557 -891 -1308 -1923 -1388 -1258 -921 -915 -934 -1238 -1640 -1124 -894 -1118 -999 -1019 -1371 -1473 -947 -1103 -866 -1461 -1662 -1052 -1722 -1126 -1337 -1142 -1177 -951 -1550 -1496 -995 -881 -1230 -995 -1547 -1460 -989 -1300 -950 -1010 -1804 -1017 -1744 -1101 -2019 -1017 -867 -1318 -1145 -1584 -655 -1043 -1270 -1213 -1366 -850 -888 -1085 -1245 -1679 -666 -880 -1202 -758 -928 -722 -1120 -1127 -1203 -959 -918 -1019 -708 -1012 -1289 -1231 -844 -1221 -973 -1635 -884 -1591 -1011 -1117 -1358 -1101 -550 -1167 -1432 -1146 -1337 -1112 -1246 -862 -961 -733 -1066 -1110 -1176 -1534 -1234 -1341 -1128 -1136 -1467 -1047 -658 -902 -668 -939 -772 -1350 -1150 -1514 -1173 -1286 -1105 -909 -1237 -1044 -1070 -1211 -715 -1338 -1566 -1141 -1115 -1164 -1079 -1007 -728 -1062 -1339 -1178 -1215 -1509 -701 -717 -1000 -1096 -1133 -1533 -1558 -1425 -876 -1522 -1036 -1060 -1098 -1121 -1475 -943 -1448 -1199 -994 -941 -1515 -1188 -751 -1599 -915 -1392 -1663 -621 -1305 -721 -1429 -1538 -1111 -1152 -1353 -802 -883 -1204 -1143 -707 -1159 -1256 -1492 -1598 -1251 -927 -1204 -1325 -1120 -1332 -961 -883 -838 -760 -1288 -1287 -943 -1065 -1822 -1287 -1264 -1093 -1449 -1187 -1508 -877 -1010 -760 -998 -1517 -897 -1272 -949 -992 -1635 -969 -1202 -818 -751 -1256 -1309 -961 -842 -1248 -1362 -773 -921 -923 -1209 -557 -1500 -1165 -1656 -854 -876 -1403 -1102 -806 -1137 -1610 -826 -1158 -1069 -989 -1296 -974 -889 -978 -1013 -689 -1125 -1250 -819 -680 -1523 -1019 -770 -889 -787 -1306 -1023 -1468 -1140 -1270 -1675 -1200 -1067 -870 -805 -1040 -1413 -1259 -1037 -1715 -1000 -855 -1528 -1074 -869 -1089 -828 -940 -957 -703 -1072 -1265 -901 -889 -1356 -1590 -888 -1008 -1189 -901 -1009 -1163 -1123 -1777 -1564 -1186 -1087 -861 -920 -1436 -789 -1139 -668 -1363 -1469 -948 -1196 -958 -1094 -1266 -898 -906 -1645 -1093 -1489 -1777 -1151 -1501 -1119 -806 -1267 -1323 -1447 -1137 -1335 -1312 -924 -736 -1053 -944 -1143 -1129 -1254 -981 -1073 -1190 -1638 -1354 -1629 -1098 -1353 -1444 -1027 -700 -881 -1451 -1391 -1201 -1190 -965 -1023 -852 -929 -988 -1072 -1096 -962 -882 -929 -1578 -1202 -1509 -1061 -1361 -1446 -1112 -1513 -1075 -1547 -1394 -803 -1238 -550 -1548 -1444 -1489 -733 -1206 -1057 -1235 -696 -940 -930 -1201 -971 -1832 -1294 -929 -1202 -919 -869 -1118 -1207 -831 -894 -1016 -1611 -1134 -1250 -1075 -1145 -1778 -1127 -1032 -931 -544 -1261 -847 -1287 -1346 -1385 -898 -1393 -1151 -1189 -837 -970 -1122 -497 -1374 -1010 -1363 -871 -1120 -788 -1181 -1133 -1794 -926 -853 -801 -1305 -1148 -1055 -1190 -1404 -1413 -1518 -1332 -1017 -835 -839 -1254 -1417 -900 -748 -1275 -884 -1172 -1044 -792 -953 -1582 -1389 -1034 -1293 -625 -1295 -1028 -1373 -1384 -830 -1189 -884 -1430 -818 -1053 -900 -871 -1137 -1111 -549 -1318 -766 -1536 -1383 -786 -769 -1151 -1046 -721 -654 -956 -1496 -972 -930 -1413 -1235 -1077 -856 -1216 -888 -1278 -791 -1320 -1047 -988 -1247 -970 -932 -823 -1319 -717 -1251 -1494 -950 -851 -825 -809 -1113 -994 -1008 -1267 -779 -1363 -990 -1106 -1413 -1370 -1613 -1219 -1224 -1160 -1251 -1503 -1459 -832 -1046 -690 -1262 -1126 -878 -845 -1160 -998 -776 -970 -1117 -1179 -813 -1093 -848 -1398 -1176 -1125 -780 -1341 -1216 -1275 -1169 -888 -750 -1328 -1516 -945 -1201 -1087 -901 -1123 -1245 -1477 -1055 -1039 -562 -1201 -1403 -1478 -897 -1495 -847 -1071 -1094 -1499 -801 -1249 -1332 -1582 -766 -1833 -933 -1415 -1333 -931 -1120 -1019 -959 -1040 -739 -696 -941 -997 -1501 -1206 -1113 -475 -1012 -939 -1079 -1055 -1378 -1170 -1365 -1027 -1224 -835 -1457 -1007 -1341 -1106 -2037 -878 -1261 -1156 -1307 -1521 -616 -1000 -727 -1128 -656 -1222 -862 -1158 -1613 -1179 -715 -1303 -1371 -1249 -968 -1155 -1220 -1075 -1500 -1530 -1187 -1138 -1217 -1424 -811 -868 -1028 -1300 -1242 -1004 -1420 -900 -1305 -762 -1054 -1639 -1053 -1314 -1226 -1341 -1213 -1216 -1067 -1104 -1390 -1562 -1233 -1275 -1171 -1177 -1078 -1326 -1386 -827 -1299 -1018 -1530 -878 -1207 -1206 -1447 -1548 -919 -859 -1097 -838 -785 -1576 -803 -894 -1213 -637 -1123 -683 -837 -1437 -994 -1017 -783 -1245 -1430 -846 -1967 -1562 -987 -879 -1160 -1058 -964 -1156 -1120 -1358 -855 -1505 -785 -1647 -766 -1279 -1109 -1442 -1247 -1326 -1469 -1240 -1056 -1014 -1307 -967 -1469 -612 -1456 -1160 -1101 -1207 -675 -923 -751 -1200 -1137 -1074 -822 -794 -1081 -1548 -760 -1333 -982 -1044 -1678 -584 -989 -1368 -1419 -1226 -1639 -1710 -900 -880 -1131 -1189 -754 -1249 -1169 -1513 -420 -1007 -1181 -1006 -1255 -814 -1128 -1099 -1342 -777 -1205 -1330 -973 -948 -745 -886 -963 -932 -1135 -1358 -1015 -1486 -1717 -1110 -894 -843 -1221 -818 -888 -743 -1143 -1098 -862 -1452 -1162 -1789 -1260 -383 -894 -1081 -974 -860 -823 -968 -1601 -1113 -1476 -1095 -1218 -1074 -867 -778 -733 -979 -1165 -1453 -1350 -1024 -1091 -1233 -1430 -1022 -1412 -943 -1010 -601 -1289 -1371 -796 -1096 -1064 -1024 -891 -894 -1047 -1401 -1320 -1042 -904 -1157 -863 -695 -1395 -1088 -1131 -1394 -929 -840 -1300 -727 -1294 -569 -2049 -1442 -1145 -1608 -1220 -876 -1214 -1303 -1496 -1279 -949 -1292 -1289 -995 -949 -931 -1366 -1224 -1325 -1046 -971 -822 -995 -1324 -1101 -870 -1196 -1240 -1443 -1876 -852 -1083 -913 -926 -951 -847 -1121 -1119 -1095 -1197 -967 -1417 -1451 -1071 -999 -1026 -1369 -1221 -1419 -1351 -1347 -886 -1135 -920 -1860 -1116 -877 -1087 -866 -976 -884 -1175 -1184 -1037 -1049 -1041 -1337 -1265 -832 -1009 -845 -1079 -935 -1134 -916 -1389 -952 -883 -1121 -1109 -815 -1602 -598 -1823 -1706 -1640 -1175 -1381 -911 -1563 -1624 -1530 -1172 -997 -1087 -857 -1425 -1987 -1051 -1349 -1195 -1431 -902 -1169 -772 -1459 -1044 -1268 -1406 -1203 -1034 -1035 -1005 -1432 -813 -787 -1309 -785 -974 -814 -625 -1505 -1794 -926 -1298 -1108 -1702 -1700 -1024 -1123 -937 -1192 -753 -931 -1160 -1147 -1305 -1396 -1195 -1586 -548 -1220 -1430 -1018 -1143 -923 -1138 -1177 -1461 -1216 -1538 -1498 -1139 -1623 -975 -1261 -583 -1198 -1046 -1212 -688 -901 -1339 -556 -1178 -1489 -1220 -830 -725 -757 -814 -997 -1350 -1544 -881 -1474 -870 -1584 -1633 -789 -1044 -1088 -1254 -1149 -1319 -1234 -1094 -1272 -993 -863 -1169 -1113 -1030 -1389 -927 -1737 -1405 -1686 -690 -1017 -1262 -692 -1574 -1046 -1275 -848 -1120 -1563 -1590 -950 -1784 -1698 -1094 -1241 -719 -1183 -1080 -1078 -537 -929 -1446 -1621 -1493 -1191 -1210 -1400 -1641 -1216 -1388 -1028 -896 -1082 -572 -1073 -699 -819 -740 -1119 -1440 -869 -823 -1001 -737 -903 -1294 -1490 -983 -1973 -1162 -1029 -1499 -1145 -1055 -587 -1243 -1401 -1577 -884 -1466 -1683 -1809 -946 -933 -851 -772 -1048 -719 -1356 -1277 -833 -647 -1042 -1105 -1110 -1054 -1266 -959 -1593 -1192 -1343 -1053 -976 -744 -1057 -1349 -884 -885 -1283 -974 -936 -1333 -940 -1235 -1434 -932 -1386 -1036 -1057 -2055 -1204 -1013 -928 -1343 -708 -1290 -848 -1341 -1908 -1183 -1350 -1210 -1110 -1272 -1127 -720 -1325 -1232 -964 -881 -1542 -659 -962 -1143 -1250 -1269 -1297 -942 -831 -855 -1441 -725 -966 -1686 -1384 -1060 -2002 -989 -508 -909 -844 -978 -1448 -931 -1195 -1152 -1121 -1067 -1069 -860 -1086 -1773 -1006 -762 -1137 -1169 -619 -956 -1145 -1040 -1647 -1032 -1193 -635 -1303 -1205 -1008 -1121 -1057 -949 -1344 -959 -1501 -1440 -765 -1189 -676 -952 -1381 -876 -1867 -1384 -869 -1643 -988 -1213 -1479 -1033 -1351 -1014 -879 -816 -1111 -940 -815 -901 -593 -1596 -917 -986 -1114 -774 -778 -1161 -1350 -864 -459 -1191 -941 -1169 -893 -1037 -1626 -709 -1350 -1494 -1319 -869 -1149 -800 -806 -851 -1524 -1512 -928 -1046 -777 -1386 -467 -990 -763 -1288 -1266 -1146 -1172 -1284 -1408 -1448 -1336 -1464 -1168 -1078 -1074 -790 -998 -1111 -1422 -1521 -1183 -948 -992 -1129 -1008 -1634 -1750 -752 -1113 -1449 -1290 -1298 -1350 -754 -2012 -857 -1095 -1188 -731 -1081 -1967 -1115 -1522 -1149 -775 -939 -1288 -691 -1116 -1104 -1500 -978 -1315 -1765 -860 -1113 -1002 -1233 -1090 -756 -686 -950 -695 -727 -1397 -1525 -1206 -1686 -545 -1042 -2027 -1064 -1002 -1087 -1079 -1046 -1184 -976 -980 -1312 -928 -1236 -1019 -1152 -1595 -1505 -848 -982 -1067 -1100 -1122 -1425 -862 -1480 -1056 -1314 -727 -1311 -1097 -1479 -1024 -1305 -1267 -821 -1125 -790 -993 -1415 -1132 -985 -976 -1152 -962 -1242 -1129 -1811 -606 -1087 -1244 -771 -825 -816 -1280 -928 -842 -1603 -797 -1261 -1255 -911 -789 -1566 -1056 -1590 -923 -1290 -973 -1676 -1268 -1080 -1269 -1089 -1101 -1061 -1229 -897 -1084 -974 -1193 -1559 -985 -1112 -1278 -1393 -1335 -1208 -1385 -725 -1039 -890 -1429 -1258 -1465 -1368 -1237 -1061 -1145 -1185 -1385 -1013 -839 -1495 -893 -821 -967 -1201 -836 -698 -1260 -1378 -1363 -613 -1080 -910 -864 -1252 -1514 -813 -726 -1162 -1038 -965 -984 -946 -758 -828 -986 -1200 -1303 -931 -1173 -1189 -726 -983 -1007 -1074 -1372 -906 -1228 -988 -1204 -1275 -1262 -1369 -1383 -1227 -1070 -1797 -940 -814 -867 -821 -919 -1454 -1940 -1242 -1300 -1211 -1119 -983 -920 -1182 -1569 -1382 -775 -1203 -1085 -658 -906 -1423 -956 -1325 -982 -783 -1507 -1028 -839 -1034 -1071 -1046 -1066 -1152 -1326 -1331 -1412 -1231 -1151 -1366 -1342 -1565 -1083 -623 -984 -799 -1418 -1366 -963 -1225 -2085 -404 -1181 -1300 -1265 -1052 -1225 -1120 -979 -1139 -1505 -1034 -1744 -995 -852 -1362 -1448 -1090 -860 -693 -1128 -1270 -1975 -1340 -1246 -1008 -1305 -859 -1329 -1395 -693 -1500 -1351 -1296 -651 -1159 -961 -752 -1071 -1212 -645 -1151 -1067 -803 -1126 -1110 -1177 -1400 -1423 -1140 -1494 -976 -969 -1167 -979 -1123 -678 -1163 -1313 -656 -817 -1096 -1384 -714 -1309 -1265 -1261 -1294 -936 -1135 -1538 -1121 -1139 -937 -1226 -790 -563 -947 -631 -1411 -1222 -908 -996 -999 -721 -1417 -911 -2238 -955 -705 -1220 -1128 -1161 -1295 -1029 -1001 -1074 -1215 -854 -831 -1187 -796 -1412 -703 -698 -803 -469 -1020 -1692 -734 -895 -1005 -1283 -865 -684 -900 -1041 -838 -900 -1132 -1636 -1262 -1450 -982 -937 -1232 -1017 -1707 -1069 -975 -1091 -855 -797 -1362 -922 -986 -986 -1184 -1106 -1323 -1313 -1212 -1307 -1278 -1626 -1406 -898 -826 -822 -1181 -1138 -1829 -624 -1911 -1050 -1160 -1340 -1310 -1356 -994 -1155 -1022 -1189 -1231 -1281 -844 -906 -925 -1132 -1162 -1329 -707 -2061 -990 -1339 -1136 -1123 -1384 -992 -713 -725 -749 -1185 -1109 -1268 -1027 -1436 -474 -1598 -997 -1088 -1215 -845 -796 -1545 -900 -1127 -1625 -1055 -1250 -970 -1364 -984 -1093 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/random.txt deleted file mode 100644 index 092014d87..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4095 -3077 -1498 -3282 -2490 -3483 -3146 -2060 -3018 -2530 -2805 -2708 -3050 -3459 -2415 -3464 -2182 -4233 -3856 -3883 -4288 -4151 -2838 -3104 -4062 -2020 -2759 -4049 -2481 -3269 -2620 -2846 -3390 -2706 -3247 -2420 -2607 -4649 -4139 -2948 -2320 -2767 -2903 -2517 -4300 -3347 -3855 -4359 -4527 -2990 -3206 -4149 -2033 -2683 -3783 -3922 -2144 -2425 -1705 -3206 -2120 -2825 -2356 -4206 -2676 -2414 -2933 -3246 -4900 -3446 -3406 -2577 -3314 -5569 -3644 -4566 -2710 -3056 -2542 -3136 -3928 -2857 -5319 -3177 -2823 -3835 -3860 -3389 -1929 -2842 -4882 -2413 -2230 -3313 -3793 -2761 -3199 -3253 -3877 -4585 -3209 -2288 -3034 -2990 -3600 -2232 -1652 -2386 -3131 -1978 -2749 -3620 -3066 -4281 -2040 -2804 -2886 -2215 -1680 -3889 -2097 -3444 -3438 -2672 -2136 -3603 -1924 -3375 -3396 -2985 -3356 -3248 -1856 -2212 -2988 -2910 -3078 -3879 -2606 -3996 -2348 -2219 -2630 -3031 -3540 -2370 -2768 -4031 -2430 -2848 -3255 -2794 -3021 -2955 -2295 -3209 -3631 -2251 -2426 -3114 -3876 -3774 -4061 -2166 -3299 -2770 -3391 -5253 -3259 -2837 -5410 -3443 -2962 -2181 -3532 -3153 -4656 -5427 -2840 -3524 -3935 -2802 -3596 -4028 -4171 -2703 -3009 -3186 -3202 -3827 -3027 -4039 -3295 -3511 -2052 -4177 -3193 -6107 -2164 -3365 -3269 -3557 -3302 -3429 -3570 -2842 -3285 -3578 -3013 -3567 -3329 -3276 -3368 -6028 -3488 -3381 -2038 -2698 -4645 -3331 -4312 -3314 -2213 -2723 -3524 -3478 -4892 -4197 -4177 -4650 -3843 -4587 -3918 -4011 -3060 -1814 -2993 -2995 -2970 -3138 -3241 -3262 -3452 -2492 -4470 -3388 -2784 -1347 -2436 -2787 -3372 -3286 -4371 -3702 -3709 -2750 -1461 -3859 -4415 -3258 -1634 -1540 -3219 -2609 -3385 -2199 -3307 -2122 -2981 -2680 -3958 -3716 -2762 -2445 -3083 -4806 -3428 -3085 -2176 -4296 -3817 -2281 -2979 -3605 -3388 -3388 -3619 -3582 -3681 -3510 -1274 -2787 -3498 -3793 -1394 -3137 -3538 -3836 -3246 -3344 -3177 -3213 -3560 -3102 -3605 -2929 -3000 -1827 -3971 -3637 -3279 -2935 -3133 -2834 -3471 -3745 -3212 -2626 -2986 -1556 -2721 -3094 -3395 -3909 -3567 -2642 -2566 -3307 -4029 -2573 -2589 -2227 -4269 -3478 -4579 -4038 -3670 -3413 -1611 -4769 -3426 -2342 -3527 -4003 -2670 -4310 -3614 -4048 -4679 -4300 -2462 -3769 -1115 -3154 -1957 -3163 -3160 -3214 -4084 -5274 -4118 -4023 -2564 -2374 -2401 -2442 -3420 -4772 -4651 -2799 -4614 -4168 -3682 -2896 -2558 -5886 -3857 -3652 -4505 -3502 -4930 -4108 -5120 -4471 -2733 -2581 -2309 -3964 -1603 -4831 -3600 -2983 -4734 -1645 -2588 -1879 -3356 -3804 -2484 -4729 -3381 -2966 -1787 -2080 -1552 -3163 -2677 -2987 -2561 -2566 -2670 -3496 -3570 -4160 -2889 -4377 -2803 -2549 -3125 -2311 -3102 -2039 -2667 -5079 -2800 -3034 -3973 -3262 -2898 -3686 -2985 -2961 -1723 -2511 -3149 -4204 -3055 -3921 -3181 -1844 -2274 -3273 -2871 -4715 -2910 -3669 -2808 -2817 -2441 -2897 -3675 -3946 -3570 -2972 -3886 -1883 -2449 -3240 -2999 -3238 -5313 -4238 -3855 -3445 -2513 -2750 -6623 -2869 -4543 -3159 -2223 -1999 -3469 -4115 -2728 -2938 -2495 -3906 -3574 -2250 -3119 -2668 -3048 -2606 -4429 -2841 -2258 -3797 -2731 -3641 -4473 -4818 -3789 -3539 -2428 -2628 -3839 -3536 -4201 -4371 -2105 -2135 -3283 -3464 -3674 -3079 -3716 -3397 -2888 -2693 -2400 -4125 -3217 -2058 -3221 -3148 -2656 -3295 -2734 -2897 -2262 -3878 -3266 -3113 -2786 -2977 -2684 -5006 -3534 -2510 -4310 -3185 -3230 -3650 -5097 -2772 -2337 -2314 -3818 -2901 -2957 -2664 -2327 -3141 -2936 -3504 -2727 -2505 -4165 -5609 -3706 -3143 -3768 -3351 -2803 -2838 -3269 -2836 -4429 -2964 -2477 -2291 -2145 -4080 -2693 -4475 -2286 -3337 -2833 -2955 -4275 -3889 -3387 -3315 -3463 -4755 -3017 -3311 -2288 -3099 -5083 -2540 -2301 -3607 -2902 -5104 -2198 -2108 -3547 -4730 -1790 -2043 -3477 -2381 -2283 -2424 -1779 -3175 -3610 -2996 -2930 -3677 -3369 -2355 -3663 -3308 -2257 -2330 -3140 -2220 -2360 -3772 -2149 -2002 -3112 -3032 -3614 -5307 -2100 -4549 -3246 -3425 -3923 -3104 -3501 -4113 -4706 -1763 -3018 -4260 -2021 -3993 -2950 -2161 -3112 -2703 -2516 -4650 -3511 -1862 -2909 -4064 -3102 -1800 -3895 -2836 -2261 -3665 -4980 -4479 -4252 -2650 -3628 -2921 -4688 -2751 -4122 -3325 -4204 -2782 -3580 -2006 -3214 -2997 -4016 -2435 -3758 -4994 -2777 -2658 -4255 -1984 -3368 -3339 -3923 -3039 -2343 -3304 -4217 -2694 -3819 -3182 -3269 -2750 -2587 -2747 -3301 -2741 -3590 -3908 -2655 -2344 -2338 -3817 -2502 -4093 -2960 -2833 -3645 -3096 -2182 -4121 -3122 -2287 -3489 -3826 -2023 -5066 -4127 -3153 -3277 -3549 -2386 -3073 -4927 -4863 -4205 -3299 -3718 -2470 -3597 -2949 -2490 -2515 -3455 -2688 -4710 -3340 -3458 -3235 -2729 -4137 -2913 -2391 -3838 -3664 -1958 -3189 -2449 -2835 -3859 -4170 -3155 -2751 -3041 -2169 -3912 -3182 -3954 -2852 -2161 -3377 -3779 -3576 -4189 -2892 -2315 -3547 -2304 -3178 -2621 -3123 -2113 -2635 -2779 -3442 -3940 -4141 -5005 -3520 -2624 -4310 -2495 -2586 -3915 -2637 -1573 -2291 -2583 -4578 -2240 -2522 -2704 -4687 -3195 -2368 -3719 -4053 -3768 -3528 -2382 -3301 -3471 -3943 -3648 -2222 -3293 -4527 -3297 -2978 -2646 -2857 -3033 -1753 -2160 -2066 -4653 -2532 -2264 -3571 -3124 -3511 -3674 -4024 -3839 -3236 -4940 -4008 -1622 -2640 -5325 -4474 -3818 -3881 -4519 -2831 -3264 -3379 -2551 -2242 -4625 -3536 -2634 -2515 -2680 -3635 -1707 -3442 -4235 -3953 -4155 -4807 -2179 -1826 -3159 -1597 -3991 -1522 -2918 -3155 -2880 -2424 -1487 -3799 -2966 -3154 -3413 -3838 -1694 -3944 -3432 -2701 -2621 -2223 -4135 -3421 -2352 -2976 -2712 -3447 -3771 -2109 -3453 -2779 -3976 -3023 -5189 -3957 -3122 -3879 -4441 -3546 -3200 -3714 -3675 -2932 -3254 -2422 -3952 -3213 -2395 -2214 -2483 -3658 -2138 -4718 -2451 -2942 -4026 -1813 -2989 -3152 -3358 -2603 -3685 -2853 -4208 -2822 -4396 -2833 -2663 -3955 -3871 -3554 -1867 -2446 -3569 -1913 -2957 -1746 -2808 -2483 -2598 -2135 -2723 -3081 -2785 -2324 -2786 -3935 -3039 -3186 -3249 -2303 -3128 -3720 -2877 -3356 -3126 -2623 -3711 -2491 -2460 -3452 -3769 -3412 -4131 -4047 -3031 -2228 -4009 -1903 -3479 -2868 -4691 -3277 -3027 -3174 -2860 -2538 -2698 -2439 -3338 -2342 -2131 -4308 -2086 -3616 -3748 -2230 -1774 -2477 -3117 -3258 -3532 -4235 -2686 -2455 -2351 -2352 -3203 -2491 -3514 -5290 -4514 -2978 -4579 -3862 -2736 -2067 -3510 -5326 -2458 -3307 -3108 -3388 -4450 -4750 -4438 -2738 -3866 -2871 -2695 -3985 -1500 -2863 -4972 -3812 -3266 -3833 -1739 -3907 -2025 -3446 -2421 -3899 -4001 -3956 -2946 -2622 -3652 -3478 -2667 -1415 -3375 -2401 -2704 -2528 -3143 -2676 -3087 -3861 -4387 -3105 -4138 -3170 -3301 -3499 -2859 -3712 -1997 -2256 -3464 -3497 -3785 -2869 -2951 -2739 -3962 -2604 -1850 -2180 -2526 -2889 -2687 -2051 -4131 -3767 -2342 -3297 -2096 -4433 -3111 -4140 -2408 -2674 -2575 -4513 -3620 -2852 -1673 -4010 -3225 -3456 -3954 -2497 -3407 -3993 -1437 -2234 -2711 -2307 -3272 -4423 -1456 -2682 -5066 -2564 -2694 -5485 -3752 -2746 -2587 -2985 -4216 -2417 -4621 -4093 -3454 -2578 -2919 -4833 -3207 -2930 -2358 -3188 -2375 -4122 -1435 -3820 -2493 -4211 -3948 -3152 -4723 -3071 -4563 -5042 -5747 -3909 -3300 -3549 -2898 -4169 -2968 -3587 -3628 -2313 -2406 -2927 -4597 -2630 -3942 -3293 -3238 -2614 -3471 -4130 -2810 -2202 -3221 -3313 -4413 -2621 -2357 -4495 -2586 -3651 -2852 -4213 -3149 -3928 -4698 -4031 -3232 -2013 -4706 -4162 -3524 -3824 -3078 -3744 -2951 -4299 -1828 -2234 -3606 -4180 -3130 -3609 -1953 -2230 -4117 -2940 -2397 -4121 -3479 -2516 -3858 -1097 -2783 -4263 -2185 -4144 -2351 -3787 -3650 -3163 -3632 -2433 -2455 -1645 -3982 -1897 -2217 -1419 -4106 -3552 -2615 -2928 -3932 -3152 -2921 -4018 -3405 -4609 -2554 -3119 -3705 -3737 -3525 -3265 -2357 -1554 -2808 -3517 -2727 -3792 -3275 -2549 -2965 -3844 -3601 -2900 -1909 -3781 -3771 -2360 -1479 -2962 -4607 -3629 -4631 -4322 -2009 -2689 -3726 -2369 -3467 -3723 -3435 -3499 -4360 -4162 -2176 -2736 -3007 -5552 -3552 -2384 -2242 -2397 -1889 -4234 -2984 -4745 -1905 -3633 -1802 -2216 -2810 -3127 -3453 -4566 -2481 -3039 -3007 -2041 -2380 -1501 -3018 -2935 -4265 -3577 -1831 -4537 -3022 -2357 -2841 -3713 -2111 -3480 -3006 -3779 -3207 -1907 -3358 -2755 -2953 -2654 -3980 -2277 -2647 -2319 -3613 -2343 -3688 -3070 -2370 -4018 -4024 -2996 -2813 -2803 -3827 -3404 -3737 -2672 -3884 -2096 -3901 -3104 -4341 -3439 -4166 -3143 -3571 -3394 -2379 -3582 -4159 -2402 -4586 -3148 -3475 -4616 -4250 -3174 -3308 -4291 -3212 -1925 -3374 -2730 -3466 -2458 -3746 -3767 -1972 -2833 -2390 -4657 -3472 -1347 -4874 -3233 -3988 -3311 -2426 -3594 -1968 -2412 -4871 -2206 -3249 -2430 -3461 -3164 -4272 -2078 -2388 -3668 -3049 -3833 -4058 -3854 -3833 -2713 -2392 -3952 -3588 -2763 -3689 -2365 -2883 -4358 -2470 -4946 -2782 -2927 -2533 -1940 -2339 -2937 -3147 -3346 -3706 -3750 -2206 -2332 -4222 -4136 -2030 -2971 -3550 -2447 -3950 -2607 -1697 -2731 -2481 -1851 -2126 -3407 -2997 -4794 -3274 -3708 -3111 -4182 -2694 -3053 -2220 -4557 -2701 -4315 -5092 -2096 -2974 -2855 -3624 -2100 -2789 -3674 -3253 -4342 -3411 -4010 -2677 -3898 -2339 -2248 -3599 -2758 -3985 -4124 -2658 -4067 -3059 -2858 -1620 -4844 -4897 -5039 -3809 -2687 -2694 -3305 -3278 -4078 -3714 -3993 -3480 -3280 -2787 -3481 -4027 -4403 -3874 -2458 -3705 -4652 -1921 -4331 -2987 -2747 -3940 -4224 -3184 -4070 -2200 -5025 -4075 -3506 -4111 -2956 -1880 -1347 -1976 -4092 -3176 -2387 -3499 -4052 -2628 -3585 -3824 -2732 -3688 -2864 -2307 -2500 -2362 -938 -2470 -3247 -4059 -3869 -3187 -3958 -4185 -2253 -4927 -2617 -2426 -2496 -2750 -2368 -1598 -2459 -2213 -2868 -3288 -4293 -3852 -1708 -3339 -3565 -3317 -2462 -4315 -5179 -2744 -3406 -3876 -3984 -2140 -3407 -3650 -1913 -2591 -2649 -3131 -4414 -2718 -3079 -2759 -3232 -2759 -3050 -3186 -1476 -2897 -4476 -3626 -4101 -2012 -2743 -3501 -2491 -1735 -3861 -3589 -2483 -2188 -2028 -3235 -3155 -3198 -3197 -3625 -4086 -3060 -4190 -2895 -4071 -4577 -3935 -4783 -2870 -3063 -1858 -3477 -3310 -3896 -2574 -3706 -4279 -4155 -3640 -3290 -3413 -4023 -3647 -3896 -3005 -2016 -4659 -3371 -4095 -3062 -2574 -2810 -3252 -2354 -3467 -2531 -3264 -2502 -4243 -3581 -2146 -2853 -2221 -2815 -3867 -3525 -3541 -3130 -4005 -4028 -4343 -4191 -2979 -4241 -2913 -2804 -2590 -3177 -2274 -3641 -3671 -2993 -3957 -4023 -4132 -3170 -4258 -2283 -3253 -3864 -4071 -4132 -3302 -4271 -2861 -3933 -2760 -2628 -2202 -3700 -3800 -4026 -3426 -2897 -2701 -2737 -2260 -4834 -3972 -3448 -4637 -3140 -2645 -3244 -3540 -3451 -3158 -1744 -2591 -4139 -2620 -3237 -2056 -3231 -3933 -2253 -2162 -3293 -2431 -4722 -2902 -3097 -2911 -2893 -3505 -2738 -3595 -3577 -2421 -1285 -4003 -2968 -3118 -2550 -3748 -3608 -1441 -2907 -3660 -4161 -2879 -3084 -4777 -2112 -2222 -2648 -3117 -3210 -1887 -2649 -2661 -2971 -3412 -2544 -2335 -2830 -4129 -3092 -4072 -3969 -2733 -2603 -2348 -3011 -2457 -3978 -3345 -3721 -3831 -3527 -2680 -3020 -3672 -3462 -3287 -2078 -3308 -3898 -3917 -1754 -3018 -1846 -4929 -2977 -3162 -4127 -2197 -2661 -4015 -2675 -4068 -2580 -4070 -3104 -2283 -2162 -3073 -4588 -2745 -2645 -2780 -3356 -3894 -2802 -3671 -3735 -6169 -3843 -2500 -3463 -3071 -1928 -2894 -1932 -2616 -3026 -4073 -4376 -2514 -2843 -2783 -2864 -5550 -3413 -3325 -3787 -3397 -3023 -3156 -2347 -2681 -3387 -2874 -4094 -3832 -2176 -2660 -4322 -3266 -1985 -4209 -3173 -4236 -3206 -4167 -1944 -3423 -2478 -1746 -4111 -3049 -2825 -3344 -1476 -3220 -2081 -3410 -2572 -2921 -4538 -3510 -3204 -4720 -2975 -3216 -3956 -3251 -4650 -2631 -2121 -3678 -2505 -3253 -4719 -3276 -2838 -2878 -2979 -4015 -3537 -4679 -4908 -4010 -4383 -2616 -3037 -4618 -4109 -3770 -2202 -3529 -2151 -1712 -3985 -3291 -2906 -3564 -2732 -3785 -2366 -3004 -4135 -2408 -2456 -4029 -3509 -3121 -1211 -3078 -2441 -3147 -3096 -3766 -2722 -1924 -3808 -3517 -2467 -2989 -3147 -3028 -3250 -2635 -4887 -2044 -5529 -1622 -3496 -2907 -2098 -2458 -3084 -3364 -3592 -3538 -2707 -2570 -2246 -3143 -3024 -3097 -4827 -3270 -2533 -2503 -3131 -3637 -2584 -3272 -2699 -4121 -1640 -2083 -2582 -2391 -2082 -3301 -3500 -1235 -3491 -4405 -3672 -2330 -4761 -2770 -2137 -3370 -3729 -2470 -4325 -2417 -2412 -3026 -3222 -3260 -3394 -2799 -3598 -1858 -1748 -5903 -3863 -3765 -1322 -2739 -4903 -1378 -4045 -3388 -3253 -4434 -3610 -2451 -3162 -2997 -3060 -3159 -2333 -3127 -3725 -2410 -3918 -1414 -3900 -3092 -2963 -5044 -4573 -3372 -4332 -3536 -3519 -4605 -3138 -4804 -2581 -2546 -2465 -4160 -3017 -2470 -2311 -3619 -2405 -2718 -3761 -4016 -3759 -3644 -3101 -3070 -3303 -4494 -1926 -3981 -2843 -4394 -3112 -1974 -2010 -3053 -2247 -3223 -3604 -3364 -3312 -4396 -3683 -5401 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/best.pt deleted file mode 100644 index 51df8413725ab4a52b592c9673865a97504f80e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13463 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 DEN}(j diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/config.yml deleted file mode 100644 index 6496749d3..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k3/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 17, 33] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/dqn.txt deleted file mode 100644 index 6057a8b50..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -510 -1434 -1349 -1022 -914 -1276 -753 -1380 -1368 -1187 -1197 -934 -1230 -928 -1027 -1135 -767 -1208 -1047 -963 -1251 -1092 -1587 -1172 -1548 -842 -756 -1096 -1488 -926 -914 -1119 -1261 -1057 -1014 -689 -1223 -1209 -965 -942 -1473 -673 -1433 -1409 -1431 -1517 -1358 -876 -1717 -1203 -1437 -1239 -1055 -1517 -1107 -688 -1110 -530 -1061 -1364 -1272 -804 -1066 -1262 -1011 -1238 -991 -1233 -1209 -963 -655 -1366 -1425 -1297 -1115 -1437 -1295 -933 -1166 -1119 -897 -1258 -1049 -768 -1357 -1335 -1263 -1216 -830 -1087 -924 -1152 -1166 -1465 -1385 -927 -928 -1094 -1261 -1217 -1423 -727 -1022 -1204 -906 -709 -1487 -1159 -740 -1167 -1740 -500 -842 -1236 -872 -1057 -1209 -1428 -973 -884 -614 -1545 -1391 -848 -964 -1240 -1067 -1345 -931 -1153 -1158 -614 -1610 -1168 -1442 -1236 -1871 -798 -1101 -1076 -659 -762 -1162 -1111 -1611 -1034 -1107 -1249 -1036 -842 -1166 -1287 -1474 -1200 -1288 -976 -1826 -830 -1114 -1081 -1405 -767 -1353 -1395 -1022 -1024 -1424 -899 -1218 -1031 -1170 -1025 -1257 -736 -662 -846 -1280 -1472 -1161 -1492 -760 -942 -1463 -844 -616 -853 -781 -1121 -1396 -925 -1243 -1380 -989 -949 -1582 -730 -625 -1482 -1182 -1333 -1041 -1045 -672 -697 -1187 -808 -1143 -1486 -981 -1197 -1182 -973 -1131 -1233 -1380 -897 -932 -1486 -898 -1685 -1504 -932 -1455 -743 -1477 -828 -1425 -1508 -1024 -1067 -1380 -1406 -1053 -1264 -1226 -1164 -1056 -690 -1164 -984 -1215 -1030 -1337 -1192 -722 -1714 -1125 -995 -1668 -1049 -1412 -1093 -735 -1126 -1381 -1432 -999 -1185 -840 -1467 -1077 -1283 -1271 -899 -1204 -682 -1164 -969 -722 -1402 -1091 -1053 -1183 -1503 -1076 -706 -2041 -1336 -1370 -1144 -1071 -1671 -1839 -1468 -643 -1003 -745 -1160 -1219 -1038 -1157 -852 -1167 -1435 -843 -757 -960 -1457 -1342 -1149 -1158 -543 -915 -1189 -1352 -1243 -1779 -991 -1310 -1084 -1218 -1421 -1198 -1136 -974 -952 -1548 -1068 -909 -1347 -1352 -1397 -1141 -1176 -911 -1169 -1398 -857 -879 -1095 -1083 -756 -1417 -1918 -925 -1025 -836 -756 -786 -971 -1628 -660 -1732 -813 -843 -1205 -845 -1123 -1139 -1226 -1444 -781 -1004 -887 -1051 -1308 -722 -1152 -1525 -950 -449 -1074 -1428 -1172 -796 -604 -1164 -1205 -1015 -964 -1036 -1195 -1612 -1207 -1061 -1013 -552 -1293 -905 -1450 -1410 -1098 -1092 -1263 -1331 -925 -1187 -1750 -1138 -1107 -1472 -1284 -1269 -1349 -1117 -881 -690 -1080 -1666 -1820 -1337 -1479 -1307 -1055 -1098 -987 -1311 -724 -1054 -1501 -1171 -1283 -1139 -1322 -1427 -1102 -929 -918 -1071 -1214 -1046 -1206 -1254 -1185 -1001 -603 -1248 -1120 -684 -666 -681 -1467 -1402 -1136 -792 -852 -1136 -1347 -1107 -852 -1286 -1331 -1642 -779 -1426 -1356 -914 -1064 -1531 -1119 -1168 -1497 -1252 -925 -1114 -978 -1656 -1124 -1063 -881 -865 -739 -1033 -824 -897 -1334 -935 -950 -1225 -754 -769 -918 -1159 -1306 -938 -701 -731 -742 -677 -899 -1223 -710 -1301 -1184 -820 -1081 -1659 -956 -1432 -1060 -887 -934 -1513 -1038 -1168 -726 -748 -1298 -674 -1543 -1351 -994 -1325 -592 -1634 -1032 -922 -825 -1560 -962 -951 -1181 -1013 -729 -781 -979 -909 -1516 -758 -1010 -1024 -1554 -1374 -1232 -1158 -1225 -1537 -1051 -533 -1651 -1162 -1149 -1119 -1091 -1190 -1179 -1567 -796 -638 -682 -829 -637 -1222 -802 -996 -963 -935 -1296 -1280 -934 -1288 -1087 -843 -916 -1176 -1139 -1113 -1285 -1147 -911 -824 -977 -1061 -1590 -908 -1166 -803 -995 -1285 -1040 -1437 -1499 -1344 -1337 -821 -556 -1372 -1190 -1172 -1607 -706 -934 -1397 -825 -1022 -901 -1012 -1424 -1775 -1524 -929 -1224 -1487 -1264 -1254 -1290 -1702 -1310 -1006 -816 -1098 -1178 -727 -1704 -891 -903 -1437 -1805 -889 -996 -872 -774 -998 -1331 -1324 -1049 -1293 -1123 -1160 -712 -1030 -726 -839 -835 -1347 -1156 -857 -1005 -725 -1691 -1039 -671 -589 -1022 -1428 -1027 -903 -2105 -729 -1050 -1117 -957 -1085 -1089 -1760 -870 -1492 -1265 -1091 -879 -1249 -728 -1289 -395 -1019 -1098 -769 -861 -1045 -1071 -930 -859 -1387 -1312 -905 -1417 -1201 -1151 -1215 -1078 -624 -1125 -1284 -944 -1336 -1316 -1282 -1326 -751 -1451 -593 -1238 -1508 -890 -1861 -974 -1421 -1059 -761 -887 -1339 -1027 -1210 -1015 -658 -981 -691 -1068 -813 -1338 -1086 -1220 -1054 -1303 -895 -615 -652 -896 -1580 -1305 -1552 -1178 -1292 -906 -1299 -1230 -997 -1194 -1027 -1591 -1020 -1276 -1138 -793 -639 -927 -1217 -1181 -703 -1030 -1255 -1217 -1557 -1091 -1156 -1114 -1470 -1196 -1438 -1420 -974 -1495 -1019 -1505 -903 -801 -743 -780 -741 -815 -941 -758 -1025 -1143 -1288 -1093 -1947 -1354 -1285 -719 -864 -1072 -1315 -949 -817 -1148 -594 -1147 -800 -866 -824 -1363 -1079 -731 -1594 -725 -1033 -1260 -1084 -692 -1069 -901 -1857 -1321 -756 -832 -873 -1373 -1136 -693 -1207 -1484 -1891 -1467 -1034 -1252 -611 -1016 -889 -1150 -1399 -750 -938 -1076 -1098 -1216 -1180 -691 -1112 -701 -804 -1355 -1314 -1167 -841 -619 -923 -1631 -1549 -1110 -1414 -868 -956 -1110 -1549 -1096 -918 -984 -1162 -790 -711 -1041 -1128 -1372 -1149 -1089 -1145 -1692 -1058 -481 -1179 -1072 -1217 -1189 -1209 -1498 -670 -1173 -905 -1231 -707 -1406 -1399 -1706 -1125 -1428 -834 -725 -843 -812 -879 -858 -1306 -858 -1028 -1438 -1295 -1061 -573 -1212 -1603 -1076 -834 -851 -1258 -699 -902 -621 -760 -968 -1370 -1082 -1112 -1176 -1404 -1376 -681 -667 -1498 -1068 -1285 -750 -715 -1250 -1415 -940 -1478 -1419 -1222 -839 -1194 -1449 -1228 -1635 -824 -726 -1037 -1087 -1294 -1157 -1339 -1268 -776 -1090 -1215 -994 -1169 -1790 -1461 -1439 -1074 -1159 -1054 -893 -895 -1127 -1555 -1247 -1171 -905 -727 -1065 -1398 -890 -925 -648 -844 -1199 -1347 -980 -1033 -975 -1224 -909 -706 -1328 -867 -1019 -1008 -837 -1463 -1242 -1006 -1278 -1090 -1072 -975 -759 -1148 -1129 -1004 -1111 -1031 -1003 -909 -864 -843 -1098 -1040 -1447 -1151 -1821 -1499 -1203 -1106 -1256 -1052 -1227 -1245 -1359 -1169 -1549 -652 -1197 -1019 -1490 -1206 -1340 -1171 -1073 -842 -1301 -972 -692 -1012 -1309 -1349 -1343 -1059 -1208 -670 -901 -755 -601 -816 -777 -902 -804 -1358 -1714 -928 -1126 -959 -1115 -1182 -1173 -1165 -1201 -1276 -654 -673 -914 -1566 -562 -850 -1077 -1494 -1359 -731 -815 -1108 -996 -1503 -807 -1203 -933 -823 -825 -1020 -1079 -1414 -853 -1383 -1267 -966 -785 -1509 -1297 -943 -987 -1277 -1361 -1255 -1189 -673 -1690 -856 -1116 -979 -808 -1481 -1164 -1561 -680 -1187 -1252 -1320 -1467 -1289 -722 -1485 -931 -1099 -1248 -933 -1100 -877 -1428 -883 -1010 -1048 -1465 -1171 -1054 -1407 -1685 -1450 -1388 -1475 -1762 -522 -641 -911 -478 -1203 -993 -1280 -1040 -870 -795 -1159 -961 -899 -817 -924 -1231 -1085 -1612 -1327 -1196 -1212 -1690 -835 -1454 -1790 -1328 -1322 -1688 -725 -616 -941 -1278 -838 -1216 -919 -819 -1535 -1421 -1329 -1165 -877 -960 -1364 -961 -1105 -1092 -1541 -904 -1176 -1459 -1328 -1856 -930 -1551 -1201 -1583 -1210 -974 -978 -993 -793 -984 -1067 -1305 -938 -987 -1086 -1014 -1079 -765 -955 -1363 -617 -1069 -1317 -682 -798 -1379 -1249 -803 -595 -1710 -1428 -833 -953 -1076 -750 -985 -686 -678 -1190 -1099 -1148 -850 -1479 -901 -898 -936 -1406 -1180 -936 -914 -1275 -798 -814 -1055 -822 -940 -976 -969 -838 -648 -1496 -1396 -771 -876 -1083 -1445 -1151 -1106 -639 -1254 -1726 -1152 -984 -868 -1516 -1149 -810 -1194 -948 -1005 -1356 -1498 -1135 -1151 -694 -1136 -1076 -694 -1131 -901 -1331 -958 -851 -887 -1583 -1471 -1573 -886 -913 -1211 -1537 -1033 -1035 -925 -857 -1073 -819 -915 -829 -1304 -1238 -1441 -1377 -1521 -1078 -1031 -1204 -1290 -838 -985 -1373 -1040 -911 -512 -1024 -1387 -797 -1099 -1182 -1271 -1029 -1475 -748 -1552 -1008 -1499 -716 -1002 -682 -984 -901 -1011 -1137 -1074 -936 -726 -816 -1081 -1316 -1506 -1311 -1325 -728 -1014 -1139 -856 -802 -1032 -1395 -1140 -391 -939 -1142 -852 -884 -1404 -747 -883 -1919 -1405 -1016 -878 -725 -920 -1231 -815 -904 -1546 -861 -1042 -1393 -1110 -1170 -1004 -1345 -933 -1263 -1071 -1381 -1218 -645 -1585 -1062 -1346 -655 -1502 -1729 -1057 -759 -709 -1702 -787 -1375 -1185 -738 -1507 -736 -969 -1452 -860 -1291 -910 -869 -1408 -963 -1295 -1038 -770 -838 -1696 -1277 -1534 -916 -1168 -1010 -1230 -935 -1119 -1705 -1276 -772 -1167 -1531 -1481 -1273 -1003 -719 -1109 -1376 -825 -756 -855 -1877 -1145 -1132 -1209 -1223 -1024 -804 -876 -1176 -1448 -1708 -1112 -1448 -1100 -1608 -1219 -1018 -1012 -928 -1617 -1216 -1036 -1064 -1037 -625 -708 -1250 -842 -876 -945 -1035 -1501 -1204 -884 -949 -1024 -1228 -1737 -1482 -723 -1321 -700 -1164 -991 -904 -1495 -1573 -922 -520 -854 -1033 -874 -1065 -957 -910 -1510 -608 -1508 -859 -1482 -854 -890 -1104 -1327 -946 -982 -918 -1128 -1338 -1862 -1344 -1290 -907 -1066 -841 -626 -809 -1382 -1773 -474 -1133 -1204 -908 -1492 -1183 -1128 -1162 -727 -939 -803 -1711 -1075 -707 -1060 -1609 -944 -1002 -1238 -969 -1237 -1432 -750 -1037 -1321 -1637 -1023 -717 -933 -647 -1303 -1020 -1637 -636 -1073 -1521 -833 -897 -1447 -1030 -1359 -1337 -809 -1584 -1283 -1355 -1310 -890 -460 -909 -1188 -1214 -2242 -1472 -1080 -963 -826 -1043 -1230 -1061 -1058 -1032 -1078 -695 -1288 -941 -1040 -851 -369 -1706 -1509 -1102 -1035 -1454 -1496 -1171 -1537 -1129 -636 -1416 -469 -1280 -1444 -817 -1367 -1912 -1250 -840 -812 -911 -926 -997 -1178 -981 -1055 -1050 -1068 -1292 -1227 -766 -1249 -1045 -1087 -1033 -1402 -1304 -1309 -1138 -420 -593 -1261 -628 -1523 -1168 -1573 -812 -1551 -862 -906 -1208 -651 -784 -1262 -1208 -1614 -771 -1224 -1183 -1049 -871 -1315 -1131 -1098 -891 -1285 -902 -1010 -1258 -1149 -1287 -552 -1007 -926 -826 -847 -1392 -1462 -665 -1124 -945 -804 -929 -1624 -1371 -1124 -1193 -1154 -677 -1534 -676 -1180 -1078 -1338 -987 -1369 -618 -580 -1144 -375 -830 -860 -1054 -1120 -955 -1252 -849 -803 -1626 -1166 -1084 -867 -1127 -1116 -1294 -875 -1462 -744 -1397 -825 -1734 -1308 -1368 -345 -1363 -1155 -890 -1147 -498 -1535 -1500 -1287 -1111 -1035 -943 -874 -684 -486 -763 -905 -1370 -1096 -1381 -1261 -1222 -947 -997 -1100 -1200 -1454 -1434 -1389 -879 -1179 -909 -1174 -1012 -1096 -1036 -876 -1557 -544 -1495 -1133 -1467 -627 -903 -1090 -1189 -1397 -821 -1365 -1096 -1273 -978 -984 -806 -899 -1453 -619 -1206 -1000 -678 -845 -1155 -1149 -1024 -1421 -1308 -1317 -795 -1002 -1570 -1316 -995 -1116 -1014 -1200 -1351 -1201 -1455 -1026 -976 -1117 -1330 -918 -726 -771 -1104 -844 -554 -1113 -1668 -1446 -796 -902 -1178 -1006 -1176 -1027 -989 -1500 -886 -1224 -984 -798 -1098 -1063 -906 -1272 -823 -1132 -752 -1130 -1758 -1646 -1097 -1268 -1573 -1157 -712 -1047 -1330 -999 -835 -1160 -875 -1047 -1003 -963 -1045 -1225 -901 -1429 -1242 -659 -827 -1042 -1033 -990 -816 -911 -739 -1511 -1080 -1009 -1105 -947 -1534 -1202 -1640 -1125 -976 -735 -1088 -1034 -1272 -1522 -1505 -1184 -1200 -1003 -1226 -1234 -907 -1046 -881 -1165 -1469 -831 -1382 -742 -1182 -1448 -988 -1112 -782 -1140 -1292 -774 -988 -1217 -907 -1212 -1274 -798 -1047 -975 -1346 -1135 -1012 -774 -993 -1047 -960 -798 -1309 -1113 -1058 -1352 -1295 -896 -955 -1441 -845 -1489 -1170 -894 -868 -874 -723 -815 -732 -958 -482 -1441 -980 -1227 -805 -1503 -1175 -1314 -872 -1073 -1553 -1132 -894 -794 -532 -1064 -430 -1633 -686 -1320 -1073 -1187 -989 -1162 -943 -984 -856 -1072 -1016 -1235 -1020 -1544 -1064 -884 -991 -789 -989 -1085 -795 -1164 -1280 -1239 -1330 -1131 -1111 -899 -1189 -631 -1720 -1325 -1143 -909 -998 -999 -878 -1338 -1429 -1196 -967 -1048 -982 -1163 -1398 -1304 -987 -1107 -642 -802 -1103 -1823 -881 -1070 -1049 -1259 -1338 -1228 -961 -1166 -800 -1204 -855 -1245 -896 -1170 -1232 -923 -1413 -1408 -1242 -989 -1335 -887 -846 -1039 -1002 -1180 -1006 -991 -1277 -1353 -1293 -1096 -1184 -1115 -837 -1868 -1007 -1252 -732 -1187 -1194 -952 -1441 -1546 -518 -1092 -914 -1065 -1172 -1049 -876 -608 -1478 -764 -1233 -1076 -1331 -1678 -888 -2153 -1082 -598 -1146 -928 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/optimal.txt deleted file mode 100644 index 3ebc59351..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1170 -1434 -1242 -1121 -1311 -1314 -1340 -1103 -931 -831 -985 -1363 -725 -856 -1027 -1219 -1290 -1485 -956 -973 -788 -1092 -1116 -1172 -876 -1211 -936 -1096 -741 -1214 -736 -1018 -1371 -786 -1014 -1415 -1223 -1096 -965 -851 -895 -840 -1038 -1076 -1018 -1022 -1354 -876 -1717 -880 -1390 -1239 -852 -607 -1107 -948 -1110 -1744 -1288 -558 -1272 -1761 -965 -1262 -1530 -1199 -1048 -977 -785 -1141 -1230 -704 -618 -1197 -1115 -940 -1529 -933 -1357 -941 -1248 -1258 -720 -510 -913 -998 -982 -867 -759 -898 -1395 -940 -1286 -1132 -1382 -905 -1057 -1094 -1090 -587 -1208 -727 -1177 -1355 -1126 -709 -1157 -1205 -803 -1166 -1168 -1557 -1043 -704 -1124 -1458 -866 -1428 -973 -884 -1342 -1031 -1165 -848 -1124 -895 -1067 -1038 -1436 -854 -1024 -614 -997 -880 -755 -1251 -718 -931 -769 -982 -922 -762 -1343 -857 -1611 -1033 -1410 -1249 -885 -798 -1039 -1242 -754 -1298 -902 -1932 -849 -1062 -821 -956 -1911 -1433 -1219 -801 -705 -600 -1268 -1108 -1218 -1220 -1566 -1103 -738 -1112 -893 -1117 -1036 -1098 -932 -935 -1068 -1018 -1233 -629 -616 -1556 -781 -833 -1200 -1768 -1243 -1380 -1137 -941 -921 -730 -1303 -1613 -1182 -1333 -1041 -1045 -672 -697 -1039 -709 -749 -1486 -657 -737 -1182 -973 -1131 -1233 -1380 -739 -830 -1208 -991 -1354 -870 -932 -1455 -743 -1480 -899 -1112 -1508 -807 -1142 -1029 -1579 -1406 -1264 -1207 -1127 -993 -1131 -1171 -1262 -865 -1030 -1256 -1097 -1238 -919 -1330 -995 -1013 -1280 -1436 -1093 -651 -604 -697 -1432 -1295 -569 -664 -658 -1073 -1141 -1187 -1367 -1140 -1219 -1164 -1548 -1222 -827 -894 -1849 -1183 -1503 -818 -706 -860 -1336 -1654 -831 -1071 -685 -945 -800 -643 -758 -745 -860 -1219 -1071 -1157 -852 -1408 -815 -843 -757 -1575 -643 -1342 -1437 -1326 -543 -1629 -1120 -899 -748 -1867 -1096 -991 -1289 -1218 -1421 -1198 -1136 -1465 -1140 -1548 -927 -909 -1092 -1088 -1420 -1141 -1052 -911 -765 -941 -857 -539 -1411 -831 -1407 -1417 -807 -727 -1025 -836 -756 -769 -1092 -1628 -1426 -1014 -813 -843 -1012 -852 -909 -1164 -986 -1158 -921 -1004 -887 -1445 -1308 -722 -1071 -1278 -950 -1202 -1612 -1751 -1183 -1414 -873 -1164 -710 -961 -1156 -1036 -1658 -1013 -1265 -697 -1013 -1115 -1001 -526 -1045 -1334 -1461 -959 -1031 -1331 -1023 -1011 -1750 -1138 -1253 -1637 -1284 -1270 -1086 -1117 -1128 -984 -1410 -1142 -1066 -1304 -1479 -817 -831 -1244 -987 -1634 -762 -590 -982 -1443 -1283 -1352 -474 -1154 -1035 -995 -918 -1055 -1026 -1516 -1206 -1254 -1528 -1187 -603 -1248 -691 -684 -1322 -681 -733 -1158 -1136 -1327 -758 -1485 -1140 -941 -852 -1177 -1092 -976 -1247 -1534 -1356 -914 -1064 -655 -859 -1081 -1079 -1351 -1519 -1351 -1018 -1656 -1124 -704 -893 -990 -1153 -1033 -883 -885 -1334 -812 -1523 -1225 -1016 -918 -1209 -1159 -1500 -1307 -701 -776 -901 -948 -1399 -1014 -677 -822 -1184 -557 -914 -1659 -1305 -819 -673 -1273 -1370 -882 -828 -1036 -1022 -748 -1298 -674 -852 -786 -1007 -1325 -1332 -1259 -1693 -1015 -872 -1365 -1092 -951 -974 -944 -1418 -415 -979 -732 -1183 -1090 -1445 -1299 -1554 -1374 -1107 -1158 -1070 -671 -741 -533 -1121 -779 -1576 -903 -667 -927 -1179 -1399 -1139 -638 -1149 -829 -637 -793 -1096 -1831 -817 -935 -831 -1280 -934 -1144 -1087 -1127 -775 -920 -798 -1939 -923 -1263 -1418 -824 -870 -1189 -1590 -1087 -978 -904 -995 -1215 -1178 -1437 -660 -1180 -1242 -821 -1069 -1372 -1190 -1040 -1013 -849 -1318 -1766 -1033 -1047 -901 -874 -792 -646 -1181 -831 -1080 -1258 -799 -922 -880 -1026 -911 -1006 -1090 -1008 -1178 -1521 -1704 -891 -1152 -1414 -1537 -889 -683 -895 -697 -988 -788 -1326 -911 -1041 -694 -829 -1251 -1029 -901 -839 -799 -1166 -1156 -587 -1278 -725 -1194 -991 -1064 -589 -772 -831 -1061 -880 -2105 -701 -937 -1534 -919 -1085 -1771 -980 -1162 -1303 -1265 -1294 -1173 -715 -751 -733 -1345 -1337 -984 -1157 -1231 -733 -1108 -930 -859 -1387 -993 -741 -888 -795 -857 -977 -969 -961 -1340 -1024 -1780 -665 -742 -1282 -1004 -1324 -908 -933 -852 -681 -935 -681 -964 -893 -860 -761 -566 -1976 -1262 -1039 -1709 -1050 -981 -691 -762 -1198 -1672 -849 -1220 -1050 -1339 -947 -911 -774 -1365 -1580 -1467 -634 -1178 -977 -1339 -670 -867 -997 -787 -1156 -1170 -952 -1114 -1138 -879 -1559 -508 -1217 -1181 -799 -1030 -891 -1400 -1191 -921 -1289 -1449 -1101 -1196 -1110 -1138 -974 -1389 -1647 -959 -948 -1599 -1349 -780 -952 -896 -1013 -1256 -1570 -1143 -1288 -885 -1288 -655 -1291 -1372 -763 -854 -1564 -847 -1234 -579 -876 -883 -1400 -1149 -2064 -956 -1079 -979 -1710 -1246 -851 -969 -1110 -969 -914 -1183 -595 -1335 -1589 -1415 -1091 -1347 -1178 -1394 -1207 -1484 -1137 -821 -853 -997 -751 -920 -889 -897 -1370 -750 -950 -739 -1595 -1216 -1043 -1099 -954 -709 -804 -1355 -1530 -1157 -841 -1471 -923 -1711 -903 -1459 -823 -868 -1174 -1050 -778 -1096 -794 -984 -1162 -1016 -1658 -1616 -1316 -1372 -496 -1266 -1145 -1692 -1618 -1060 -1179 -611 -1217 -719 -1209 -920 -670 -853 -905 -1140 -1224 -617 -1124 -1706 -1125 -1366 -1292 -951 -1382 -812 -1124 -1313 -983 -452 -1058 -1438 -803 -1013 -573 -875 -945 -1076 -742 -851 -1214 -1036 -1543 -1025 -1156 -1831 -801 -777 -1112 -1217 -981 -1376 -572 -661 -1218 -1068 -1285 -1131 -1216 -1156 -1277 -1464 -1709 -1419 -1222 -1408 -945 -1032 -1273 -947 -605 -1562 -1037 -1087 -1568 -1233 -1498 -1100 -721 -1090 -1011 -992 -919 -1160 -1322 -1102 -1144 -1219 -990 -999 -1810 -1127 -1004 -1579 -1171 -591 -727 -664 -1398 -1415 -945 -1232 -1004 -1112 -1052 -980 -1484 -975 -1015 -990 -646 -1319 -1000 -850 -844 -1264 -809 -1400 -1331 -1002 -1344 -1072 -975 -1061 -1148 -1129 -935 -1165 -736 -584 -1877 -1417 -752 -1098 -1040 -1218 -1012 -1821 -1325 -1165 -1459 -1264 -1052 -1159 -984 -762 -742 -1014 -1565 -1197 -1083 -996 -877 -1019 -1169 -1343 -1221 -1234 -972 -1109 -1313 -808 -1308 -810 -1448 -1170 -1479 -883 -984 -779 -1292 -763 -1277 -976 -1358 -1264 -1273 -1126 -1507 -1115 -1131 -1186 -918 -1365 -1418 -654 -1347 -914 -1372 -951 -1437 -857 -1369 -896 -949 -1464 -1103 -1292 -1279 -857 -1005 -1034 -823 -893 -1020 -1319 -1414 -834 -901 -1344 -1069 -1418 -1509 -785 -1165 -1285 -1853 -1026 -1256 -1250 -1553 -1690 -1054 -971 -931 -756 -910 -1736 -1296 -1101 -579 -359 -764 -1467 -1289 -1380 -1009 -1357 -767 -1288 -1300 -1100 -873 -1147 -1242 -1010 -1213 -1108 -528 -1582 -932 -1048 -1234 -1388 -1475 -1053 -522 -898 -1170 -868 -784 -993 -951 -856 -602 -789 -1161 -961 -881 -817 -1617 -1097 -1085 -1232 -1055 -1118 -1094 -734 -838 -1054 -1068 -1328 -1245 -1205 -1212 -1032 -1423 -1278 -1238 -1216 -1049 -1337 -1223 -957 -876 -815 -974 -960 -1116 -1360 -798 -1409 -1541 -1083 -1176 -1459 -978 -1011 -930 -1551 -1201 -1583 -1210 -974 -1264 -1017 -650 -825 -726 -1305 -659 -1144 -1086 -1014 -1204 -765 -1117 -832 -1103 -1523 -1317 -1127 -1137 -1379 -1666 -1078 -692 -1149 -1255 -833 -1259 -1103 -849 -1360 -686 -678 -1190 -583 -1572 -711 -1479 -1757 -1041 -936 -726 -1389 -562 -1125 -1125 -1835 -746 -1323 -1467 -940 -1174 -973 -1633 -1071 -1120 -789 -1016 -876 -1083 -1271 -1553 -1106 -639 -1010 -1210 -1152 -984 -868 -1115 -1149 -1119 -1350 -1479 -1275 -1896 -1123 -1135 -1151 -694 -802 -1610 -694 -578 -901 -1142 -958 -924 -887 -853 -1503 -1055 -907 -913 -1278 -1454 -781 -1035 -1427 -1162 -1326 -741 -822 -1285 -851 -1000 -919 -1706 -997 -1078 -1031 -1099 -1041 -1679 -1649 -841 -739 -915 -512 -1121 -1196 -872 -1099 -780 -1271 -1249 -934 -748 -871 -2024 -910 -1396 -971 -989 -984 -901 -1332 -1137 -842 -714 -726 -772 -1081 -1055 -1506 -1266 -1325 -1697 -597 -1195 -856 -853 -1032 -994 -1140 -1485 -1157 -1686 -876 -1124 -1483 -1166 -967 -1919 -1205 -1016 -902 -725 -920 -1439 -595 -1281 -1546 -1390 -1042 -1269 -593 -1745 -1445 -1345 -933 -1016 -1428 -1381 -1131 -645 -798 -972 -1591 -655 -1014 -1504 -1141 -759 -709 -1702 -971 -1043 -793 -738 -1507 -571 -955 -1452 -860 -1094 -1446 -1259 -1408 -1479 -1295 -1038 -1174 -838 -857 -1132 -1253 -916 -1168 -1240 -1351 -1160 -1306 -895 -1079 -829 -1167 -1531 -1481 -1171 -1077 -901 -1109 -1079 -825 -938 -797 -1199 -978 -816 -1400 -1288 -1024 -1298 -1287 -1176 -1210 -1163 -1050 -592 -848 -1608 -1227 -1018 -1292 -928 -941 -1349 -1223 -992 -909 -625 -765 -1250 -892 -1095 -945 -1161 -1501 -1204 -884 -651 -1141 -1228 -1333 -1207 -1277 -1074 -1154 -598 -1615 -1048 -1667 -1573 -1001 -1356 -1029 -1218 -964 -1065 -1071 -910 -1001 -608 -1608 -1356 -1211 -816 -672 -1140 -1116 -946 -982 -918 -1483 -1586 -1198 -897 -891 -675 -1066 -609 -1223 -1371 -1113 -1773 -1525 -1172 -1204 -719 -1154 -498 -1128 -1146 -871 -1414 -1643 -995 -1493 -1430 -874 -1573 -1214 -1646 -419 -1229 -1109 -925 -1489 -1037 -1063 -1637 -1327 -749 -1236 -498 -967 -1020 -1218 -648 -1013 -1521 -833 -1747 -1277 -971 -1359 -1248 -991 -1584 -841 -1355 -1310 -1116 -1522 -1123 -1075 -1232 -2242 -1345 -1655 -963 -826 -1043 -1230 -1252 -1058 -1139 -1078 -659 -1136 -835 -957 -1226 -1376 -1706 -529 -1939 -772 -910 -1164 -1171 -1065 -1129 -1444 -1487 -903 -1280 -1444 -1080 -945 -707 -1440 -1355 -694 -1520 -926 -1179 -812 -874 -1055 -1050 -943 -1019 -554 -766 -1773 -1108 -1235 -1046 -856 -1304 -949 -1127 -1279 -789 -1014 -804 -1523 -1252 -1573 -1407 -1551 -706 -906 -1236 -1230 -1562 -1262 -776 -973 -1412 -986 -1731 -1079 -871 -942 -734 -1098 -891 -1258 -937 -1010 -1258 -1149 -1163 -1230 -528 -1159 -1260 -937 -1392 -873 -665 -1164 -945 -524 -1104 -1039 -1138 -1124 -1037 -983 -1087 -1521 -1132 -1140 -1078 -1338 -987 -873 -618 -931 -1112 -664 -830 -860 -1054 -1009 -955 -797 -1421 -952 -1626 -1229 -1084 -830 -1324 -1171 -1294 -1698 -1462 -722 -1397 -928 -855 -1083 -1040 -1005 -1545 -1221 -892 -741 -498 -1535 -1189 -946 -1496 -1035 -621 -874 -801 -1241 -959 -1888 -1464 -873 -762 -1261 -1222 -947 -1026 -643 -1837 -1454 -882 -764 -932 -1390 -763 -804 -1209 -785 -756 -1261 -676 -765 -1075 -1308 -1618 -900 -1673 -1434 -1212 -1511 -821 -953 -1096 -1274 -1356 -868 -806 -1123 -766 -1370 -1206 -1000 -1523 -980 -842 -1643 -1238 -1549 -922 -554 -1028 -1042 -715 -1051 -995 -555 -1014 -1277 -1351 -864 -1387 -1026 -1126 -1619 -1330 -1101 -1461 -1249 -1104 -844 -883 -956 -1668 -1446 -1236 -1339 -1178 -742 -1176 -1438 -989 -1070 -886 -1130 -1063 -1089 -1099 -1248 -1119 -937 -772 -615 -1472 -650 -453 -865 -1209 -1326 -943 -1157 -1710 -1047 -1290 -922 -835 -1484 -1123 -906 -1325 -1266 -893 -1088 -1010 -976 -744 -952 -899 -1300 -1321 -969 -1710 -1111 -739 -919 -954 -1009 -893 -1116 -1253 -1184 -1640 -712 -1384 -947 -939 -1034 -1321 -1666 -813 -1274 -1398 -1003 -1073 -1031 -1358 -656 -1236 -1234 -1113 -831 -1382 -742 -1079 -1004 -1013 -1112 -949 -811 -676 -745 -991 -775 -907 -1212 -1118 -539 -1047 -1052 -773 -1209 -1345 -1344 -1381 -1047 -513 -763 -1583 -1113 -1058 -854 -1295 -896 -707 -912 -1314 -1194 -1170 -894 -1235 -874 -1241 -998 -1656 -415 -882 -1486 -1928 -1227 -1005 -1105 -1458 -980 -1148 -1087 -1553 -1132 -757 -794 -1050 -1064 -845 -890 -918 -666 -1336 -1013 -989 -1162 -1788 -1214 -1092 -1657 -1080 -1189 -1133 -926 -840 -1237 -967 -1041 -1141 -924 -795 -785 -1280 -1028 -1330 -1131 -1035 -899 -1062 -1054 -953 -743 -832 -1667 -1093 -999 -1321 -1338 -1167 -1196 -1311 -1390 -859 -1163 -1183 -1304 -929 -812 -642 -1108 -1103 -1376 -881 -1070 -1123 -668 -732 -1451 -961 -893 -823 -1106 -855 -1245 -1129 -1002 -1232 -799 -966 -900 -951 -1417 -631 -1046 -1454 -1226 -1308 -1424 -783 -1330 -1277 -967 -1094 -893 -1061 -1115 -966 -812 -872 -1224 -1792 -1065 -1280 -1309 -825 -1332 -913 -1092 -914 -1272 -1346 -1049 -1105 -1287 -1170 -1009 -1667 -1076 -1331 -907 -1015 -814 -977 -906 -1125 -757 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/random.txt deleted file mode 100644 index ba056d173..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -3261 -2952 -4652 -4865 -2356 -4234 -3484 -2619 -3450 -3613 -4227 -4677 -3384 -4781 -3721 -5555 -4180 -4573 -3027 -3854 -5685 -2326 -3336 -4593 -3673 -3844 -2591 -5207 -2754 -5725 -4499 -2328 -3276 -5419 -3605 -5347 -4224 -2783 -3421 -3086 -3720 -5164 -3739 -4537 -4241 -4367 -6912 -3692 -2580 -4602 -2837 -4111 -2599 -4801 -2367 -2794 -4281 -4877 -5348 -5492 -3005 -3756 -4680 -3011 -4626 -5513 -6370 -2499 -3046 -3218 -3386 -4850 -4741 -3676 -3168 -5514 -5991 -4424 -3440 -4141 -3339 -6931 -4008 -4647 -3860 -5420 -3219 -5429 -5401 -3299 -4350 -4589 -5387 -3329 -3517 -2976 -3716 -4925 -4458 -3865 -3817 -4398 -3090 -3644 -3496 -3704 -4037 -5358 -2838 -3682 -5540 -3917 -3854 -2139 -5391 -1938 -4220 -4111 -4068 -3399 -3512 -2575 -2724 -4458 -4596 -4108 -2691 -4127 -3578 -2836 -4658 -3316 -4457 -4580 -4408 -4997 -2730 -2769 -3402 -4211 -3333 -3202 -3081 -5208 -3308 -4277 -6203 -4320 -3283 -2949 -4439 -3136 -3857 -3025 -5455 -3438 -2135 -4614 -1729 -3064 -2829 -6248 -4066 -3593 -4591 -5248 -3662 -4668 -5139 -3234 -4561 -4971 -4639 -5124 -6230 -4816 -2365 -3989 -4373 -4607 -1694 -2323 -2570 -5179 -3265 -2332 -3603 -4768 -4085 -4014 -4617 -6779 -4235 -4765 -6840 -2632 -4069 -4254 -2973 -3576 -4599 -4730 -2521 -3713 -4988 -5226 -1704 -4406 -5649 -5439 -4024 -4426 -3921 -3122 -3265 -2590 -2868 -2438 -4328 -3417 -4455 -4860 -5353 -4212 -4044 -4939 -1818 -4391 -4306 -3419 -2671 -4727 -4616 -2950 -3117 -4233 -1917 -3083 -3458 -3442 -3598 -3946 -3726 -2718 -2602 -3127 -3656 -4880 -4967 -3067 -4138 -4000 -3560 -3837 -3719 -4160 -5329 -3864 -4023 -4406 -4965 -4374 -6950 -4551 -4112 -4199 -3904 -5105 -3938 -2427 -4469 -3817 -3673 -4385 -3088 -2419 -2274 -4534 -2238 -3707 -2748 -3582 -2440 -3137 -3616 -3880 -2582 -4209 -2182 -4537 -4414 -4312 -2820 -3412 -3447 -4812 -5364 -5922 -3717 -3066 -3753 -3147 -3074 -4056 -3159 -5118 -3449 -4322 -6326 -4219 -4043 -3885 -8053 -3255 -7552 -4766 -3489 -3783 -3028 -2342 -2926 -6278 -5369 -4487 -4672 -4039 -3766 -3726 -2790 -5323 -4111 -4274 -5933 -3527 -2519 -4862 -5580 -4986 -3229 -6274 -4553 -4268 -5148 -4196 -3060 -2790 -5143 -4873 -3473 -2953 -4342 -2655 -5126 -3011 -5148 -2202 -4292 -4285 -2145 -4032 -3667 -5265 -4418 -6640 -6541 -3880 -2553 -5210 -5463 -3895 -4249 -3658 -2557 -4263 -4240 -3762 -4071 -4605 -4754 -3996 -3510 -4629 -5051 -4417 -3457 -4966 -7370 -2695 -4844 -3895 -4571 -2605 -4424 -2975 -4518 -3460 -5041 -2749 -4247 -4547 -4935 -4553 -3591 -3595 -3880 -4883 -3783 -4571 -4772 -5450 -2436 -5339 -4033 -5303 -4256 -4700 -3352 -2391 -4039 -3756 -4496 -3540 -2889 -3434 -2813 -3296 -5125 -3025 -3840 -5073 -5108 -5194 -3410 -3807 -3545 -4591 -2252 -4692 -2874 -4263 -2367 -5280 -8009 -3446 -2892 -1964 -3352 -4622 -3831 -3674 -5472 -3628 -2783 -3507 -3540 -3552 -5012 -4501 -3628 -3477 -4846 -5363 -4024 -3057 -3839 -4633 -3913 -3894 -3334 -3245 -3732 -3063 -1342 -2965 -3585 -4663 -4619 -4379 -4717 -5361 -3889 -4148 -4904 -4329 -4891 -3647 -3617 -4469 -4180 -3364 -4102 -5440 -3667 -3869 -4429 -3244 -4227 -5831 -4488 -4284 -2704 -2995 -5051 -5445 -4354 -4326 -4439 -4157 -2320 -6315 -3804 -3131 -5112 -2725 -4611 -2133 -4280 -4224 -5061 -5965 -3627 -4103 -3519 -2958 -3815 -4672 -3660 -3733 -3987 -2739 -4174 -3433 -3010 -2828 -3324 -3864 -4984 -3617 -3486 -5635 -6832 -2352 -5095 -3039 -5249 -3031 -4282 -3378 -5576 -1578 -3147 -6944 -5021 -5647 -4983 -3548 -4747 -6636 -4130 -3373 -2576 -5403 -4500 -5116 -3084 -1549 -2975 -3667 -2551 -3739 -2100 -3530 -4013 -3192 -3576 -2970 -4389 -2620 -4173 -6657 -4239 -6059 -4380 -5056 -3473 -4086 -2953 -3629 -3023 -3969 -3241 -4268 -4764 -4680 -6044 -6601 -2937 -2654 -3773 -6595 -5091 -3989 -4419 -3428 -5434 -3927 -4055 -5035 -3939 -2697 -3302 -2804 -3523 -4986 -2581 -3792 -3759 -5437 -4681 -3436 -2455 -3729 -4309 -4288 -5189 -4605 -5690 -4163 -4962 -2645 -3721 -5229 -3673 -4539 -4898 -3367 -4596 -4182 -3974 -3130 -3899 -3998 -4082 -2000 -4702 -5533 -3964 -3592 -3393 -4104 -3824 -4664 -4734 -3823 -6714 -3237 -4105 -4455 -5117 -6173 -4715 -6523 -6163 -4597 -6021 -5617 -4270 -2174 -3347 -5550 -3865 -2908 -4497 -4886 -3748 -4523 -2915 -4451 -3962 -2524 -5079 -5832 -4260 -3329 -4004 -3797 -3926 -4883 -4934 -5140 -3485 -3049 -2924 -5418 -3142 -3686 -5202 -4644 -4860 -3954 -5715 -4219 -3466 -3749 -3735 -4583 -4774 -3092 -5469 -3746 -4260 -2774 -4621 -5785 -4712 -4229 -2783 -4937 -4421 -2349 -5727 -2177 -4724 -3740 -3417 -4664 -3997 -4715 -6023 -3985 -4196 -5254 -7105 -2896 -3736 -3784 -3378 -3160 -3479 -4677 -2668 -4431 -3821 -3170 -6862 -3402 -2785 -4805 -3237 -2910 -4753 -5450 -4535 -4562 -3616 -5718 -3152 -3748 -4217 -5184 -5791 -5620 -2075 -2596 -3207 -4247 -3302 -3362 -3576 -3223 -5154 -4062 -3842 -5425 -5624 -3227 -2940 -3363 -4163 -2506 -5441 -4670 -5923 -5007 -5410 -3709 -5890 -3939 -5958 -4596 -6564 -5669 -6403 -7976 -6434 -4685 -4492 -4421 -6099 -6114 -4856 -3514 -3302 -4983 -2892 -3845 -5112 -4904 -4022 -3926 -3364 -4218 -3887 -4204 -4101 -4175 -5714 -3881 -5175 -2294 -4594 -2565 -4340 -3993 -4091 -3434 -2288 -2768 -3699 -4661 -5498 -6223 -4008 -4575 -6771 -3259 -2970 -4552 -5747 -1998 -4608 -4192 -2442 -4639 -3487 -4198 -6833 -1998 -3563 -3381 -4275 -5899 -6005 -3966 -5182 -3254 -5556 -4079 -4876 -3742 -3620 -3864 -4970 -6280 -4148 -3930 -5210 -5124 -3173 -3992 -3482 -4587 -2949 -3474 -4693 -2379 -2572 -4334 -3816 -4502 -3677 -4076 -3725 -4971 -3111 -2781 -2454 -3580 -3681 -4705 -4160 -6782 -4634 -3361 -6096 -4076 -5176 -4330 -5041 -5059 -5319 -3933 -2677 -3052 -6085 -3545 -4998 -3783 -4488 -5625 -4293 -4320 -2127 -5940 -4425 -5960 -5199 -2911 -3789 -3169 -4724 -3085 -3407 -4397 -3588 -5250 -4710 -4144 -2952 -2850 -6382 -6617 -3227 -4688 -4084 -4119 -2989 -2302 -2165 -3978 -3357 -3792 -4150 -5792 -4674 -5360 -6995 -5052 -3553 -6098 -3753 -3040 -2869 -4810 -3941 -2208 -3987 -4152 -5689 -5092 -3887 -3689 -3668 -4942 -5400 -6372 -4940 -4252 -3580 -6421 -4828 -4187 -3353 -3974 -2758 -5203 -3293 -4671 -3621 -2844 -3015 -4529 -5330 -3220 -4677 -4591 -3871 -3845 -2595 -2977 -2742 -4759 -5897 -3805 -4494 -7514 -4270 -1686 -4728 -5135 -5625 -3412 -4681 -4756 -4377 -2765 -3379 -3517 -3436 -4314 -3184 -4013 -5424 -5167 -5062 -2203 -3519 -3497 -5082 -3921 -3660 -4921 -3527 -3632 -4084 -3514 -5115 -4419 -3912 -3597 -4196 -5377 -5481 -4748 -2964 -2472 -4277 -7741 -5022 -5118 -4991 -5076 -2318 -6830 -3304 -3397 -3790 -3424 -4532 -2705 -4134 -2373 -6053 -4455 -4355 -4985 -3686 -5753 -3234 -3253 -6455 -3317 -3170 -4529 -4547 -4362 -3457 -3320 -3753 -3147 -3831 -2915 -4899 -3458 -4171 -2735 -3793 -5445 -5626 -3742 -2282 -3808 -5347 -4117 -4598 -5207 -4163 -4739 -2943 -2914 -5773 -3895 -3984 -3905 -4126 -3591 -5711 -2982 -3558 -5455 -5890 -4681 -4915 -4645 -3588 -3184 -4329 -2167 -4681 -5378 -4158 -3643 -3192 -3008 -2528 -3077 -3760 -4967 -5857 -4359 -5423 -4922 -4765 -7062 -4179 -2588 -4558 -4663 -5661 -6739 -4547 -4054 -4204 -4950 -3443 -2571 -1696 -2722 -4237 -2779 -2967 -3755 -2830 -3586 -3287 -6366 -2983 -5994 -3599 -4568 -4695 -3645 -2999 -4287 -3800 -4321 -4526 -6131 -3941 -4375 -4745 -4585 -4627 -3101 -4809 -5009 -2485 -4533 -4485 -4118 -4552 -3591 -5671 -6394 -4235 -5197 -3289 -4397 -5610 -5589 -5428 -3163 -4785 -4254 -4997 -2561 -2935 -3420 -3699 -3569 -5592 -2532 -3175 -5199 -3688 -5143 -5623 -2573 -2800 -6344 -4059 -3412 -4392 -3096 -3458 -4089 -3923 -5200 -3975 -4256 -2854 -5359 -3889 -3451 -2731 -3085 -3619 -3307 -4139 -3529 -4199 -4855 -2860 -3992 -4722 -6028 -3370 -4932 -5012 -4466 -3341 -4168 -3802 -4407 -5015 -3978 -4360 -3852 -1890 -2749 -5183 -4619 -3577 -3392 -3975 -3867 -4345 -5084 -3463 -3570 -4286 -3851 -3233 -5666 -4964 -4723 -3811 -3892 -2516 -4159 -3693 -3396 -5050 -2572 -3505 -2768 -4012 -4596 -4640 -5131 -2740 -5498 -4731 -2951 -7156 -6955 -2584 -3992 -2579 -3324 -6280 -5431 -3463 -4271 -2602 -2514 -5569 -4953 -4440 -4045 -4499 -3285 -5984 -5188 -3632 -3490 -2841 -2438 -3621 -2725 -4539 -4589 -3760 -5001 -3592 -4318 -3301 -3617 -4123 -5867 -4608 -3251 -4694 -5034 -4558 -5046 -5111 -5331 -4627 -4377 -2611 -3814 -3182 -3373 -2374 -4921 -4942 -3047 -2100 -6076 -4784 -3026 -3697 -4350 -5071 -6695 -4930 -3975 -2505 -4795 -2877 -4612 -3856 -3657 -2871 -4231 -5881 -3800 -3837 -5439 -3199 -3692 -3976 -1943 -6216 -6019 -4663 -4448 -4960 -2659 -5477 -4092 -3212 -4590 -4062 -2640 -3904 -6054 -4030 -4747 -4704 -2045 -4710 -4287 -5752 -3026 -2366 -3227 -5137 -2513 -4957 -3329 -3523 -4328 -2332 -3391 -5802 -4172 -3019 -3138 -3112 -3809 -3310 -3045 -2860 -1668 -4613 -4002 -6554 -3885 -6264 -5082 -3929 -2854 -5520 -3872 -4568 -2802 -3531 -4817 -5022 -3885 -5053 -2938 -4738 -3873 -6117 -3499 -3806 -5080 -5638 -5225 -4367 -3203 -5889 -3375 -2602 -3396 -3244 -4596 -3267 -4173 -3373 -6427 -6387 -3542 -5446 -4570 -4653 -3250 -4101 -4340 -6223 -2656 -4424 -5567 -5341 -4761 -3846 -3932 -3128 -4706 -4136 -2755 -2513 -3174 -3994 -3324 -3585 -4968 -4476 -4769 -5208 -3332 -5340 -4122 -3088 -3866 -6008 -4793 -3974 -4756 -2890 -4917 -5415 -2946 -6135 -3654 -2386 -4254 -5145 -2993 -3661 -6572 -2287 -4153 -2916 -6080 -3151 -4310 -3614 -2504 -3689 -2242 -4111 -4550 -3861 -4718 -4169 -3715 -3041 -3118 -3128 -3674 -3970 -5472 -2845 -3251 -4897 -3641 -3556 -4330 -4138 -3967 -5032 -5453 -2631 -3725 -3933 -4192 -3277 -5885 -3492 -2924 -3587 -3988 -3719 -3929 -4548 -2170 -3523 -3367 -4034 -4131 -3702 -2872 -4831 -2536 -4189 -2753 -3970 -5044 -1968 -3923 -3678 -4734 -5169 -3566 -3806 -4737 -5483 -3260 -2672 -3038 -4210 -3549 -4074 -6172 -4162 -3755 -4880 -4225 -4003 -3094 -3481 -5547 -4428 -3461 -2496 -4879 -5618 -4245 -5440 -3764 -5424 -5438 -2899 -3814 -4787 -4237 -2996 -5842 -5515 -4119 -2816 -3467 -3930 -4921 -2842 -4786 -2535 -3683 -3514 -5048 -4777 -3533 -2363 -3680 -4364 -3879 -2769 -3987 -4854 -3408 -3752 -4549 -3335 -6879 -4921 -3382 -3064 -4205 -3185 -2992 -3794 -4019 -3847 -4493 -3122 -5048 -6664 -3597 -2699 -3990 -5853 -4401 -6884 -4663 -3397 -1933 -5421 -4100 -3580 -3276 -3794 -4251 -3067 -4373 -5067 -3943 -2530 -4769 -4076 -5418 -3848 -4076 -3830 -1890 -4764 -5323 -2895 -5434 -7019 -4656 -2732 -3853 -2337 -5178 -4087 -3624 -5377 -4917 -2849 -3602 -6824 -3735 -3745 -2494 -4229 -4321 -4140 -2629 -3247 -3984 -4370 -4245 -4248 -3599 -4144 -2589 -2603 -4517 -4448 -3616 -6099 -3174 -3169 -6716 -3354 -3549 -4442 -2798 -3894 -6005 -4329 -5874 -5612 -4924 -4656 -3391 -4332 -3466 -4311 -3455 -4227 -3999 -4225 -3199 -1952 -2865 -4043 -5113 -7518 -5761 -4368 -5342 -4503 -3611 -3860 -5334 -4781 -2884 -3886 -4182 -3817 -4675 -6447 -3707 -4243 -3311 -4756 -4191 -5099 -3257 -3608 -5563 -3359 -3131 -3607 -3707 -4712 -6132 -3234 -5049 -3828 -2637 -3619 -2230 -4987 -3186 -4489 -4714 -3703 -2992 -4200 -4910 -5176 -4184 -4921 -2677 -2857 -3799 -2706 -4341 -4795 -5846 -4421 -3823 -4907 -5229 -3321 -4553 -2263 -4328 -4598 -4531 -3752 -2947 -5614 -3662 -3539 -4617 -5635 -4555 -5327 -3626 -3964 -2890 -5981 -3480 -4662 -3439 -4069 -3445 -3977 -4200 -3185 -5044 -5344 -3147 -3341 -5024 -2971 -5638 -3727 -5372 -2004 -3818 -3964 -5884 -3460 -2445 -3552 -2635 -3814 -3168 -3970 -3383 -3953 -7423 -6100 -4515 -4145 -5076 -3247 -4061 -4507 -3776 -4439 -3214 -1220 -4616 -4147 -5248 -5330 -2769 -2677 -4001 -4677 -3985 -4037 -3591 -3771 -3697 -4442 -4523 -5624 -3960 -4757 -5379 -3493 -1780 -3334 -5636 -4102 -3891 -4604 -3791 -4517 -2751 -4478 -3118 -5961 -6662 -4203 -4340 -3273 -6217 -2347 -3528 -5101 -5609 -4257 -3906 -3471 -2122 -3163 -5950 -2345 -3715 -2507 -3773 -3737 -3644 -3401 -3733 -6365 -2024 -6616 -4133 -3040 -2989 -2860 -3264 -2542 -4735 -5867 -4149 -3186 -4859 -2482 -4286 -4350 -5315 -2773 -3608 -3196 -3141 -5117 -2642 -1695 -3567 -4786 -3043 -4663 -4780 -4813 -3640 -4979 -5277 -3410 -3562 -3867 -5836 -5246 -3065 -4631 -3003 -4090 -3723 -3263 -2504 -4143 -3604 -4011 -2305 -2066 -2721 -4093 -3550 -4290 -4269 -4722 -7734 -4896 -3853 -2943 -2996 -5424 -4602 -4855 -5330 -3064 -2379 -4602 -2944 -3989 -4854 -3353 -3603 -4630 -6435 -3874 -5308 -3209 -3719 -2417 -4488 -4834 -4277 -5445 -3702 -4391 -5582 -3110 -3338 -5782 -4436 -3590 -3709 -3607 -3733 -4220 -2242 -3387 -2949 -4008 -2581 -2643 -5494 -4019 -4436 -1821 -5678 -5583 -2577 -2852 -4153 -4965 -3571 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k4/trained_ddqn/best.pt deleted file mode 100644 index 1f2afae4f3c9f7933012dff4d36783b21fcfdde0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/trained_ddqn/config.yml deleted file mode 100644 index 58de4fcb6..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k5/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 11, 21, 31, 41] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/dqn.txt deleted file mode 100644 index 75e4e6b12..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -688 -955 -1559 -1579 -909 -1113 -1097 -992 -1445 -1220 -1088 -797 -966 -808 -944 -996 -1498 -566 -1328 -853 -1059 -1263 -815 -1015 -1228 -1158 -666 -1183 -930 -1606 -432 -1039 -1284 -1026 -455 -673 -666 -1335 -1074 -1180 -952 -1043 -1191 -883 -1537 -1409 -812 -1044 -1376 -611 -1191 -1385 -1137 -1064 -816 -1378 -979 -1000 -764 -969 -1137 -1100 -562 -1389 -836 -1140 -970 -1345 -1188 -1338 -846 -1053 -945 -1018 -1118 -438 -1232 -327 -883 -1071 -1062 -1269 -1221 -1631 -1236 -1009 -927 -871 -1274 -904 -1202 -1440 -1376 -1122 -1441 -658 -932 -1266 -1245 -1065 -1143 -767 -1257 -852 -764 -799 -863 -1075 -859 -966 -998 -1312 -1153 -670 -1086 -1453 -1264 -1074 -722 -670 -716 -1182 -832 -894 -744 -1285 -1145 -780 -986 -679 -1059 -762 -1406 -756 -629 -1183 -975 -768 -1225 -1210 -1107 -630 -1619 -1083 -667 -1025 -883 -1664 -893 -1463 -1364 -822 -693 -1006 -999 -955 -1184 -1023 -383 -1160 -1392 -1187 -698 -1026 -1210 -1249 -839 -1362 -814 -1150 -1073 -996 -1196 -1005 -1091 -1006 -1377 -1297 -924 -1939 -535 -993 -1449 -1208 -909 -1174 -1009 -894 -1308 -802 -980 -1062 -947 -856 -1373 -904 -613 -1259 -577 -1216 -1230 -781 -831 -958 -861 -906 -883 -798 -949 -1276 -991 -1453 -925 -949 -890 -737 -1397 -957 -1089 -1239 -1560 -853 -942 -962 -834 -1658 -1261 -1144 -1342 -895 -894 -1059 -1282 -1034 -1189 -465 -1221 -1048 -1188 -830 -728 -728 -1073 -1507 -1222 -1121 -1359 -1405 -1255 -851 -953 -959 -1465 -893 -2021 -833 -1038 -1021 -1239 -1148 -1476 -1167 -763 -831 -1286 -1554 -1117 -1172 -629 -1213 -1005 -1795 -1029 -832 -1212 -1348 -1349 -753 -1254 -1046 -657 -772 -819 -1509 -1256 -917 -1343 -1294 -1318 -1156 -1437 -681 -1371 -1485 -1015 -1247 -1197 -798 -1016 -1066 -1245 -1551 -1085 -916 -1004 -885 -965 -1196 -1094 -469 -672 -827 -1971 -800 -1748 -1512 -711 -1113 -1866 -1031 -1278 -946 -1130 -1115 -1107 -988 -700 -1208 -1128 -590 -830 -1109 -1568 -547 -638 -953 -914 -1257 -1189 -1872 -1100 -908 -844 -1154 -1078 -971 -977 -1248 -856 -1301 -1395 -1454 -1271 -933 -1155 -1783 -470 -1017 -557 -1053 -942 -1199 -885 -1084 -1106 -833 -1303 -834 -799 -552 -1097 -1038 -1267 -1103 -1022 -805 -1325 -1091 -1047 -1173 -1012 -804 -737 -1189 -922 -602 -1146 -810 -1192 -1026 -1371 -1136 -712 -1409 -1226 -841 -1187 -1486 -893 -956 -979 -1057 -1425 -750 -1303 -1143 -1035 -1426 -1933 -813 -1805 -536 -1355 -1139 -1009 -1685 -1283 -1369 -896 -1337 -1423 -1276 -778 -1342 -794 -1025 -1060 -699 -1290 -1216 -1651 -1164 -911 -1158 -846 -1083 -914 -1188 -1323 -1122 -1238 -820 -1343 -1316 -1239 -1006 -1062 -1333 -1093 -1194 -1167 -848 -1032 -645 -887 -1071 -961 -1842 -1060 -1155 -608 -1151 -1329 -1762 -756 -884 -646 -991 -719 -1121 -902 -945 -1119 -867 -1033 -999 -1049 -1257 -1324 -859 -970 -1097 -1310 -719 -1517 -1259 -946 -1131 -864 -810 -1013 -1214 -1292 -657 -1792 -1859 -675 -1128 -677 -833 -1073 -843 -947 -1202 -1225 -1185 -1099 -769 -774 -924 -613 -1038 -1062 -1088 -1229 -1286 -665 -948 -1183 -1059 -758 -1129 -954 -1462 -970 -892 -711 -594 -1207 -703 -1214 -886 -868 -1269 -1055 -1044 -1126 -619 -1227 -1086 -980 -1032 -1095 -476 -1118 -786 -671 -1369 -2033 -889 -1184 -1315 -1304 -979 -1701 -1413 -1194 -1040 -1331 -1106 -1559 -1596 -741 -1093 -1520 -883 -778 -1406 -1042 -923 -1296 -704 -743 -1157 -1217 -1312 -1307 -1174 -1216 -820 -534 -851 -1141 -802 -901 -1152 -1053 -982 -1405 -1374 -1069 -1661 -815 -1757 -840 -1274 -1524 -1217 -1188 -707 -1399 -720 -1064 -1021 -836 -832 -1398 -898 -997 -980 -1559 -956 -773 -731 -716 -1585 -1578 -876 -858 -1673 -662 -845 -621 -689 -934 -1076 -1462 -643 -864 -957 -804 -1005 -970 -1550 -1176 -1177 -805 -1083 -996 -419 -1181 -1048 -1087 -1099 -979 -1329 -610 -1096 -1220 -1221 -776 -1113 -1191 -839 -1480 -1285 -1370 -988 -1366 -807 -1102 -962 -820 -991 -1065 -792 -1178 -1012 -497 -1320 -1196 -874 -684 -978 -1091 -744 -1146 -1990 -1160 -1006 -1271 -1169 -719 -987 -789 -803 -1116 -1054 -1204 -1124 -852 -1100 -987 -1438 -1055 -1041 -1204 -731 -1065 -1345 -1356 -884 -852 -1230 -1243 -753 -1298 -719 -611 -588 -793 -1029 -937 -1438 -853 -1397 -1198 -1100 -994 -888 -884 -1223 -818 -1223 -803 -1348 -1452 -658 -1383 -844 -1015 -913 -905 -1243 -1190 -1040 -1029 -1488 -1152 -902 -1563 -1192 -1114 -899 -830 -1436 -834 -965 -1018 -749 -1582 -686 -1160 -779 -1096 -1328 -1145 -826 -865 -1567 -668 -1347 -795 -779 -875 -1145 -1369 -676 -640 -1180 -939 -1258 -1380 -902 -1099 -1818 -1146 -1082 -1179 -1714 -1136 -1423 -860 -1041 -883 -1124 -612 -912 -959 -1158 -1150 -1483 -1564 -1237 -923 -1083 -807 -1348 -946 -1176 -683 -958 -857 -1218 -1176 -696 -1017 -885 -696 -639 -1765 -839 -1257 -1030 -937 -1058 -1154 -1429 -644 -818 -1301 -1235 -1421 -999 -1381 -1538 -1170 -1111 -958 -1434 -1269 -858 -1079 -820 -947 -909 -1190 -1606 -824 -1474 -1080 -935 -579 -997 -1113 -1013 -696 -915 -1251 -990 -1126 -1304 -1145 -968 -849 -1070 -897 -882 -529 -881 -1181 -1178 -1401 -989 -648 -1671 -718 -1565 -411 -1353 -886 -621 -978 -803 -1005 -1032 -1214 -1355 -1170 -1307 -620 -1011 -1633 -1103 -971 -1354 -1063 -1086 -1314 -1075 -1157 -1125 -901 -1186 -1026 -1201 -1105 -762 -780 -841 -1171 -1303 -736 -1191 -1228 -784 -1389 -942 -1167 -916 -1167 -626 -1379 -1006 -1052 -1110 -665 -1427 -1573 -1482 -1118 -1562 -1312 -1939 -1051 -1115 -850 -1689 -805 -1079 -1040 -897 -1106 -925 -1447 -1277 -1060 -1208 -2027 -1350 -1215 -950 -1151 -1285 -1241 -714 -757 -1459 -1178 -1018 -1033 -1150 -1143 -1151 -1207 -1402 -1153 -719 -1186 -1265 -1135 -1393 -1025 -999 -1310 -1250 -1073 -1896 -1114 -1018 -838 -1179 -1275 -1054 -1092 -1348 -1556 -1112 -1195 -1021 -939 -773 -1167 -1251 -1655 -1297 -779 -955 -721 -1080 -1343 -799 -832 -1850 -1323 -889 -1192 -565 -1283 -863 -1031 -971 -841 -689 -1300 -996 -781 -1002 -1581 -420 -1272 -1064 -1153 -766 -1091 -797 -744 -1247 -1376 -754 -916 -1235 -1073 -1172 -878 -1008 -1212 -1032 -1234 -1738 -822 -948 -520 -1103 -1012 -676 -960 -1210 -1115 -1537 -1784 -1040 -957 -654 -1166 -1293 -1088 -1776 -1185 -758 -1101 -956 -1043 -920 -1407 -1018 -1055 -1042 -1190 -1433 -1341 -717 -1244 -1319 -707 -1169 -704 -1295 -895 -843 -967 -1523 -1136 -927 -1131 -981 -1584 -1390 -1148 -765 -490 -891 -1366 -1367 -848 -1500 -694 -1316 -1197 -1654 -1395 -371 -992 -1079 -1362 -613 -1262 -838 -1485 -1125 -1102 -764 -888 -1165 -808 -1005 -744 -992 -1192 -937 -1062 -998 -842 -667 -1345 -1266 -1626 -590 -964 -832 -1220 -708 -1630 -1096 -880 -715 -1167 -731 -953 -1004 -946 -1555 -1243 -986 -1032 -825 -1096 -962 -1269 -587 -968 -1713 -1234 -1131 -1124 -674 -1746 -939 -1042 -1312 -1135 -1208 -924 -1613 -993 -1340 -1036 -1322 -775 -1522 -1183 -1170 -1375 -1278 -974 -1335 -824 -681 -923 -941 -645 -845 -1242 -1271 -1055 -924 -1202 -846 -730 -1312 -862 -969 -1135 -1143 -1339 -963 -1205 -1214 -1059 -977 -1029 -1193 -1045 -1170 -1369 -1173 -1693 -1193 -847 -1262 -768 -1175 -1117 -680 -1000 -1206 -816 -1464 -814 -1055 -759 -811 -1296 -1305 -1117 -863 -1039 -1396 -624 -1348 -1016 -1240 -1533 -1794 -1065 -1241 -1123 -1279 -1232 -889 -1020 -1156 -1065 -1151 -1138 -1187 -1156 -1078 -531 -1121 -841 -1209 -946 -790 -1549 -727 -923 -929 -1274 -885 -1126 -1248 -826 -794 -1516 -1027 -918 -1038 -1112 -1216 -1326 -1538 -916 -1544 -813 -1666 -1112 -1009 -765 -628 -1017 -793 -1294 -1568 -1011 -1193 -1308 -1518 -1347 -966 -1410 -502 -1289 -1136 -730 -1024 -1025 -1041 -961 -1206 -709 -918 -1405 -1030 -718 -986 -916 -868 -798 -1407 -1592 -762 -1116 -1354 -1746 -719 -1530 -1326 -1664 -849 -1510 -748 -810 -966 -892 -1475 -1133 -1001 -740 -927 -975 -996 -910 -833 -1703 -814 -731 -1225 -1189 -1114 -1075 -1308 -688 -1111 -1005 -1292 -945 -1370 -645 -911 -902 -1222 -806 -1249 -1181 -711 -967 -954 -568 -1039 -961 -785 -1107 -1510 -915 -1522 -1746 -786 -1376 -1331 -919 -969 -1231 -1236 -863 -838 -1209 -1413 -1146 -1222 -1158 -901 -1678 -1140 -675 -852 -1097 -797 -1077 -1520 -1299 -1277 -1500 -954 -1364 -1389 -899 -1242 -833 -890 -874 -889 -1380 -1167 -1198 -817 -1180 -942 -1181 -984 -844 -1476 -1155 -1187 -1312 -779 -854 -1020 -640 -1071 -982 -1708 -1106 -1103 -1884 -965 -690 -900 -1275 -1053 -1140 -958 -899 -837 -1239 -1063 -907 -993 -921 -1515 -1392 -1364 -936 -674 -478 -1234 -1017 -888 -858 -1269 -904 -1127 -1130 -611 -860 -1221 -1016 -457 -1398 -860 -596 -1266 -1516 -1239 -1151 -958 -973 -1422 -1147 -619 -1208 -1236 -829 -812 -1534 -1099 -1214 -649 -1618 -569 -1090 -1113 -892 -796 -903 -861 -1142 -1013 -1576 -663 -875 -408 -1511 -1084 -904 -1191 -724 -901 -1079 -770 -1456 -811 -721 -1132 -444 -1443 -682 -1322 -1079 -814 -1213 -657 -580 -766 -1076 -1035 -678 -1061 -693 -1085 -1338 -1173 -869 -1164 -801 -1209 -951 -956 -1472 -800 -1244 -1321 -1161 -1320 -957 -661 -1273 -1464 -784 -814 -1221 -1049 -1172 -1146 -1117 -1051 -1785 -999 -1012 -1024 -1119 -462 -927 -846 -883 -1795 -1601 -900 -917 -1274 -1596 -1210 -455 -1082 -938 -575 -1107 -1346 -608 -1137 -1157 -1451 -707 -917 -1035 -918 -1030 -954 -864 -1319 -1357 -830 -1237 -798 -1179 -1105 -768 -1313 -894 -649 -1032 -1186 -916 -1049 -781 -1040 -1341 -1187 -1104 -1319 -1112 -690 -1508 -734 -945 -1365 -727 -1005 -1075 -1566 -1121 -861 -1200 -689 -1304 -1552 -1098 -973 -1072 -1003 -927 -1240 -1144 -843 -808 -1180 -1171 -820 -1119 -1013 -987 -1324 -1300 -830 -1678 -737 -1267 -955 -741 -863 -972 -1046 -931 -1428 -1852 -699 -522 -1215 -1337 -1607 -1045 -1469 -1247 -676 -907 -1039 -1518 -1402 -1290 -1495 -1134 -820 -867 -1019 -994 -818 -1041 -678 -1134 -1163 -1467 -1343 -927 -1337 -1072 -1463 -1375 -299 -815 -1142 -1173 -727 -1692 -978 -1229 -1285 -1092 -1543 -1042 -458 -1061 -1540 -1421 -1140 -1335 -1461 -1248 -1093 -729 -1287 -1144 -1381 -1023 -1013 -935 -666 -1645 -1570 -1133 -890 -783 -1141 -1390 -750 -1002 -1523 -1439 -1142 -1322 -1187 -999 -1075 -1497 -784 -1137 -616 -501 -762 -1038 -996 -1130 -912 -1159 -995 -901 -776 -1137 -1207 -1452 -707 -889 -826 -791 -1136 -1445 -1502 -1150 -1069 -917 -641 -1058 -795 -1515 -986 -935 -977 -1367 -528 -731 -1098 -1241 -820 -560 -771 -1551 -1042 -1229 -1043 -1342 -1009 -906 -632 -1304 -564 -582 -1324 -1343 -1062 -1013 -799 -1011 -740 -1170 -1216 -695 -981 -1537 -787 -1549 -555 -1129 -869 -1158 -1074 -730 -505 -647 -1298 -799 -1415 -984 -1116 -1206 -1360 -1250 -1084 -841 -404 -908 -969 -1097 -1095 -1120 -856 -1899 -836 -647 -1185 -1020 -973 -1398 -863 -1546 -968 -966 -800 -1373 -657 -801 -1332 -812 -1471 -895 -605 -1269 -1167 -923 -598 -1008 -1273 -718 -974 -952 -704 -1322 -748 -1032 -1015 -731 -1382 -876 -798 -568 -857 -1302 -1346 -1611 -1306 -1085 -1241 -1039 -1247 -1339 -1106 -1048 -1602 -960 -699 -936 -808 -1142 -871 -1125 -1136 -1473 -964 -1061 -1248 -1415 -845 -965 -760 -1005 -1468 -1442 -729 -801 -694 -1015 -955 -1010 -755 -1183 -864 -1162 -1387 -990 -1320 -906 -676 -1291 -855 -928 -483 -1077 -1130 -734 -1538 -1188 -703 -1890 -1541 -1211 -994 -1193 -1128 -788 -1296 -854 -971 -1115 -1100 -938 -826 -731 -1134 -786 -951 -615 -1160 -1135 -1355 -804 -1097 -950 -1640 -750 -1435 -660 -1009 -931 -1614 -1257 -887 -422 -753 -1502 -1426 -1801 -923 -1263 -731 -807 -823 -942 -1386 -906 -1233 -616 -1165 -1281 -739 -715 -976 -977 -1369 -922 -872 -1108 -714 -927 -1235 -1434 -819 -1078 -970 -1183 -826 -1161 -1124 -1191 -1157 -854 -1062 -1291 -1537 -1372 -1022 -1079 -1092 -869 -900 -896 -627 -931 -856 -1140 -914 -777 -1340 -1426 -932 -992 -1042 -867 -826 -1211 -1241 -1399 -1093 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/optimal.txt deleted file mode 100644 index 5ad9e3e7a..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -656 -536 -912 -1076 -623 -995 -1097 -742 -1252 -929 -913 -1083 -923 -900 -1284 -1539 -1118 -1155 -1126 -1080 -1198 -1352 -1182 -669 -1154 -805 -845 -601 -1227 -1242 -851 -1192 -984 -1345 -1541 -1126 -666 -910 -1074 -1278 -968 -1099 -807 -388 -950 -556 -1614 -1060 -964 -611 -629 -1267 -718 -1126 -1162 -1152 -777 -838 -1309 -1013 -1191 -821 -1434 -1133 -1139 -1285 -812 -1218 -819 -1375 -1080 -1069 -837 -1306 -1115 -1105 -1177 -791 -1022 -886 -487 -997 -893 -1230 -953 -841 -1004 -1292 -1193 -592 -938 -494 -1384 -1602 -755 -900 -800 -1060 -1280 -1065 -1241 -1139 -1529 -1192 -863 -1902 -1141 -1383 -935 -916 -907 -1312 -656 -680 -823 -1374 -764 -1018 -845 -1383 -848 -938 -908 -1647 -1120 -1384 -1307 -570 -1138 -806 -1299 -873 -1202 -1179 -1036 -841 -1130 -992 -1593 -1440 -1391 -1007 -1014 -1106 -1185 -1747 -1173 -920 -894 -1304 -1276 -971 -777 -1221 -1216 -1170 -1097 -978 -821 -1193 -702 -1215 -1177 -876 -998 -958 -844 -1185 -1282 -768 -646 -1215 -1048 -702 -988 -1142 -822 -964 -1122 -841 -1371 -1180 -1048 -1225 -1120 -1139 -944 -817 -1092 -963 -807 -971 -827 -1189 -1161 -904 -1033 -981 -940 -1230 -1033 -1290 -831 -1066 -994 -1623 -963 -1113 -1055 -1192 -1087 -1207 -1340 -978 -731 -1233 -1279 -1118 -1579 -1182 -1216 -853 -973 -1067 -1516 -766 -1137 -1604 -1086 -1316 -1411 -1066 -1035 -829 -875 -727 -1007 -1078 -916 -730 -719 -1211 -921 -946 -1405 -1369 -1657 -1339 -1218 -1137 -1031 -780 -962 -1106 -1316 -1018 -1403 -633 -1028 -1313 -1459 -1327 -872 -892 -1286 -1264 -872 -1243 -853 -790 -812 -1162 -1029 -1493 -1159 -380 -1488 -1027 -1045 -1027 -1575 -911 -1230 -1607 -1002 -1053 -734 -971 -882 -1206 -1437 -1232 -877 -598 -822 -1239 -1199 -1698 -1176 -717 -922 -1551 -617 -849 -1079 -1119 -523 -1212 -936 -1062 -794 -649 -1135 -1260 -1095 -1093 -685 -946 -1426 -1013 -1096 -1358 -765 -610 -1168 -781 -1366 -1116 -838 -941 -837 -655 -673 -819 -813 -1142 -982 -896 -970 -709 -1379 -1359 -955 -859 -1159 -1047 -1374 -800 -1678 -691 -828 -1242 -1012 -883 -1015 -1264 -921 -614 -581 -1034 -1040 -901 -775 -1461 -869 -1028 -1120 -998 -1535 -908 -857 -951 -951 -652 -926 -1286 -866 -1323 -1303 -1285 -1151 -757 -1151 -814 -911 -1156 -905 -1131 -1302 -1322 -832 -1318 -1512 -687 -760 -1202 -935 -570 -1584 -1061 -912 -854 -840 -1368 -882 -1064 -1386 -1119 -861 -1317 -1265 -1529 -1082 -1318 -1298 -1168 -1281 -1098 -843 -930 -919 -735 -682 -1203 -605 -1442 -1068 -1001 -1359 -1342 -791 -1085 -850 -1162 -829 -1000 -936 -1429 -1070 -1161 -995 -583 -1120 -1650 -1032 -672 -965 -1362 -754 -996 -1157 -753 -803 -1379 -977 -1491 -961 -719 -1136 -1241 -946 -1171 -933 -866 -1338 -957 -1195 -960 -1053 -891 -875 -1723 -1333 -1374 -956 -718 -831 -1136 -1155 -1227 -1234 -1363 -844 -1152 -1589 -1510 -638 -1193 -954 -1173 -957 -737 -790 -1421 -747 -922 -641 -1233 -1352 -915 -1105 -885 -1826 -1683 -1176 -672 -1099 -779 -980 -934 -1349 -846 -1062 -1250 -1425 -1231 -747 -1299 -1288 -1331 -952 -1236 -898 -1015 -1112 -903 -755 -1175 -719 -1496 -836 -1342 -1292 -681 -838 -1662 -861 -929 -910 -1164 -943 -686 -927 -576 -1236 -1892 -763 -1316 -1127 -988 -986 -1187 -933 -944 -1113 -1427 -1161 -995 -1501 -1032 -941 -959 -996 -1252 -655 -1082 -961 -1114 -1740 -1193 -1536 -834 -1096 -672 -1792 -922 -849 -954 -914 -757 -1039 -955 -1239 -1453 -963 -790 -790 -824 -694 -951 -804 -1030 -822 -848 -892 -611 -1054 -1168 -1416 -928 -946 -864 -837 -1021 -911 -756 -821 -1000 -878 -934 -939 -1535 -1051 -945 -1750 -967 -686 -1197 -1132 -1091 -998 -1183 -621 -1036 -1053 -1594 -1185 -1057 -1016 -866 -1202 -853 -1662 -1130 -1166 -837 -1135 -888 -1140 -990 -925 -1043 -766 -1199 -1162 -1154 -1081 -935 -903 -1404 -980 -1602 -1212 -886 -946 -1436 -748 -1073 -1520 -1009 -674 -777 -865 -1304 -1604 -1623 -605 -983 -836 -1483 -1082 -1356 -880 -1271 -1439 -777 -1168 -1191 -811 -985 -818 -835 -783 -913 -1353 -1194 -855 -1139 -1204 -1131 -1011 -569 -1217 -826 -1473 -1025 -1045 -1259 -957 -1193 -1370 -661 -852 -1069 -1097 -819 -766 -665 -1016 -1213 -1198 -1046 -853 -1438 -419 -1266 -1296 -794 -1114 -1509 -1191 -1044 -893 -753 -968 -1306 -1312 -680 -1097 -785 -927 -768 -1002 -870 -1084 -1040 -738 -1387 -868 -1049 -787 -1305 -891 -963 -923 -1019 -1352 -1135 -1449 -835 -698 -1126 -1279 -1562 -1206 -888 -931 -1121 -1315 -1300 -863 -1490 -795 -942 -930 -1022 -1073 -1203 -1000 -1244 -1270 -1172 -776 -989 -1040 -739 -1116 -1338 -949 -781 -1018 -1171 -977 -687 -972 -1266 -1342 -1163 -853 -611 -1348 -795 -938 -1081 -525 -619 -1059 -1627 -1278 -939 -1174 -1019 -838 -1137 -1229 -755 -1176 -1103 -1224 -1090 -1470 -960 -1186 -1030 -1373 -1054 -1240 -1519 -788 -1314 -868 -996 -1330 -1302 -1488 -864 -866 -1863 -958 -1091 -1351 -1448 -907 -406 -561 -944 -826 -860 -1350 -730 -1386 -912 -1164 -1175 -1113 -1310 -639 -915 -970 -563 -859 -890 -1274 -742 -1046 -1369 -722 -843 -957 -1219 -893 -1026 -1000 -974 -1347 -906 -885 -1271 -624 -1369 -1441 -1066 -1054 -886 -1058 -850 -679 -971 -868 -1509 -955 -1136 -1028 -1375 -1300 -1475 -1045 -973 -1644 -1088 -700 -926 -509 -1273 -973 -530 -624 -1178 -919 -793 -900 -1695 -1160 -1213 -1068 -892 -1251 -821 -1003 -1112 -1011 -756 -1187 -856 -846 -1108 -1547 -1091 -1315 -1309 -542 -1025 -1234 -1223 -1552 -498 -1689 -876 -805 -663 -913 -421 -974 -1038 -1491 -808 -872 -969 -956 -1113 -1588 -1100 -736 -1055 -593 -1572 -958 -1132 -988 -1471 -1141 -1069 -827 -1593 -1019 -936 -1320 -1167 -1419 -1186 -792 -1482 -1541 -1391 -1426 -1029 -1226 -714 -763 -1288 -1180 -941 -645 -1054 -681 -1113 -891 -1365 -1143 -982 -1461 -1233 -1137 -877 -771 -573 -1186 -1190 -737 -1268 -1030 -866 -815 -954 -947 -1080 -643 -1307 -1446 -851 -706 -1220 -1097 -1089 -1045 -863 -861 -832 -1771 -1599 -696 -1304 -1035 -737 -1134 -1141 -1230 -500 -859 -853 -916 -1054 -822 -498 -823 -906 -1576 -969 -1108 -1193 -822 -703 -1379 -1088 -907 -1378 -844 -763 -1115 -1124 -1190 -1586 -924 -1010 -1046 -961 -883 -1295 -793 -1593 -1101 -814 -1051 -1130 -1452 -1325 -1201 -578 -1466 -1028 -946 -1156 -802 -1277 -636 -982 -1529 -986 -1016 -785 -991 -1528 -866 -1350 -1660 -1138 -1376 -1216 -1328 -1198 -891 -1301 -1189 -1006 -1331 -881 -1134 -988 -886 -648 -1316 -773 -980 -813 -1071 -774 -668 -1028 -712 -1190 -791 -1120 -635 -1320 -715 -837 -634 -1524 -1560 -1347 -834 -786 -1050 -2087 -1838 -909 -1323 -751 -664 -952 -1318 -1386 -1176 -945 -997 -886 -702 -1200 -1506 -1412 -1591 -920 -1017 -1248 -734 -1355 -1249 -1228 -1453 -854 -878 -1088 -1508 -1407 -699 -1023 -1066 -1535 -1413 -917 -851 -1125 -1578 -931 -1088 -906 -1540 -966 -1401 -1236 -1329 -1312 -1911 -623 -474 -843 -1103 -1069 -1220 -784 -1077 -1663 -1178 -756 -1428 -1027 -1016 -971 -541 -1136 -1010 -937 -994 -1001 -736 -891 -1351 -928 -1088 -1121 -1042 -898 -1093 -580 -744 -1273 -1449 -1105 -957 -941 -1203 -1094 -1070 -1223 -496 -1438 -1354 -1018 -1097 -1055 -759 -1267 -1024 -896 -2124 -1682 -923 -1232 -1336 -1155 -1388 -738 -1533 -1176 -1649 -809 -1285 -1064 -1497 -764 -859 -706 -1218 -1405 -1372 -1138 -885 -873 -1271 -1092 -837 -1294 -1265 -1083 -847 -951 -735 -1147 -1410 -1231 -1349 -1324 -731 -1131 -867 -1022 -550 -1201 -988 -1241 -1257 -902 -797 -1143 -1859 -1666 -1153 -626 -1066 -655 -767 -813 -838 -1360 -1011 -1185 -473 -679 -1193 -1602 -1117 -1039 -891 -971 -730 -1367 -897 -941 -1308 -1020 -1191 -1436 -862 -1215 -1112 -876 -761 -964 -1051 -971 -959 -752 -944 -958 -946 -1169 -806 -1372 -553 -1021 -743 -1151 -1040 -915 -1021 -980 -1024 -1128 -811 -1139 -656 -1066 -1299 -871 -1423 -1143 -746 -412 -788 -796 -1181 -1210 -661 -946 -1757 -1244 -936 -935 -810 -1704 -1090 -905 -913 -986 -1200 -751 -1130 -1224 -745 -1191 -1061 -707 -1632 -945 -1240 -778 -1070 -774 -1835 -941 -939 -1244 -981 -1376 -903 -1489 -1194 -776 -1321 -1119 -979 -1260 -1036 -1400 -1043 -1400 -794 -1112 -1046 -1012 -1278 -1079 -958 -1171 -658 -1110 -1572 -1459 -842 -1333 -1435 -1112 -1380 -1177 -997 -1050 -1049 -797 -1181 -745 -1229 -874 -1243 -1539 -1283 -1114 -838 -1420 -1009 -1510 -1445 -762 -943 -723 -853 -1040 -898 -983 -726 -1447 -974 -1431 -1444 -1057 -1446 -1240 -1760 -1303 -1315 -1720 -1392 -1006 -1187 -1385 -665 -1394 -1375 -850 -750 -1017 -805 -835 -1499 -1195 -956 -1060 -1040 -1195 -1056 -1341 -806 -1060 -874 -875 -1036 -1460 -1279 -937 -1069 -1188 -1507 -1042 -1391 -1084 -1262 -766 -1422 -1349 -1062 -849 -833 -1078 -1600 -1372 -768 -759 -1736 -1344 -912 -1102 -1135 -1241 -1074 -745 -744 -1185 -724 -1318 -598 -1014 -1017 -929 -1322 -665 -939 -1268 -1150 -931 -1092 -624 -1331 -1077 -623 -1007 -1516 -1219 -915 -389 -1345 -1549 -937 -1506 -951 -1117 -820 -776 -881 -444 -807 -743 -742 -786 -819 -936 -584 -1470 -716 -913 -643 -608 -1095 -1313 -1093 -1164 -1086 -553 -1165 -1311 -1215 -754 -794 -1070 -961 -637 -1022 -925 -1238 -865 -1394 -987 -961 -760 -986 -1235 -1253 -1191 -1340 -1197 -1500 -1190 -1004 -1085 -693 -1288 -1250 -1510 -1731 -927 -798 -1182 -769 -1178 -1237 -1582 -880 -1141 -857 -1009 -1158 -649 -958 -1136 -1434 -1519 -915 -1066 -748 -881 -980 -875 -1448 -1080 -1430 -1325 -621 -1003 -1194 -1056 -803 -1035 -1259 -751 -859 -845 -884 -1253 -1239 -833 -869 -1342 -1351 -1216 -1253 -1340 -958 -975 -1517 -1603 -897 -787 -1598 -719 -1204 -1077 -1173 -1063 -1267 -1745 -792 -731 -1393 -855 -1064 -1257 -1476 -1126 -1369 -1434 -1368 -1056 -1241 -914 -1330 -1100 -1288 -1221 -822 -1194 -942 -868 -969 -1462 -1542 -1019 -780 -1140 -831 -762 -1156 -1338 -922 -1165 -1104 -1571 -1508 -1463 -758 -1077 -1539 -1064 -1431 -1439 -789 -1230 -1144 -1448 -809 -967 -1160 -840 -711 -920 -806 -1126 -877 -1084 -1040 -1506 -798 -964 -834 -808 -1457 -1034 -1101 -1090 -886 -1441 -1114 -596 -1207 -1162 -1202 -506 -625 -1139 -1018 -1527 -1080 -924 -1197 -819 -1145 -834 -887 -1323 -1063 -648 -940 -1081 -951 -952 -1325 -1085 -864 -1277 -1182 -1041 -1003 -1200 -1054 -869 -1128 -994 -1094 -1234 -1150 -1230 -752 -641 -1135 -1185 -1134 -1001 -654 -1216 -916 -1486 -1065 -1304 -836 -1028 -1540 -843 -1308 -909 -1028 -1102 -1342 -1330 -882 -989 -1427 -1234 -804 -969 -645 -1300 -982 -1123 -939 -1454 -941 -1216 -1293 -788 -1423 -1064 -1188 -1020 -1107 -992 -821 -899 -1039 -505 -825 -862 -717 -1738 -1202 -1262 -1356 -1014 -955 -1091 -879 -1132 -1511 -958 -1293 -1077 -939 -990 -976 -1351 -1277 -1185 -1062 -1410 -867 -1252 -605 -968 -1148 -698 -1235 -1117 -1066 -1037 -1134 -793 -1509 -698 -908 -1089 -926 -739 -776 -809 -1198 -768 -772 -1595 -1052 -1180 -829 -493 -1201 -1120 -1849 -688 -877 -863 -1125 -908 -1354 -1155 -1194 -915 -1157 -1149 -1392 -1027 -989 -780 -1192 -1492 -1171 -533 -696 -945 -1199 -1151 -1536 -1491 -966 -923 -974 -1013 -997 -839 -1311 -1534 -1194 -795 -916 -1525 -1523 -532 -981 -1067 -854 -898 -1597 -1000 -801 -989 -1133 -853 -812 -1209 -1146 -1041 -1132 -1409 -1248 -662 -857 -543 -765 -1043 -657 -1115 -612 -1718 -887 -931 -1241 -1071 -1151 -1121 -902 -535 -943 -957 -1274 -1033 -1188 -1200 -850 -738 -1138 -602 -1560 -839 -1100 -1141 -884 -737 -1303 -1283 -1769 -989 -1182 -569 -1199 -701 -1045 -1003 -1678 -1398 -608 -823 -1074 -716 -908 -933 -1484 -1029 -948 -1013 -1226 -1210 -905 -846 -692 -983 -658 -1010 -1128 -1151 -1695 -1162 -1019 -795 -1048 -889 -1257 -1029 -1169 -1038 -1077 -602 -1828 -1052 -1146 -1146 -1101 -742 -1122 -1037 -774 -1068 -1173 -856 -1149 -1153 -1008 -840 -1265 -1818 -1114 -1171 -1075 -1318 -886 -878 -665 -620 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/random.txt deleted file mode 100644 index b34411e8f..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -5765 -5679 -5492 -9115 -7126 -5832 -5204 -5219 -6468 -6429 -4212 -3744 -3290 -5584 -5560 -7032 -5042 -8224 -9679 -5649 -4461 -3198 -5147 -5344 -5818 -3010 -5307 -3814 -8769 -4429 -3168 -7684 -6580 -6563 -8099 -5635 -5469 -2460 -7392 -4997 -5716 -7018 -6678 -7240 -8419 -7503 -6463 -5214 -4117 -7230 -5398 -3461 -6805 -4536 -4444 -4924 -6671 -5896 -7307 -6115 -6680 -4004 -4513 -4284 -6022 -4634 -4754 -3582 -7230 -8565 -4497 -5585 -4964 -1946 -4138 -4019 -5729 -8629 -6447 -7200 -4875 -2703 -5933 -4640 -5153 -6675 -7045 -2451 -5098 -2457 -5465 -6557 -5300 -6206 -5936 -4753 -3788 -7919 -5837 -7126 -7288 -7219 -5140 -4029 -6037 -7011 -5091 -3865 -2934 -6922 -8056 -5433 -4695 -6680 -5940 -8230 -5827 -5962 -6141 -6582 -6489 -7800 -3364 -9170 -5767 -4961 -4454 -5556 -5398 -3188 -3935 -4032 -8355 -8081 -7326 -5286 -5532 -5709 -4844 -5678 -6258 -5105 -6013 -7595 -7344 -6669 -5940 -6499 -5617 -4136 -6051 -6172 -5673 -6851 -6069 -5049 -1825 -4390 -4369 -6793 -7436 -5415 -6850 -4157 -6107 -6256 -4053 -3434 -4503 -7223 -3926 -3736 -5511 -7671 -3051 -3397 -8392 -4478 -7496 -4441 -6024 -8391 -4534 -3813 -5407 -6038 -5500 -5783 -5921 -2462 -6551 -8138 -3920 -6655 -6537 -4642 -4543 -4276 -6125 -5875 -5559 -4249 -3999 -4817 -5885 -5317 -6986 -5902 -6063 -6551 -3980 -10508 -4221 -7833 -5088 -5608 -5250 -8044 -8086 -4848 -4807 -7320 -6611 -3810 -4650 -6672 -5272 -6175 -5693 -4138 -3797 -6114 -5398 -4362 -6579 -6924 -6779 -4973 -4150 -4900 -7303 -8402 -6600 -4540 -2631 -6195 -7071 -9872 -3741 -2934 -1981 -6750 -5189 -7830 -4253 -5428 -3908 -7326 -4538 -5765 -4192 -3214 -7791 -5632 -5944 -5611 -3787 -3783 -6039 -5391 -6927 -5470 -4987 -7223 -3476 -7887 -4144 -4801 -8864 -5013 -3519 -3083 -4866 -6780 -4812 -10205 -4719 -5879 -3611 -5424 -3422 -6126 -6896 -4283 -4862 -3538 -5793 -6999 -7936 -9042 -5503 -6964 -7725 -5229 -9299 -4022 -4627 -7509 -5196 -5202 -4035 -5833 -5820 -3720 -4725 -7457 -6035 -2361 -7663 -4074 -6676 -6827 -6869 -8441 -4213 -3499 -4184 -7201 -3660 -6519 -5472 -6213 -6709 -3450 -4361 -4548 -3919 -6934 -9545 -7556 -4141 -4473 -6308 -7396 -8337 -7277 -6229 -5223 -4478 -6313 -6538 -6048 -4069 -5396 -5570 -6544 -5587 -5313 -5262 -6531 -5679 -7245 -7450 -5988 -5124 -4658 -5207 -3504 -2997 -5290 -6827 -5045 -4507 -2903 -5402 -6679 -3995 -5360 -5720 -6642 -4456 -5279 -5310 -3615 -5464 -8523 -3920 -6024 -3609 -8418 -5386 -6475 -9536 -6241 -8155 -4346 -7820 -4507 -7889 -8791 -6658 -4245 -7373 -4465 -7023 -2830 -6683 -4273 -5846 -5083 -3810 -6385 -2732 -7443 -8809 -5766 -2257 -3737 -6316 -3608 -3710 -5931 -5887 -5054 -5457 -7901 -6213 -3573 -4924 -4815 -4545 -3571 -2917 -4672 -5564 -6135 -5552 -4247 -4724 -4635 -5781 -8274 -7676 -7823 -6812 -4851 -6317 -4303 -6671 -3043 -8376 -5033 -4371 -5678 -4344 -6047 -3967 -8988 -5247 -5175 -3619 -3962 -7279 -5371 -7841 -4507 -6206 -9545 -7031 -4394 -4148 -3908 -5906 -4283 -4283 -4811 -5901 -3665 -4615 -7647 -7543 -7817 -4697 -7963 -6487 -7083 -4074 -4975 -5453 -7590 -5492 -5673 -5274 -9346 -8765 -5373 -5457 -4460 -6451 -6384 -7946 -5395 -6348 -3389 -6325 -3095 -7475 -4784 -3639 -4351 -5629 -3972 -7103 -3510 -6403 -6882 -6634 -5975 -4003 -6517 -7027 -7998 -4331 -6192 -4829 -2119 -2995 -4201 -6140 -9067 -4378 -5503 -5710 -4506 -7796 -5560 -4206 -4871 -3906 -5508 -6423 -3592 -3884 -3865 -6930 -4723 -4988 -7346 -4587 -4747 -9588 -6333 -8279 -2362 -5177 -4663 -5806 -7022 -6052 -6324 -4716 -5108 -3945 -5740 -4820 -3853 -6705 -6331 -5342 -4294 -5081 -5950 -4390 -7670 -6852 -6821 -6272 -5346 -5268 -3881 -6086 -4145 -5844 -6943 -7165 -5186 -4372 -7213 -6314 -4502 -7593 -6737 -6740 -6424 -7332 -5797 -5653 -5689 -6160 -4956 -6144 -5293 -3121 -5561 -5243 -5097 -5053 -3589 -4429 -3892 -7941 -4094 -4181 -4934 -9091 -3739 -6555 -6827 -8742 -6297 -5698 -8005 -3784 -5176 -4701 -5764 -3136 -4884 -4892 -4729 -4702 -7446 -6128 -7459 -6227 -8193 -5817 -5474 -6852 -4373 -4845 -5233 -5034 -3154 -6750 -3934 -5591 -4383 -5099 -5784 -7161 -7064 -4758 -8389 -4510 -6757 -6076 -4185 -5747 -6774 -6629 -6393 -3208 -5602 -5311 -4631 -4407 -6317 -5739 -4806 -5052 -6042 -4052 -6247 -4089 -8488 -2125 -4547 -5735 -6409 -5572 -4610 -5335 -7622 -11481 -4504 -5642 -4730 -4261 -5118 -6409 -4804 -5724 -7329 -8055 -5100 -6938 -6743 -4354 -5667 -5816 -5113 -9239 -8189 -5756 -4589 -4334 -3835 -8701 -6494 -6926 -6843 -7598 -5293 -5579 -3913 -6393 -5346 -5484 -3686 -8028 -5778 -7282 -4818 -4671 -3439 -7801 -5242 -8114 -6943 -3642 -3288 -6641 -4229 -6915 -5357 -4151 -4026 -5926 -6232 -7429 -8186 -5597 -5210 -3787 -3117 -4735 -7397 -3287 -3854 -6560 -6686 -5525 -5568 -7584 -4024 -4403 -3206 -8323 -6482 -6865 -6975 -5204 -8475 -6428 -4791 -2852 -3701 -7796 -3789 -5704 -6413 -4266 -4483 -4181 -4981 -2614 -6959 -4542 -4713 -6344 -5420 -4865 -5145 -7501 -5010 -3947 -4338 -6310 -4080 -4417 -6452 -4863 -6699 -6409 -8668 -4349 -6742 -4283 -7563 -7284 -7154 -5297 -3435 -8639 -6782 -4788 -9138 -3961 -5231 -7782 -9170 -5673 -5170 -2939 -6746 -6669 -6290 -7709 -4711 -5983 -5925 -6706 -4692 -7403 -5898 -3940 -4822 -4317 -6528 -3658 -4702 -4497 -5542 -4599 -7041 -4482 -4597 -2575 -4881 -7205 -5131 -5705 -6785 -5968 -6678 -6657 -5167 -6149 -5820 -4902 -4793 -3773 -3381 -3424 -6011 -7173 -7193 -5650 -9746 -5430 -4086 -3404 -4644 -6323 -3995 -9411 -3800 -5355 -4320 -4660 -5659 -5530 -5174 -6936 -5832 -7509 -6414 -7577 -5393 -6512 -8858 -5351 -4525 -4248 -2893 -4486 -4876 -3524 -6705 -4768 -5241 -4547 -4805 -3836 -5805 -5070 -6485 -5703 -4177 -4304 -6868 -5995 -7070 -6312 -3936 -6218 -8660 -3759 -5176 -4439 -3712 -8527 -4174 -5659 -6598 -5080 -4879 -6982 -6235 -4345 -5494 -7830 -9138 -5812 -3612 -3476 -5548 -4866 -6230 -6864 -4263 -5720 -4037 -6158 -6430 -5625 -2328 -5218 -5640 -3691 -4400 -5412 -4192 -3704 -3159 -5913 -3591 -6934 -2886 -5297 -5656 -4994 -4899 -7029 -3038 -6600 -5088 -3484 -5475 -4373 -4294 -8017 -3675 -6100 -3560 -5002 -3162 -6073 -3048 -3628 -2452 -6884 -5617 -3779 -8496 -3885 -5029 -3281 -5778 -3343 -5993 -6235 -7050 -6385 -5572 -7308 -9124 -5077 -3570 -4831 -3277 -3837 -6279 -4910 -5323 -5000 -6745 -2807 -5786 -7689 -8084 -5178 -4361 -12860 -4237 -5744 -6013 -4434 -4698 -5606 -6056 -5602 -5797 -3768 -5274 -6527 -5567 -6870 -4325 -3889 -5930 -6827 -4720 -4832 -5958 -4721 -7377 -5772 -1900 -6430 -7824 -5531 -2977 -4252 -7067 -5140 -4423 -5573 -6256 -4077 -6142 -7876 -3521 -5353 -8161 -5129 -5707 -5093 -3569 -7340 -3216 -4876 -7418 -2874 -2489 -4442 -4016 -3794 -5467 -5319 -7335 -3217 -3387 -4996 -5259 -3938 -4422 -5540 -6713 -7430 -4846 -5599 -4618 -4752 -5265 -8086 -5512 -3579 -4708 -4775 -5086 -4913 -4418 -4819 -3283 -5117 -5275 -6450 -3792 -7841 -5016 -3348 -8215 -6350 -4172 -5670 -6143 -5966 -6901 -5483 -5884 -7374 -5119 -8166 -6180 -6822 -5228 -6549 -4889 -3844 -8046 -9091 -2508 -6101 -7369 -3853 -3793 -7648 -5342 -2903 -5867 -8947 -6086 -6150 -3888 -3886 -4519 -7732 -5936 -5441 -5117 -4133 -5478 -5191 -2997 -6058 -5476 -5083 -7641 -6334 -2951 -3130 -6794 -6036 -3923 -3615 -6595 -7453 -1592 -5125 -4400 -3905 -8866 -3341 -5068 -2863 -5858 -8529 -3882 -6887 -5813 -4446 -5769 -5847 -3924 -6628 -7541 -6106 -5851 -6114 -5782 -4956 -9625 -5751 -3944 -7622 -6037 -6030 -6138 -4446 -4765 -5482 -2592 -7031 -5467 -6595 -8020 -6943 -4782 -6873 -5681 -4456 -6906 -4907 -6090 -3062 -5960 -5024 -4447 -4011 -8084 -5680 -6718 -5688 -5423 -6935 -5590 -2862 -5325 -8019 -8101 -6656 -8426 -4845 -5617 -2977 -4990 -4959 -7075 -4649 -4564 -5425 -5951 -6288 -7301 -7072 -7582 -4025 -5564 -5461 -4962 -5170 -4515 -7305 -4019 -4870 -2708 -4942 -6199 -8891 -7483 -4022 -7186 -5495 -5001 -6175 -2959 -5006 -6727 -6954 -3926 -5167 -4914 -6277 -5705 -3149 -5724 -7402 -6814 -5747 -5342 -6271 -8467 -4363 -3796 -5841 -4485 -3914 -6481 -5772 -4927 -5465 -4419 -4654 -5811 -6873 -6320 -6026 -4094 -7198 -3442 -8530 -3436 -6441 -3285 -4498 -7413 -6374 -5802 -4727 -5428 -6337 -4866 -3810 -2785 -5085 -5744 -7563 -6792 -5890 -6121 -4800 -8020 -4925 -5607 -6436 -9515 -8254 -5032 -6590 -3808 -5629 -5050 -3300 -3363 -6090 -5659 -5461 -4512 -6702 -4728 -4452 -3685 -6219 -6481 -6023 -4166 -6578 -7716 -4822 -5197 -5720 -3936 -5900 -5503 -5035 -4090 -5670 -5004 -4908 -6044 -3081 -7638 -10525 -7543 -6074 -5041 -6372 -6451 -4729 -6901 -5192 -4446 -7287 -5526 -4038 -5852 -7132 -8004 -5171 -4306 -5851 -5730 -4977 -5019 -5509 -4854 -4849 -7059 -5777 -4909 -5676 -7386 -5442 -8096 -4032 -4523 -8240 -7156 -3766 -4265 -6019 -5790 -6495 -5660 -4885 -4634 -5444 -7371 -3920 -5400 -7905 -7435 -5218 -8179 -5069 -6836 -6127 -6974 -6535 -4797 -6649 -5893 -5402 -4094 -4806 -6335 -4469 -9162 -7022 -6645 -6171 -6829 -6097 -4616 -5839 -5691 -5176 -5626 -4851 -6030 -4083 -7009 -5622 -6538 -4818 -3544 -6582 -3698 -8020 -6497 -6935 -8516 -4656 -5490 -4461 -4599 -5283 -5297 -5296 -4324 -6818 -7586 -5801 -6116 -4555 -6893 -4449 -5215 -5234 -6533 -7192 -5242 -5972 -5618 -7867 -6502 -2705 -4154 -6649 -6941 -6671 -5567 -7962 -6462 -5616 -4807 -4664 -3789 -5701 -7175 -3050 -6268 -6542 -9044 -3859 -6682 -5063 -4499 -8822 -5441 -4966 -6151 -2734 -8102 -6049 -3445 -7701 -5741 -5109 -6188 -4369 -7173 -6450 -5014 -4101 -6421 -8423 -4668 -6851 -5920 -7142 -7556 -5137 -6613 -6218 -7010 -4467 -2989 -3609 -6634 -6753 -6583 -5534 -4617 -5148 -5990 -4657 -5616 -7244 -6041 -5884 -5346 -8562 -4725 -2879 -5910 -5372 -4503 -5132 -4790 -4970 -6598 -4839 -9433 -7398 -8287 -7450 -3334 -5444 -4575 -4956 -3928 -5342 -9425 -3916 -4544 -4839 -5217 -6766 -8615 -5797 -6743 -4576 -7464 -9145 -5926 -6555 -6542 -7813 -5565 -5197 -6528 -3725 -5780 -5746 -5220 -4840 -7208 -6972 -5128 -6308 -7870 -4879 -9784 -6210 -4815 -5023 -6455 -9147 -5579 -5464 -7348 -6073 -5727 -5916 -5300 -3754 -6800 -6784 -5450 -3661 -4020 -5060 -6402 -6136 -5029 -3978 -6603 -7233 -5237 -5329 -5191 -2988 -7288 -7786 -8929 -5135 -7582 -6538 -4864 -4803 -7415 -5496 -4331 -3902 -5445 -5451 -8636 -5040 -3891 -3988 -4626 -5863 -4073 -7573 -6243 -6283 -9246 -7387 -5400 -5114 -6238 -5312 -5627 -3924 -6277 -5807 -5950 -4425 -3122 -6779 -2925 -6374 -7001 -4865 -4545 -6329 -3543 -5142 -9143 -5222 -3361 -4912 -5561 -5830 -8514 -3543 -9323 -14411 -5884 -6513 -4946 -11808 -5867 -5056 -5330 -4357 -5578 -3945 -2961 -3453 -6561 -7373 -6110 -3551 -6609 -6478 -5341 -5724 -4309 -6359 -3719 -5602 -4206 -6278 -10232 -3700 -4314 -9685 -7416 -3500 -6609 -9442 -4676 -7990 -7672 -5661 -4506 -4163 -6157 -5685 -6962 -9263 -5558 -4037 -3872 -5435 -6670 -6908 -4603 -3644 -4523 -3496 -5330 -7147 -6916 -8197 -7393 -4932 -3978 -6137 -5125 -3512 -5326 -3393 -6454 -5741 -6896 -6578 -6663 -7579 -4856 -6223 -4894 -5435 -4654 -4957 -6563 -4190 -5660 -4176 -9363 -5921 -4618 -6395 -7427 -5583 -6464 -7316 -4952 -3986 -3334 -7182 -4862 -5579 -3316 -5461 -6498 -7906 -5518 -5467 -5247 -2682 -5659 -5934 -6548 -6725 -6587 -8687 -3279 -8678 -3214 -4040 -5812 -8258 -6682 -6256 -3460 -4470 -4573 -4894 -5769 -5347 -4821 -7406 -7041 -9870 -3451 -6421 -7433 -7128 -4857 -4591 -4211 -4986 -10455 -4597 -7967 -6424 -5801 -6205 -3135 -7796 -6468 -6696 -5371 -7505 -9741 -6601 -3667 -4876 -2556 -5247 -5276 -5715 -3614 -4641 -3367 -6501 -7695 -4970 -7698 -5757 -4434 -4542 -5955 -7695 -4753 -7558 -5530 -6788 -5479 -4813 -6417 -3672 -4844 -6099 -4179 -7126 -5881 -6569 -7363 -6924 -5453 -3202 -4888 -4909 -6701 -6272 -5332 -5764 -6016 -3281 -5276 -3945 -5449 -4422 -5227 -4478 -7734 -6048 -6337 -5903 -5307 -4579 -3284 -3974 -5667 -6223 -2713 -5020 -5888 -6703 -7369 -5848 -6905 -8042 -5767 -3280 -6020 -7588 -6536 -6747 -4646 -6146 -5028 -5864 -3906 -4116 -4580 -7234 -5778 -7754 -4042 -6562 -6356 -3421 -4133 -4988 -5952 -5415 -4830 -2530 -4666 -7894 -5624 -9654 -5753 -5327 -6857 -6405 -7367 -8136 -4924 -6465 -6702 -9762 -7400 -4724 -5464 -3571 -2896 -7321 -6302 -7164 -4415 -4148 -2324 -7595 -6393 -5471 -8361 -4113 -6976 -7493 -4383 -6230 -3559 -2773 -5943 -5345 -6008 -6135 -5068 -6135 -8190 -5002 -2774 -5681 -7596 -4539 -6563 -5025 -3281 -5024 -6843 -4706 -4385 -6740 -5421 -5857 -7350 -3948 -3714 -4751 -4408 -6000 -6075 -4947 -5275 -5109 -4871 -5255 -9254 -5227 -4733 -5066 -5890 -3148 -5834 -6520 -8284 -10066 -5256 -5199 -5451 -3922 -4492 -4838 -6607 -6048 -5407 -4583 -6729 -6644 -4271 -4418 -6452 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/best.pt deleted file mode 100644 index fdb05617b7dd6222f7794c18323d96b7beece8f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14039 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%0D{@exKdJ9FwSHFGo5n+WS$gb1uaM# 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 Y_pkK(Z(D0ovEMfm{NL~Lf0h0J0P)*NoB#j- diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/config.yml deleted file mode 100644 index 32beb4058..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k6/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 9, 17, 25, 33, 41] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/dqn.txt deleted file mode 100644 index 3a3b65dc8..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1237 -810 -830 -1350 -890 -884 -767 -972 -759 -805 -1042 -978 -937 -962 -708 -775 -1552 -1071 -967 -933 -1211 -1081 -1493 -768 -1176 -960 -490 -1314 -1352 -854 -1025 -644 -964 -893 -552 -1467 -1147 -989 -1196 -1098 -1014 -1266 -948 -1221 -1000 -1077 -1128 -838 -1174 -632 -1561 -1394 -1219 -944 -1169 -1532 -1307 -728 -1063 -1487 -1352 -708 -1246 -634 -803 -1077 -1671 -1077 -787 -1252 -967 -1258 -1080 -1038 -851 -1636 -1180 -1080 -1122 -864 -786 -939 -1133 -1089 -878 -1336 -914 -1326 -1231 -928 -835 -1235 -1468 -977 -981 -690 -610 -877 -597 -1138 -994 -866 -749 -892 -769 -990 -746 -1334 -705 -645 -1041 -1074 -915 -1122 -1007 -777 -1351 -561 -1000 -1042 -885 -759 -933 -1116 -1015 -1204 -839 -813 -1487 -1179 -911 -1190 -661 -774 -993 -915 -1011 -1259 -1243 -812 -1400 -736 -829 -781 -790 -1232 -1253 -1304 -802 -1557 -1088 -873 -1573 -1092 -751 -806 -1063 -1117 -870 -1113 -918 -1510 -1233 -905 -1415 -820 -1405 -645 -1398 -811 -756 -1693 -954 -1462 -986 -834 -829 -1111 -1096 -732 -458 -850 -1259 -1003 -1078 -1305 -1620 -749 -935 -971 -1355 -783 -947 -984 -1012 -1315 -1074 -989 -1187 -1195 -1002 -1576 -1164 -1368 -614 -1570 -755 -1365 -1092 -1060 -1249 -975 -816 -736 -1086 -1083 -937 -1032 -1004 -1220 -1373 -678 -1109 -1389 -1843 -1002 -1003 -790 -1107 -661 -912 -1322 -1506 -999 -970 -969 -995 -1045 -912 -1088 -927 -1338 -856 -1371 -1086 -1132 -793 -1355 -1276 -584 -1008 -1195 -1184 -1186 -1404 -1150 -777 -1346 -807 -869 -951 -1207 -1242 -1033 -1642 -1470 -1212 -1234 -1213 -1199 -947 -856 -1028 -1354 -653 -990 -1585 -919 -1695 -1019 -562 -1302 -1146 -1198 -1014 -1036 -1328 -890 -987 -860 -824 -1101 -1586 -682 -957 -1136 -761 -1253 -1166 -701 -766 -750 -1288 -861 -839 -1072 -1082 -1802 -1219 -1339 -1149 -1051 -851 -836 -862 -947 -1298 -872 -1345 -1033 -823 -679 -1246 -1036 -979 -1282 -830 -1426 -957 -1068 -997 -1355 -1445 -1351 -1298 -1185 -1055 -909 -634 -1143 -879 -665 -919 -965 -1110 -1167 -1157 -1455 -611 -808 -1287 -1026 -898 -1193 -857 -2000 -1426 -570 -1126 -1040 -1011 -1439 -1040 -1239 -1271 -1160 -677 -1441 -972 -1005 -619 -761 -1447 -767 -717 -1555 -648 -1397 -1200 -788 -1261 -1008 -667 -726 -1301 -992 -1603 -1322 -1422 -1073 -1338 -1191 -897 -981 -780 -1185 -826 -1872 -1114 -865 -730 -1403 -979 -1239 -922 -682 -1206 -1404 -893 -901 -789 -685 -1387 -939 -1212 -894 -971 -1125 -1341 -641 -1002 -1125 -1054 -1190 -1116 -658 -854 -1331 -948 -1051 -1071 -1243 -1146 -1222 -912 -1240 -2357 -798 -939 -1239 -1071 -779 -812 -887 -1071 -1321 -1274 -1259 -1173 -927 -1571 -1094 -1191 -947 -595 -1686 -1331 -1168 -845 -1347 -566 -1054 -580 -925 -965 -636 -996 -1139 -1556 -1334 -1196 -1147 -781 -1074 -889 -1066 -1185 -1619 -720 -1032 -772 -1555 -873 -1075 -962 -1720 -1742 -1190 -847 -1042 -1070 -1244 -1350 -934 -1422 -1651 -986 -1182 -1324 -713 -983 -762 -969 -681 -785 -949 -1365 -692 -1013 -1214 -692 -914 -1149 -1446 -896 -958 -1209 -1075 -1013 -1013 -1144 -1587 -769 -1264 -853 -759 -611 -1065 -1056 -1240 -961 -493 -979 -836 -844 -900 -851 -968 -1096 -1413 -1522 -1190 -1172 -1140 -1286 -1205 -815 -572 -943 -1589 -686 -872 -1017 -781 -1245 -1105 -876 -1093 -939 -447 -795 -826 -1072 -734 -522 -809 -1318 -1484 -538 -1716 -1099 -1603 -943 -752 -1017 -1209 -1183 -1009 -826 -747 -1521 -673 -932 -1179 -792 -1015 -1007 -881 -1062 -1215 -752 -938 -1085 -1414 -883 -1096 -860 -1601 -1361 -1354 -1080 -1029 -1138 -861 -904 -1599 -827 -1161 -1448 -1323 -980 -807 -952 -1425 -984 -585 -690 -948 -1387 -991 -1181 -1221 -1667 -1204 -1626 -1074 -1372 -877 -658 -1204 -1257 -807 -700 -1281 -912 -981 -994 -1146 -1200 -998 -1279 -967 -1324 -856 -999 -946 -932 -1519 -1196 -946 -839 -1282 -887 -927 -1331 -1163 -770 -747 -840 -1519 -805 -660 -1004 -1246 -979 -800 -619 -1606 -1190 -1532 -830 -1369 -796 -1043 -901 -1135 -1324 -934 -1294 -1335 -608 -1245 -813 -777 -1204 -958 -441 -1138 -868 -1521 -1223 -990 -495 -1358 -935 -541 -1174 -779 -1527 -1004 -1202 -1616 -874 -836 -1231 -1252 -1133 -1261 -1483 -1202 -1048 -1348 -1339 -1177 -1059 -955 -989 -958 -817 -1220 -1044 -1507 -1263 -1315 -1238 -675 -1364 -1534 -1475 -540 -1162 -791 -1017 -989 -1227 -1037 -1566 -871 -1443 -653 -1224 -1353 -427 -966 -876 -1304 -1202 -820 -1330 -1194 -1027 -1045 -915 -626 -649 -983 -1065 -962 -1599 -1262 -1196 -888 -1236 -791 -1263 -1500 -1196 -1706 -1293 -920 -933 -842 -928 -908 -586 -975 -857 -1013 -748 -985 -937 -943 -1020 -956 -613 -1025 -1225 -1092 -884 -1436 -1112 -896 -1458 -911 -551 -862 -700 -699 -1127 -1170 -930 -1264 -1527 -860 -1569 -1086 -1000 -1001 -1407 -1596 -1176 -825 -1161 -679 -1506 -1144 -951 -1223 -1217 -556 -623 -1577 -1201 -936 -824 -1065 -810 -857 -1218 -940 -789 -1010 -1102 -1192 -1048 -836 -854 -1265 -1120 -1000 -970 -1310 -1034 -795 -1314 -777 -992 -1137 -983 -1318 -1171 -1346 -658 -691 -567 -835 -921 -763 -566 -1208 -1231 -832 -1134 -1054 -549 -1283 -1107 -1003 -463 -705 -1224 -1813 -544 -1238 -307 -1472 -556 -1253 -1200 -1650 -890 -1244 -1130 -1084 -1239 -1325 -1241 -622 -1011 -1142 -1201 -1121 -1054 -1034 -1346 -1749 -686 -1107 -1484 -952 -1498 -1522 -785 -640 -716 -1002 -1003 -1217 -1194 -1180 -1287 -1069 -629 -791 -875 -1026 -351 -1091 -1647 -994 -920 -1003 -1029 -1066 -1045 -651 -894 -1213 -1053 -1242 -845 -935 -970 -1266 -1430 -1486 -1051 -1031 -1041 -660 -1446 -623 -1255 -1133 -1155 -1378 -833 -1155 -876 -1103 -913 -982 -1583 -1097 -1122 -1427 -1428 -923 -1017 -637 -567 -1227 -1187 -1095 -824 -696 -1428 -1263 -1322 -1166 -1468 -710 -1033 -883 -598 -352 -1427 -547 -760 -1343 -977 -670 -1533 -1238 -1343 -1346 -1393 -1146 -817 -834 -1002 -1135 -985 -1185 -614 -959 -654 -864 -1266 -1208 -1329 -1145 -1507 -458 -832 -1244 -1356 -814 -1223 -830 -1229 -1014 -1057 -804 -932 -1008 -1011 -1306 -576 -509 -858 -972 -1382 -998 -1535 -1182 -986 -1707 -1430 -1013 -1433 -921 -1424 -781 -1240 -959 -1013 -959 -747 -1180 -641 -832 -884 -1468 -1262 -1156 -856 -876 -1225 -1556 -1069 -1439 -793 -1032 -1363 -764 -793 -670 -500 -1213 -716 -845 -987 -796 -1494 -868 -800 -1183 -1125 -1034 -1294 -1041 -879 -1526 -729 -750 -1097 -1068 -1775 -1059 -1180 -1801 -883 -904 -673 -1189 -1390 -1137 -942 -1499 -1164 -954 -987 -1300 -1146 -1156 -1085 -705 -1571 -973 -931 -466 -1031 -1787 -1550 -1893 -601 -1203 -1089 -1022 -1173 -491 -1344 -797 -613 -1166 -716 -856 -964 -1251 -1033 -1507 -1310 -921 -1041 -1016 -1797 -745 -757 -666 -926 -749 -1664 -864 -1022 -1589 -922 -1099 -809 -1199 -602 -1623 -1647 -1220 -610 -810 -535 -1368 -1708 -798 -1099 -1137 -898 -892 -1484 -754 -1337 -1449 -654 -1036 -591 -995 -977 -1563 -1310 -1039 -801 -1274 -1316 -985 -1126 -1986 -953 -752 -1297 -1401 -870 -816 -887 -1015 -1148 -918 -903 -1470 -803 -739 -1065 -1350 -968 -855 -1746 -1124 -669 -1112 -1101 -958 -1241 -1291 -1206 -1383 -1221 -1047 -1045 -837 -936 -915 -998 -1189 -1175 -1835 -1210 -907 -1421 -1298 -741 -953 -1138 -989 -480 -773 -1274 -798 -1187 -1070 -1313 -1039 -590 -827 -1388 -583 -805 -1046 -1098 -983 -935 -1248 -503 -1061 -789 -1160 -1171 -954 -1062 -745 -1150 -1532 -1119 -1355 -979 -766 -828 -962 -1489 -981 -608 -1290 -603 -872 -1031 -574 -1553 -1055 -1044 -760 -831 -987 -703 -1042 -1196 -1129 -880 -822 -934 -757 -760 -930 -873 -724 -677 -1183 -851 -726 -1555 -1376 -768 -1228 -799 -946 -1720 -811 -1353 -1231 -1249 -1169 -1214 -775 -1276 -1263 -791 -1365 -1099 -1013 -1589 -1034 -833 -977 -918 -1015 -843 -700 -1497 -1388 -975 -734 -962 -1565 -825 -881 -632 -977 -975 -1034 -1708 -1027 -756 -779 -1022 -716 -984 -1310 -1279 -1077 -864 -1202 -1133 -573 -1082 -864 -1246 -1190 -851 -1164 -1338 -900 -1370 -1028 -1096 -1293 -964 -930 -1173 -1183 -1133 -1360 -782 -1423 -1039 -1384 -903 -1074 -878 -1492 -999 -1382 -946 -829 -629 -1076 -972 -930 -1590 -1422 -719 -1045 -1129 -1135 -1268 -1220 -1088 -1358 -1107 -899 -837 -1157 -901 -1129 -906 -1442 -1159 -815 -586 -741 -966 -1019 -1112 -597 -957 -482 -1165 -1053 -931 -772 -886 -1201 -982 -844 -945 -1083 -986 -1033 -1581 -868 -824 -760 -1079 -987 -1380 -881 -901 -937 -1455 -1697 -944 -1177 -725 -1200 -932 -1295 -1245 -1854 -1167 -1441 -1187 -986 -498 -1057 -1167 -867 -1025 -1339 -1009 -786 -798 -1252 -1030 -1204 -967 -1184 -1632 -873 -1061 -768 -1042 -923 -1059 -1312 -1646 -723 -678 -866 -1077 -872 -961 -1129 -804 -1542 -646 -1352 -1131 -689 -987 -1025 -1079 -921 -956 -869 -982 -1003 -969 -939 -913 -856 -1122 -1214 -1061 -1385 -1008 -1135 -1317 -1345 -1251 -764 -1022 -1249 -805 -1214 -1211 -1242 -590 -1014 -1354 -1319 -506 -913 -1176 -916 -1165 -1802 -960 -1225 -1157 -1291 -682 -1390 -1056 -1029 -895 -1142 -623 -1028 -1300 -461 -1262 -778 -1000 -1247 -931 -1163 -826 -1122 -995 -1484 -1080 -688 -1381 -783 -1214 -818 -951 -625 -541 -934 -1392 -757 -1024 -1171 -980 -1163 -1347 -1422 -926 -1044 -1206 -1114 -1284 -1047 -1219 -988 -1179 -935 -1359 -1098 -1030 -640 -685 -1272 -1016 -1011 -1094 -1552 -717 -628 -772 -1051 -1107 -2071 -893 -1045 -1011 -778 -1135 -1090 -1340 -1227 -1441 -1129 -2073 -855 -777 -880 -1051 -1262 -803 -894 -1615 -1458 -1340 -1066 -1353 -1039 -1438 -1313 -1110 -847 -1095 -1212 -1315 -1162 -829 -1221 -969 -1150 -929 -1411 -658 -1082 -1349 -999 -1305 -1297 -972 -946 -918 -1115 -547 -1244 -1137 -909 -1380 -1159 -1609 -624 -928 -1210 -680 -932 -644 -1199 -979 -873 -711 -1147 -1021 -476 -924 -1361 -972 -920 -1171 -1358 -1379 -823 -1519 -1212 -826 -936 -965 -1185 -1237 -1232 -1059 -1280 -918 -726 -1154 -592 -1402 -1250 -882 -602 -1330 -864 -752 -1057 -1149 -677 -1004 -935 -1175 -1258 -826 -1089 -1321 -1098 -1311 -1659 -1316 -837 -951 -861 -702 -1082 -1053 -1508 -1303 -872 -1329 -1734 -623 -1097 -1241 -839 -1112 -1056 -1201 -1282 -1018 -1046 -1368 -744 -1562 -1340 -1489 -950 -2038 -992 -1209 -1109 -1557 -1077 -819 -1137 -1568 -1225 -1239 -1181 -1358 -734 -928 -843 -1195 -639 -1166 -1343 -1013 -1384 -1383 -734 -1570 -774 -760 -988 -1362 -835 -961 -1255 -787 -1037 -991 -1153 -1194 -1066 -1144 -720 -1614 -875 -1580 -1640 -541 -1178 -1328 -1023 -1088 -1380 -1196 -1152 -1097 -1423 -1270 -1016 -925 -886 -988 -861 -1487 -865 -1294 -766 -939 -1284 -675 -1473 -1185 -1261 -1226 -820 -974 -1008 -611 -835 -1264 -1388 -700 -1431 -1354 -958 -1227 -859 -1138 -734 -889 -800 -1012 -1313 -1024 -648 -1207 -703 -1490 -653 -679 -756 -1285 -694 -1315 -864 -586 -910 -772 -947 -1198 -832 -986 -862 -989 -1027 -1171 -739 -1421 -1265 -1508 -935 -882 -1190 -740 -1343 -550 -1481 -544 -1517 -1115 -822 -1161 -1051 -839 -569 -1378 -1263 -567 -1574 -1355 -835 -1319 -832 -919 -760 -1057 -1075 -1378 -1182 -662 -690 -1221 -1418 -758 -1494 -702 -1376 -986 -1502 -978 -714 -1386 -1010 -1417 -610 -1192 -1566 -688 -1618 -726 -1122 -1255 -1242 -1057 -985 -1165 -1456 -1319 -918 -1448 -398 -1363 -1417 -802 -737 -1207 -889 -1027 -919 -1433 -1021 -667 -1199 -1388 -872 -976 -614 -1051 -1024 -634 -899 -707 -910 -1118 -1062 -1407 -1186 -1440 -1431 -939 -1110 -1196 -1441 -1087 -889 -907 -1479 -1403 -813 -867 -1067 -1322 -901 -1341 -1015 -637 -789 -1464 -746 -860 -1074 -987 -747 -889 -1129 -846 -793 -1416 -940 -1583 -667 -911 -961 -1345 -856 -1157 -988 -835 -930 -1107 -1325 -900 -887 -907 -1460 -952 -1150 -1100 -1653 -1002 -783 -1181 -696 -1143 -1316 -1042 -1068 -1208 -837 -712 -768 -1103 -1176 -1094 -1003 -956 -1109 -1406 -751 -1255 -1005 -846 -1025 -984 -1245 -995 -684 -1022 -1517 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/optimal.txt deleted file mode 100644 index a9bf47e7b..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -818 -2046 -830 -955 -1080 -1239 -858 -972 -699 -846 -1249 -1044 -911 -943 -1147 -858 -1250 -1267 -1025 -688 -1444 -1092 -761 -891 -1258 -491 -1326 -1098 -1016 -989 -836 -1318 -867 -893 -1685 -1131 -842 -1440 -1196 -1098 -1014 -1687 -1181 -1139 -1000 -1002 -1542 -1230 -1180 -632 -911 -1468 -1363 -1207 -878 -1296 -1389 -606 -1251 -830 -1205 -708 -653 -776 -1108 -787 -1347 -928 -1411 -638 -980 -876 -1080 -1193 -1082 -1086 -1172 -805 -976 -1384 -1007 -939 -1133 -881 -1229 -544 -914 -653 -955 -793 -938 -849 -1029 -1634 -981 -624 -559 -999 -1099 -1138 -994 -886 -1619 -1157 -900 -905 -746 -880 -893 -729 -1004 -1003 -915 -1122 -1114 -777 -1412 -1213 -1230 -1171 -1134 -1058 -933 -854 -1042 -804 -839 -1362 -688 -1101 -1219 -1204 -661 -992 -1303 -965 -1577 -532 -1196 -812 -1133 -656 -829 -1551 -1159 -1219 -1270 -886 -1662 -1557 -1395 -1142 -990 -1480 -1413 -976 -1063 -1117 -803 -1018 -953 -998 -902 -1915 -1127 -1142 -731 -645 -1398 -897 -756 -1311 -729 -1462 -1220 -1066 -1125 -574 -1096 -939 -755 -834 -921 -1241 -1208 -1127 -888 -578 -1322 -971 -840 -1095 -919 -695 -905 -1057 -1117 -599 -915 -1086 -1099 -1725 -1043 -1160 -857 -1378 -790 -1365 -1304 -1332 -949 -1056 -1172 -1075 -1251 -1315 -937 -1081 -1132 -987 -1535 -678 -1109 -1593 -914 -1002 -461 -1580 -891 -661 -912 -1150 -1119 -999 -932 -969 -886 -958 -860 -941 -1248 -1338 -1098 -1371 -1026 -1296 -793 -931 -1276 -643 -1214 -1055 -1168 -773 -1404 -851 -1012 -1346 -807 -1390 -951 -1207 -847 -837 -1642 -1470 -1269 -852 -1213 -899 -1256 -997 -931 -1325 -653 -1516 -752 -794 -810 -1330 -858 -1618 -1146 -1072 -453 -1358 -745 -1503 -1276 -1232 -824 -1101 -1309 -1070 -1228 -1136 -962 -1388 -1276 -701 -1140 -1216 -1169 -741 -1444 -904 -1433 -964 -967 -725 -1037 -1051 -1252 -1005 -1028 -947 -1172 -862 -1349 -776 -1146 -1085 -1318 -864 -678 -1157 -830 -681 -1248 -987 -1509 -1029 -1325 -1003 -1108 -861 -994 -909 -1061 -1143 -879 -665 -1117 -938 -976 -1180 -1573 -1772 -983 -808 -1482 -1026 -898 -957 -1047 -2000 -1426 -1253 -1126 -1040 -638 -805 -786 -994 -891 -1254 -677 -1519 -972 -1062 -1172 -1293 -1447 -1587 -769 -1391 -648 -1035 -1200 -1003 -1034 -942 -886 -1151 -1137 -1444 -1431 -1205 -1371 -1073 -1346 -1375 -1155 -1356 -1322 -977 -888 -572 -962 -1207 -854 -1358 -1332 -948 -1092 -938 -1279 -1404 -908 -901 -880 -685 -1024 -939 -929 -1421 -574 -1284 -1002 -641 -1318 -1189 -1212 -634 -800 -543 -724 -1331 -1582 -465 -914 -1662 -1902 -1222 -1031 -974 -1030 -1288 -939 -995 -732 -1258 -840 -887 -1071 -942 -947 -1146 -655 -977 -1064 -1137 -855 -1039 -994 -994 -999 -1343 -1142 -878 -566 -1231 -1014 -925 -772 -920 -1095 -786 -1590 -942 -940 -1147 -1116 -771 -888 -851 -900 -1092 -1399 -923 -772 -1257 -876 -1075 -1085 -989 -944 -1178 -574 -1575 -825 -812 -1350 -1073 -1422 -886 -986 -1182 -753 -713 -671 -1125 -985 -681 -1172 -1014 -1608 -1221 -1013 -1227 -1372 -1206 -1360 -816 -1313 -1635 -1209 -1272 -1013 -828 -1429 -1276 -769 -708 -853 -692 -327 -837 -921 -727 -1089 -1085 -912 -872 -888 -1430 -856 -968 -1263 -1413 -1522 -1287 -1172 -1140 -1286 -697 -947 -915 -1169 -579 -982 -746 -1478 -977 -1245 -1105 -934 -1093 -1215 -1005 -1502 -964 -1046 -734 -1397 -852 -784 -1092 -538 -663 -676 -1603 -1536 -752 -1390 -869 -817 -935 -876 -578 -1001 -757 -1082 -1179 -1680 -1015 -880 -971 -1159 -766 -752 -938 -1085 -1481 -1098 -1096 -1236 -1601 -1466 -1654 -1080 -849 -1124 -1085 -1144 -1307 -827 -1161 -1093 -1162 -980 -640 -973 -1372 -1148 -1175 -906 -1583 -1123 -991 -1395 -749 -1003 -1011 -1123 -1054 -1002 -1461 -1334 -1189 -1091 -1451 -917 -1584 -1066 -981 -994 -1146 -776 -877 -906 -965 -758 -1329 -1232 -990 -1294 -1307 -1061 -1075 -1101 -1309 -877 -1313 -1264 -1163 -1506 -865 -840 -1586 -967 -917 -1576 -925 -1220 -800 -619 -1027 -771 -1189 -830 -1369 -796 -912 -901 -1135 -1084 -934 -653 -566 -1420 -1380 -1378 -876 -1380 -990 -441 -1427 -868 -884 -1670 -1100 -1311 -1007 -935 -541 -1143 -806 -1527 -1004 -1202 -797 -1323 -836 -1294 -1252 -944 -603 -951 -951 -1085 -1489 -1339 -1177 -1352 -955 -1478 -1167 -1556 -624 -1044 -949 -1263 -648 -1238 -928 -1045 -564 -1269 -1050 -1231 -662 -979 -733 -775 -1297 -1291 -871 -919 -653 -1385 -1353 -990 -1358 -1186 -1304 -1202 -996 -1168 -1101 -1027 -1334 -1457 -656 -939 -661 -1115 -1200 -1599 -1392 -699 -888 -888 -791 -1515 -1500 -1084 -1296 -1119 -920 -1368 -1002 -928 -1309 -1304 -958 -536 -1083 -544 -1119 -937 -963 -1820 -628 -1323 -1527 -957 -1548 -1176 -874 -1340 -802 -1458 -1047 -1068 -862 -700 -824 -1127 -698 -930 -1107 -1213 -968 -671 -1252 -1000 -1043 -1071 -1123 -866 -743 -1161 -679 -1537 -1144 -1104 -1522 -1118 -728 -641 -1562 -1256 -929 -824 -1065 -895 -1357 -1380 -1615 -789 -808 -1139 -1138 -804 -820 -879 -1516 -895 -1284 -887 -731 -1058 -1033 -908 -1329 -605 -1137 -913 -945 -1171 -1271 -911 -892 -984 -798 -900 -898 -920 -1208 -1231 -1067 -933 -1054 -549 -1220 -1107 -1010 -1223 -1200 -711 -1813 -984 -1431 -307 -724 -556 -773 -956 -1069 -869 -1244 -546 -911 -1545 -1492 -926 -1465 -827 -1142 -1201 -1343 -327 -845 -1346 -1749 -570 -1155 -1134 -851 -798 -1536 -859 -1174 -1192 -1104 -1203 -1102 -1334 -974 -977 -1120 -1003 -1173 -1047 -1195 -351 -1459 -1050 -1346 -1206 -1003 -1105 -1066 -1153 -939 -849 -1169 -1053 -840 -845 -1132 -1336 -591 -714 -1284 -660 -1225 -1010 -796 -1068 -964 -1255 -840 -1155 -808 -1481 -1316 -1174 -1024 -1100 -982 -649 -1097 -680 -1427 -779 -872 -1113 -1332 -966 -971 -1187 -1095 -1021 -1083 -565 -1263 -1132 -1392 -1136 -1025 -786 -1065 -598 -757 -919 -547 -1045 -816 -942 -1513 -1086 -1231 -1231 -647 -1156 -706 -1703 -551 -1002 -1135 -774 -1309 -1091 -760 -1065 -747 -1111 -1447 -1067 -1209 -1022 -458 -1018 -1244 -1453 -814 -818 -1321 -733 -1014 -1057 -1224 -1260 -894 -1273 -930 -576 -761 -858 -972 -1184 -998 -972 -1101 -1238 -931 -1379 -946 -444 -1682 -1204 -1188 -702 -1229 -1068 -959 -907 -1180 -1008 -597 -1194 -1061 -1055 -1073 -1235 -947 -1276 -781 -1069 -1531 -793 -845 -1083 -1039 -793 -1202 -1021 -915 -1014 -987 -960 -1498 -1334 -868 -1025 -1000 -644 -1350 -1672 -1859 -1172 -1127 -1361 -1200 -1097 -932 -1163 -1715 -1374 -767 -883 -817 -1084 -1189 -998 -1137 -1601 -1143 -1002 -954 -1807 -1300 -1146 -1062 -998 -705 -933 -973 -830 -1040 -1305 -1274 -853 -763 -1205 -627 -1632 -1360 -1204 -1005 -857 -797 -683 -1166 -1222 -720 -1434 -1251 -1038 -1078 -1471 -921 -1060 -846 -772 -918 -1296 -759 -1085 -751 -698 -864 -989 -1589 -1256 -1039 -1146 -1012 -1078 -1247 -1647 -1174 -973 -810 -535 -950 -2079 -1160 -985 -909 -875 -962 -1141 -754 -812 -1175 -763 -991 -591 -1515 -2072 -1413 -1495 -1039 -1379 -1151 -1316 -958 -815 -1079 -812 -1126 -1247 -1431 -1065 -946 -742 -1260 -852 -1610 -1218 -658 -1131 -739 -1065 -725 -968 -600 -939 -1124 -715 -927 -1072 -958 -1059 -1293 -1098 -1162 -1101 -1162 -960 -1171 -1128 -1012 -1376 -736 -907 -1835 -1013 -1270 -1478 -1465 -1115 -1217 -1144 -465 -1036 -964 -772 -985 -1187 -1082 -829 -874 -590 -827 -875 -762 -805 -637 -1562 -760 -974 -1143 -1080 -1278 -789 -1140 -1171 -1719 -1213 -745 -1142 -784 -778 -1312 -1194 -766 -1081 -1388 -1016 -1322 -617 -800 -603 -981 -971 -640 -695 -880 -1177 -777 -957 -1384 -1196 -1715 -937 -1129 -646 -849 -407 -1463 -1203 -930 -908 -836 -677 -992 -984 -1120 -1191 -582 -768 -1228 -1042 -814 -1720 -561 -1353 -1189 -919 -1153 -1214 -727 -1365 -1360 -919 -1052 -1099 -1013 -836 -1034 -1084 -925 -918 -1144 -843 -1185 -1497 -1388 -1090 -1676 -1289 -1306 -969 -1755 -684 -1191 -975 -1001 -1708 -892 -943 -1498 -1236 -716 -1003 -1310 -1179 -1035 -1419 -954 -1217 -573 -1197 -1672 -1083 -1015 -891 -1164 -929 -1096 -741 -914 -535 -1786 -964 -1264 -804 -757 -1133 -1064 -1291 -1010 -1087 -798 -1105 -1140 -1082 -706 -1295 -640 -658 -829 -1562 -795 -972 -1240 -733 -1266 -1061 -1174 -737 -1407 -759 -1212 -1088 -883 -1158 -1466 -837 -1128 -982 -1226 -993 -1223 -1322 -741 -831 -741 -1054 -1099 -1224 -597 -1445 -1415 -1165 -1408 -685 -772 -886 -1018 -982 -871 -1325 -1083 -1044 -1036 -1581 -880 -961 -1155 -693 -1005 -766 -881 -811 -1139 -1566 -1279 -944 -602 -887 -1207 -1187 -829 -1157 -930 -1167 -955 -1233 -986 -1393 -1057 -1167 -1248 -1085 -1445 -675 -1204 -903 -1336 -1030 -1152 -1744 -1349 -1632 -1060 -912 -1222 -1146 -923 -1059 -937 -1127 -1015 -1520 -997 -1024 -1409 -830 -1129 -804 -1127 -646 -808 -1057 -903 -1103 -1025 -1154 -708 -491 -799 -868 -776 -685 -939 -772 -1018 -744 -1180 -1061 -932 -1008 -655 -1066 -1065 -1086 -1127 -1022 -911 -1013 -1236 -889 -1242 -590 -1157 -1208 -842 -1212 -1436 -1159 -916 -1165 -1055 -960 -1365 -1157 -1128 -849 -1190 -1281 -1089 -895 -1413 -623 -1028 -688 -461 -1188 -2026 -1000 -1307 -931 -1163 -1071 -1108 -813 -1165 -650 -1453 -1313 -1107 -1577 -538 -858 -968 -993 -934 -822 -721 -1194 -1684 -1236 -1359 -1445 -671 -1220 -1044 -864 -1041 -1004 -1593 -1219 -952 -1179 -1430 -1396 -1098 -1030 -1124 -685 -1349 -906 -986 -783 -1552 -998 -628 -772 -1051 -914 -1205 -893 -1045 -1210 -1223 -1480 -1090 -1159 -819 -1441 -585 -1051 -1271 -955 -790 -799 -1262 -803 -1452 -1615 -1138 -1315 -1066 -1353 -1046 -1130 -1313 -1196 -1131 -1095 -736 -1308 -1074 -829 -1237 -969 -1150 -929 -1191 -529 -1045 -679 -999 -1439 -1112 -1019 -1433 -1114 -1175 -547 -1211 -1113 -1035 -1086 -1112 -1381 -624 -1044 -1210 -680 -835 -672 -852 -753 -873 -1232 -761 -919 -476 -924 -1150 -1226 -920 -857 -1237 -1301 -823 -893 -1212 -1021 -822 -908 -1209 -1142 -735 -1252 -1280 -918 -726 -1336 -1375 -838 -1065 -882 -929 -890 -1332 -752 -905 -1018 -677 -1004 -657 -785 -1441 -735 -1734 -1321 -662 -1144 -1103 -927 -843 -659 -872 -760 -1082 -1053 -1113 -1634 -872 -1162 -1491 -1144 -990 -1241 -1257 -591 -864 -664 -1040 -1168 -1046 -808 -1134 -1430 -1374 -1489 -1487 -1265 -995 -1209 -1109 -1198 -1077 -1178 -937 -745 -968 -1450 -1195 -1358 -1039 -1444 -1349 -823 -893 -1445 -1343 -1013 -1057 -1383 -734 -1045 -774 -786 -1223 -1262 -1261 -961 -904 -851 -952 -931 -1186 -1211 -1245 -953 -1021 -922 -1003 -1580 -1640 -778 -769 -1377 -1023 -847 -1119 -1174 -1017 -1097 -864 -837 -911 -1125 -832 -1198 -861 -837 -1053 -1023 -844 -1103 -982 -1036 -1304 -1100 -1127 -1086 -820 -1156 -1128 -952 -835 -983 -1322 -849 -995 -1322 -1039 -1172 -863 -656 -734 -889 -800 -798 -891 -1105 -1305 -1670 -703 -1297 -1116 -1523 -1276 -713 -694 -1231 -727 -586 -1443 -772 -1127 -1445 -1426 -1244 -728 -1135 -1027 -1171 -653 -1421 -1010 -830 -935 -821 -1054 -1044 -610 -550 -1127 -544 -675 -1025 -797 -973 -1051 -689 -1059 -1276 -1263 -1113 -835 -1350 -1195 -1319 -832 -1304 -760 -1343 -1672 -1378 -744 -662 -1008 -845 -596 -1097 -1329 -1099 -1016 -896 -1148 -956 -983 -719 -634 -1417 -610 -943 -1002 -1054 -1618 -867 -1391 -1108 -1242 -1057 -590 -1165 -1321 -1183 -940 -1178 -1381 -1405 -703 -1408 -749 -1207 -845 -1402 -1029 -1009 -786 -667 -1381 -919 -1404 -1221 -916 -784 -1024 -634 -899 -713 -801 -570 -1062 -1407 -766 -1488 -1431 -1110 -1039 -1302 -1002 -761 -889 -907 -1429 -951 -934 -890 -1067 -1322 -1171 -1341 -1114 -637 -789 -1464 -746 -927 -445 -1059 -789 -765 -1129 -690 -739 -1091 -1069 -1475 -1179 -992 -1007 -1345 -1288 -1262 -988 -1590 -1232 -1171 -1205 -1431 -853 -1111 -1488 -1169 -1219 -1100 -1653 -1210 -1635 -1289 -1044 -1472 -1316 -1100 -1189 -615 -1123 -963 -1489 -802 -1176 -783 -1003 -1070 -717 -1406 -1397 -1255 -613 -1127 -1188 -757 -1609 -891 -546 -832 -1200 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/random.txt deleted file mode 100644 index bedb86717..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -4760 -4144 -5419 -8529 -6720 -4520 -8823 -7348 -5502 -8448 -6109 -6942 -8664 -5087 -8947 -5679 -8767 -6621 -4503 -9050 -4729 -8100 -4378 -5626 -7982 -6113 -5101 -5718 -4025 -7140 -8623 -4249 -5616 -4181 -7033 -5625 -5728 -8996 -7014 -5364 -5758 -3381 -5213 -3745 -5406 -3898 -7174 -7923 -6220 -6470 -9152 -4690 -5612 -5508 -3628 -8967 -7636 -4439 -7536 -6792 -8599 -5376 -5151 -8226 -5585 -8897 -8590 -8068 -4415 -7490 -8999 -5977 -3859 -11191 -6012 -5002 -7054 -6851 -5485 -5981 -5442 -6319 -4351 -6049 -5459 -6735 -6349 -6280 -6645 -5510 -5248 -8233 -6657 -9248 -4438 -5669 -6186 -5434 -3866 -5506 -6003 -7446 -3953 -7704 -8041 -8573 -7266 -5342 -8328 -6714 -6214 -6606 -6238 -8349 -6855 -4317 -10109 -7126 -6715 -7092 -6761 -6591 -5421 -7875 -7924 -7002 -4590 -7691 -7145 -3687 -3338 -8277 -9113 -6534 -6527 -6930 -7969 -8310 -3329 -5638 -8303 -5230 -6076 -7254 -6267 -6423 -7519 -3229 -4180 -5810 -5497 -8053 -5591 -6374 -7505 -6267 -4719 -7411 -7330 -7403 -5454 -5998 -10502 -3380 -5355 -5427 -7736 -7619 -4196 -5639 -7198 -5784 -6044 -3973 -5268 -5609 -8597 -7609 -5541 -5777 -6091 -2789 -5815 -7757 -6644 -4947 -5176 -6847 -6805 -4332 -4252 -2295 -7841 -7053 -6746 -4236 -3475 -6214 -6739 -7026 -5806 -6068 -6215 -5849 -8108 -6426 -7257 -6281 -5484 -4273 -8013 -3098 -4469 -7958 -5165 -6098 -4328 -3936 -7361 -5640 -7283 -7206 -5518 -5323 -4294 -7191 -6397 -4572 -10452 -6932 -3510 -6258 -7364 -8030 -7357 -7421 -3987 -6499 -5269 -6311 -8319 -4319 -4952 -7913 -6154 -8371 -9034 -5392 -7680 -7833 -9636 -6757 -10159 -4700 -7260 -4548 -4988 -7620 -5611 -6919 -4504 -7764 -5870 -6490 -5426 -4367 -4797 -5614 -7879 -6305 -5316 -6875 -4002 -6159 -5813 -7079 -8883 -7543 -6280 -8676 -6951 -6380 -3848 -6293 -5571 -6379 -6870 -7920 -5347 -4263 -6685 -5682 -3646 -5249 -6510 -4623 -7871 -5589 -5152 -6025 -6380 -6455 -6321 -8140 -6552 -5029 -7428 -6637 -6189 -6780 -6591 -5542 -5958 -7181 -5900 -6348 -6201 -8137 -6353 -7932 -4126 -5897 -3798 -8248 -2925 -11658 -7107 -6193 -5652 -6784 -4296 -8718 -7232 -8009 -11205 -8057 -5726 -7462 -9071 -7380 -8734 -3242 -6927 -5701 -6587 -8250 -8227 -3720 -5602 -6607 -5503 -4719 -4496 -10876 -9165 -10736 -8912 -5760 -4618 -5383 -7172 -10779 -6516 -6279 -5814 -5331 -4544 -6024 -5548 -4066 -4533 -4547 -6227 -6838 -3838 -6595 -5620 -6586 -4659 -4280 -6061 -6230 -5125 -4741 -5973 -8232 -8125 -7747 -6630 -6172 -5134 -4745 -7902 -8943 -6368 -6073 -5321 -4490 -6243 -5994 -8432 -6361 -7956 -4595 -5801 -6752 -5367 -7416 -8452 -4884 -3029 -6070 -7026 -4368 -4971 -7051 -5851 -7108 -4462 -5936 -6388 -5476 -7109 -6609 -5059 -5563 -4758 -5117 -8449 -5220 -4866 -7103 -8552 -5236 -7504 -5295 -10145 -3935 -5432 -6826 -5643 -6851 -7876 -6350 -5852 -5620 -5739 -4007 -6952 -8282 -5237 -8146 -4546 -6866 -9977 -8035 -8610 -6249 -5342 -3901 -6853 -7729 -4985 -6841 -11103 -4776 -3771 -4627 -5630 -6551 -10115 -6170 -7984 -8705 -8001 -5824 -7181 -6450 -7497 -3883 -9415 -5343 -4202 -7923 -8520 -5808 -3791 -7733 -5272 -4804 -4296 -4248 -5761 -8910 -4783 -3883 -2927 -10869 -10640 -13479 -8219 -7443 -3200 -8136 -6639 -7088 -7187 -8706 -4544 -5824 -5032 -3271 -5733 -5337 -4495 -8028 -7183 -5183 -4997 -6368 -5656 -6216 -6768 -7034 -10099 -5029 -5870 -6286 -7676 -4293 -6915 -6903 -3983 -7151 -5209 -6483 -5888 -7705 -5150 -4556 -7530 -10700 -5765 -7420 -7773 -4335 -5781 -5056 -7105 -3630 -5568 -7498 -7671 -8021 -4781 -5975 -4789 -4382 -11996 -7609 -7342 -8247 -6191 -8117 -6201 -6759 -6756 -7410 -10472 -7315 -6610 -7100 -8946 -7254 -3559 -6024 -8390 -7400 -5341 -7670 -4351 -6288 -7452 -4485 -3665 -5090 -8177 -6659 -3171 -8687 -6878 -5939 -6877 -4574 -8283 -8645 -6653 -8075 -6182 -5310 -4906 -11692 -4749 -3249 -6819 -10535 -5419 -5208 -5786 -6116 -3363 -7038 -5509 -6977 -5268 -5823 -7950 -4588 -5669 -5338 -6502 -4926 -4915 -4040 -7025 -4691 -5166 -6338 -8093 -8611 -5196 -4847 -7342 -7959 -6157 -4272 -6206 -7089 -4014 -7503 -5214 -6541 -4972 -5800 -4768 -6956 -5189 -6655 -7000 -5907 -6435 -5679 -6051 -7509 -4107 -8213 -7366 -7036 -7153 -5975 -4703 -7096 -6893 -5979 -7813 -6990 -5606 -4367 -3486 -5255 -3904 -4757 -6086 -5409 -3668 -4167 -5385 -5652 -5951 -7298 -9008 -3659 -9969 -3570 -3838 -8489 -9281 -6325 -4632 -5692 -4006 -7978 -8046 -6217 -9029 -3959 -8533 -7873 -6925 -10553 -6572 -6749 -7333 -5018 -4226 -8097 -2140 -5348 -10982 -6744 -5389 -6179 -6432 -6590 -5055 -3388 -6886 -8928 -4919 -7251 -4339 -7207 -4635 -8927 -5618 -5349 -5765 -9032 -4414 -3589 -7285 -4930 -6095 -7237 -6544 -5796 -5202 -6615 -4360 -5818 -9690 -6694 -9852 -6670 -4854 -10079 -5810 -5358 -2960 -6808 -9093 -6433 -6691 -7398 -4450 -5210 -7016 -7049 -9275 -8813 -5606 -7128 -6066 -6870 -8113 -7460 -7683 -5670 -5275 -3600 -3045 -5373 -3463 -6738 -8899 -5644 -7143 -5376 -7274 -7051 -6529 -5952 -7215 -5860 -10762 -5283 -7532 -3489 -9415 -4864 -7556 -7716 -4366 -6458 -7221 -6791 -9432 -5434 -4136 -7211 -9163 -2816 -9427 -7128 -5297 -3766 -5852 -5643 -6789 -9297 -3101 -8524 -5852 -4278 -5391 -5460 -12731 -9429 -7534 -7108 -4975 -9728 -7561 -5332 -5481 -6587 -6195 -5811 -4975 -9509 -9023 -2640 -5647 -9180 -5154 -8135 -4638 -5753 -5871 -7062 -8618 -10184 -7946 -6644 -6549 -3522 -6639 -7037 -7671 -6309 -4168 -5353 -5291 -6342 -6393 -6270 -7249 -3352 -6844 -7056 -6565 -5244 -7750 -3222 -7768 -10239 -6221 -7004 -3764 -5020 -6416 -4791 -8772 -9547 -8274 -10174 -7820 -5774 -6143 -6685 -5370 -5830 -5241 -4135 -6303 -6320 -9528 -7723 -3480 -2610 -6721 -6972 -6087 -7698 -7602 -4941 -5531 -9732 -6904 -4351 -5720 -5142 -5190 -7101 -7072 -7675 -6825 -6206 -5798 -7132 -10042 -7307 -6681 -8256 -4703 -6204 -2775 -4953 -4657 -4671 -6536 -4171 -6400 -5720 -5511 -9024 -6256 -7480 -3885 -8560 -7135 -4753 -6606 -4765 -6705 -5877 -5024 -5684 -4810 -6569 -8020 -6290 -6742 -4221 -8933 -9676 -7437 -8167 -6429 -5460 -5635 -5229 -5240 -3757 -5185 -5767 -4268 -6136 -5555 -4683 -9558 -4203 -3888 -5447 -10599 -4649 -8250 -4835 -6394 -4512 -6903 -6124 -7411 -8171 -5291 -8946 -8807 -3661 -5502 -8487 -7862 -4896 -5100 -7086 -7243 -9674 -7648 -6620 -3840 -5767 -4331 -5823 -6787 -5918 -4211 -1799 -8225 -3177 -6836 -6974 -7894 -7138 -6166 -7749 -5686 -6958 -6235 -4160 -8512 -3470 -5545 -7442 -8561 -7661 -3825 -4295 -5083 -5710 -8592 -6538 -6899 -3409 -6643 -6751 -5708 -3409 -9894 -8210 -5836 -10255 -4118 -8197 -4482 -5767 -6185 -5850 -6512 -9903 -7770 -6558 -4783 -10458 -9144 -8244 -6577 -7427 -6206 -6799 -7272 -7787 -5791 -5337 -4964 -4840 -5835 -9198 -8448 -5264 -4754 -6755 -4485 -4868 -7561 -6893 -6513 -9583 -6307 -10257 -8743 -5148 -5254 -6466 -5431 -6958 -5814 -6936 -6166 -7194 -7332 -7320 -4961 -5588 -5814 -8753 -7023 -7464 -6958 -5793 -4543 -8238 -6594 -6081 -6641 -10035 -5699 -4907 -5761 -5853 -4868 -5623 -6051 -5280 -9218 -9392 -5043 -5506 -7608 -9567 -5560 -5636 -4363 -6979 -5684 -6846 -6658 -4899 -3901 -5091 -6160 -6612 -6991 -4549 -7558 -6040 -6381 -4210 -3512 -10288 -5937 -4881 -8414 -4071 -6220 -4647 -8097 -5746 -9628 -7283 -5815 -5076 -5836 -5645 -6603 -9857 -6676 -5797 -6276 -7737 -7256 -6321 -4697 -4955 -5010 -3391 -5477 -9967 -5488 -5921 -6851 -3904 -5609 -6730 -9640 -7171 -5888 -5845 -6723 -6687 -7819 -7886 -7247 -6080 -6939 -6136 -5768 -6513 -5102 -8101 -10410 -5318 -4980 -5293 -4450 -6628 -3342 -5249 -5966 -7834 -8269 -9491 -9206 -4893 -6398 -5040 -3998 -4854 -5368 -5159 -7661 -5747 -5346 -10250 -4939 -5534 -4508 -8935 -5873 -6858 -7619 -7219 -8339 -6246 -6091 -4529 -3566 -9760 -8985 -5171 -6662 -7483 -3860 -5124 -5176 -3610 -5314 -5598 -4974 -6483 -3945 -7052 -5520 -3912 -5034 -8502 -4675 -5417 -6666 -5565 -6318 -6589 -6498 -7172 -3512 -6442 -5013 -6897 -6832 -6749 -7695 -6120 -5814 -5156 -9495 -4453 -6815 -5310 -6050 -5880 -6116 -6412 -9284 -8158 -8196 -6036 -6728 -7611 -7885 -7805 -4987 -4898 -5789 -4712 -5218 -8205 -4568 -10233 -3557 -8195 -3781 -6107 -8171 -8162 -5647 -8971 -5239 -4057 -6131 -11037 -3125 -6790 -5895 -7813 -4011 -6773 -4966 -5444 -5317 -8125 -5221 -5372 -4451 -6729 -6601 -9035 -4325 -6366 -7634 -5762 -5150 -7619 -5901 -6395 -6741 -9536 -3558 -4456 -8406 -9674 -8846 -3124 -7692 -3680 -4191 -4951 -6828 -8297 -6679 -4859 -8279 -6782 -7078 -6755 -8041 -5987 -6404 -6405 -2883 -7984 -6894 -5892 -5380 -5755 -5427 -9294 -3763 -5296 -6255 -8237 -7650 -6064 -9689 -7521 -6886 -5057 -4769 -6973 -8871 -14025 -6114 -5985 -6063 -4657 -7636 -6701 -8524 -4466 -9177 -6362 -8320 -8867 -4290 -5573 -6640 -6491 -7464 -6543 -4911 -8974 -4724 -5803 -6558 -6642 -5103 -11573 -5866 -7313 -10958 -3696 -6941 -8228 -5077 -6196 -6914 -7150 -4745 -6891 -7291 -6433 -4251 -5046 -5348 -6764 -4777 -4157 -5343 -7410 -6760 -8020 -7185 -4740 -3516 -6117 -5366 -5747 -5683 -5449 -7112 -8958 -7603 -7407 -7208 -5992 -7847 -4271 -7162 -7534 -4010 -7207 -6209 -6008 -6138 -7733 -5362 -8837 -5194 -3601 -2696 -5908 -7378 -7940 -5813 -6936 -6040 -3405 -5666 -6642 -4242 -7572 -4911 -6085 -6126 -5783 -6635 -5499 -6433 -4185 -7598 -5507 -5911 -4080 -6852 -4603 -7180 -7817 -7972 -6756 -6051 -9571 -8008 -5618 -1887 -4291 -5811 -4045 -6270 -6017 -5996 -5607 -4423 -5233 -3727 -6668 -3887 -3757 -8246 -5963 -6308 -7348 -5049 -7834 -9453 -3867 -8515 -4463 -8529 -6052 -5363 -8143 -7294 -6913 -4635 -6326 -4691 -7757 -8263 -4385 -6118 -6944 -6765 -4539 -5719 -7884 -5585 -6114 -6981 -8093 -4956 -6243 -8375 -8242 -5184 -6663 -7750 -5784 -6127 -5877 -6372 -7682 -5444 -5199 -6567 -6666 -3510 -7538 -7516 -7255 -4853 -4996 -8205 -5209 -4997 -6658 -6774 -5568 -5077 -5699 -4507 -6504 -6544 -9083 -5718 -5814 -3463 -6291 -6783 -5354 -6483 -8971 -5653 -6860 -5848 -9211 -7203 -7508 -6296 -8163 -5083 -8750 -4360 -14668 -6347 -5047 -10058 -7055 -6304 -5109 -8929 -6059 -8782 -5269 -5768 -8893 -4197 -5550 -5024 -5928 -7055 -3759 -6119 -7343 -6318 -5387 -5599 -4549 -4372 -4981 -3046 -5722 -4456 -4065 -9979 -7635 -5346 -4727 -5369 -5500 -6040 -10097 -6350 -5640 -8070 -6533 -6536 -11393 -7913 -6479 -7701 -7486 -6146 -6930 -6672 -6392 -8148 -5387 -6869 -3323 -4239 -3459 -3886 -5199 -7876 -4194 -8835 -6343 -4680 -5683 -9997 -4788 -4206 -6225 -6442 -6199 -10642 -7102 -7275 -5914 -4925 -7110 -6791 -6514 -8459 -7853 -4513 -5564 -4174 -5791 -4637 -6670 -7492 -4865 -4555 -7987 -7569 -5793 -4829 -6825 -7732 -4018 -3069 -3448 -5324 -5080 -6294 -4761 -8093 -5481 -8080 -6540 -8926 -6328 -5803 -8579 -3600 -4445 -7065 -4589 -7354 -3620 -8281 -7080 -2832 -5968 -5652 -7843 -6464 -3654 -8707 -8270 -9083 -4755 -9020 -8173 -6179 -6341 -7784 -7532 -5144 -6500 -6204 -7549 -8242 -5694 -4876 -3859 -6049 -7522 -7324 -5357 -6663 -4097 -7041 -6710 -5766 -7128 -7772 -6046 -5577 -3671 -3317 -5835 -8510 -6720 -5811 -5112 -7711 -4559 -8265 -3695 -8892 -8217 -6569 -5329 -7674 -8332 -7031 -5977 -8387 -5688 -6985 -6135 -5983 -7568 -5129 -7674 -7615 -4889 -6962 -8491 -5755 -5704 -6091 -6479 -2807 -7144 -4326 -5687 -7563 -3866 -4496 -7804 -5438 -6800 -6319 -6165 -6489 -3699 -8946 -6152 -7120 -4460 -5959 -5475 -5648 -6561 -5756 -8727 -7224 -6611 -9405 -7099 -2909 -7653 -8360 -6632 -11273 -7054 -5689 -4246 -6255 -5366 -6758 -7855 -2402 -7202 -5892 -4326 -3683 -7244 -6039 -4708 -6181 -6670 -5760 -5413 -4285 -6838 -5397 -3638 -4104 -7098 -5205 -9603 -3848 -5155 -6586 -4854 -5708 -6215 -7305 -6836 -5304 -5933 -9235 -5761 -7529 -7866 -5856 -7517 -8857 -9605 -6945 -2840 -5979 -6014 -9829 -5603 -8101 -5229 -6490 -5571 -6458 -3959 -8647 -4842 -7000 -9437 -10156 -6476 -3262 -8683 -5271 -5971 -8059 -9561 -7653 -7651 -4647 -4890 -7095 -13094 -4960 -5626 -8790 -6716 -6118 -6162 -7357 -8987 -6521 -3720 -9214 -7169 -8692 -6463 -7438 -7321 -4718 -8334 -7989 -7413 -5574 -7860 -6292 -6936 -10073 -8149 -5337 -4843 -8127 -7266 -5031 -4007 -8208 -8490 -5468 -7846 -4241 -4599 -9044 -7243 -4217 -5325 -5303 -10683 -8880 -4083 -4759 -5016 -4967 -6860 -4237 -6561 -4011 -8165 -5460 -8611 -7171 -3826 -3767 -8312 -3627 -9266 -6268 -6462 -6530 -8396 -9415 -5381 -5729 -8084 -6118 -5381 -5763 -6819 -4715 -8253 -8311 -9176 -3252 -6014 -4117 -7336 -3601 -3849 -6309 -5429 -5513 -4256 -5565 -13483 -5131 -8357 -6678 -7444 -4807 -7458 -6644 -5360 -3798 -8990 -4823 -4697 -3315 -4499 -5668 -8572 -7101 -5293 -4715 -4922 -10548 -4203 -6276 -5578 -8907 -6363 -6099 -9926 -4063 -7232 -5058 -6759 -7654 -4909 -5911 -8278 -5802 -5918 -6048 -1951 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/best.pt deleted file mode 100644 index b52d93931bffe178db9b6fe11be102ce2d35a6e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14231 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 Jcl*EF{y&myidX;u diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/config.yml deleted file mode 100644 index de58fe337..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k7/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 8, 15, 22, 29, 36, 43] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/dqn.txt deleted file mode 100644 index bc5102028..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -649 -931 -577 -771 -1041 -1137 -719 -1303 -1312 -995 -714 -876 -836 -954 -1335 -1135 -611 -981 -1162 -916 -940 -1113 -1132 -904 -1077 -1461 -888 -889 -923 -1372 -607 -1004 -978 -1580 -751 -1003 -562 -578 -813 -861 -1063 -1454 -1218 -1649 -876 -1090 -693 -1253 -962 -1370 -1809 -1066 -1062 -643 -958 -1309 -798 -1029 -642 -835 -568 -893 -1105 -626 -1197 -931 -966 -1264 -831 -948 -1157 -1187 -829 -866 -1364 -1195 -516 -995 -1117 -815 -1126 -1250 -1589 -1155 -858 -907 -729 -840 -1047 -1114 -812 -756 -1065 -936 -916 -1315 -917 -906 -721 -875 -869 -823 -873 -818 -785 -1055 -829 -791 -919 -1089 -961 -1157 -1472 -1106 -1045 -679 -564 -1264 -1424 -1352 -1054 -1391 -842 -1168 -1061 -1101 -1232 -1231 -570 -968 -1463 -1465 -738 -933 -998 -1413 -1193 -805 -631 -1173 -1382 -737 -685 -816 -1186 -784 -620 -924 -747 -1585 -870 -1424 -1092 -1291 -840 -1165 -725 -570 -949 -1515 -1072 -1010 -748 -1092 -543 -1140 -629 -989 -881 -1543 -988 -603 -984 -906 -1129 -964 -1034 -1510 -715 -1060 -860 -1166 -1055 -1013 -733 -1040 -1238 -1530 -854 -720 -1363 -1038 -775 -981 -868 -1055 -1250 -1306 -826 -1105 -1201 -910 -1003 -705 -831 -731 -789 -1568 -1171 -1289 -806 -715 -1041 -949 -1237 -1290 -1037 -935 -2238 -1087 -625 -912 -794 -684 -829 -743 -1362 -1076 -1255 -1310 -1056 -974 -1081 -476 -1352 -926 -1117 -689 -828 -1150 -848 -868 -1080 -1005 -1052 -919 -1054 -949 -878 -787 -1217 -1043 -1266 -770 -1212 -1480 -927 -1149 -1407 -1211 -917 -801 -889 -807 -862 -705 -1136 -845 -970 -843 -1393 -1251 -853 -979 -494 -934 -1168 -1247 -1051 -725 -705 -968 -1294 -1286 -637 -1206 -1025 -1400 -990 -997 -1194 -1144 -1043 -1313 -859 -933 -767 -1578 -766 -1100 -1223 -992 -793 -1224 -1736 -928 -1168 -1072 -1060 -698 -914 -878 -1077 -618 -641 -890 -1663 -969 -1102 -777 -857 -1271 -792 -838 -1055 -986 -1044 -1096 -671 -1664 -1004 -907 -1016 -1102 -1481 -857 -1693 -1294 -456 -1475 -1309 -1142 -827 -1235 -1042 -822 -1154 -783 -945 -746 -789 -1007 -775 -751 -1168 -871 -1077 -778 -1160 -770 -1634 -854 -1195 -583 -1124 -1341 -1255 -716 -937 -976 -1427 -727 -803 -873 -868 -823 -1405 -563 -837 -860 -716 -632 -1401 -1271 -722 -733 -1020 -850 -1205 -912 -937 -1167 -1352 -700 -1228 -761 -975 -963 -927 -1083 -1227 -637 -1202 -830 -977 -1550 -981 -1156 -893 -1461 -726 -1125 -731 -812 -1019 -887 -855 -869 -1070 -831 -1141 -1070 -684 -816 -922 -1677 -718 -995 -1015 -1264 -1266 -1147 -814 -656 -1541 -1065 -1052 -1390 -797 -797 -1363 -944 -677 -853 -804 -932 -1362 -790 -1158 -939 -1767 -847 -1074 -690 -1050 -1316 -1063 -1152 -1284 -1319 -819 -1022 -1093 -581 -899 -887 -621 -1139 -1014 -1053 -1375 -857 -1167 -785 -1090 -1143 -723 -1028 -1510 -875 -1616 -1084 -1306 -1136 -1083 -1217 -1130 -921 -1041 -1006 -688 -788 -850 -902 -1019 -1261 -1109 -751 -1256 -803 -1401 -1644 -996 -854 -1132 -694 -847 -584 -1344 -860 -716 -904 -1658 -1329 -1157 -1303 -998 -794 -1323 -1389 -1358 -822 -1284 -1231 -986 -1032 -633 -1454 -1230 -1352 -968 -1117 -815 -1013 -627 -660 -667 -1419 -969 -832 -658 -896 -654 -1253 -1332 -981 -856 -895 -1479 -1051 -780 -1211 -1053 -1084 -1300 -804 -1107 -1031 -831 -1485 -805 -1018 -604 -867 -702 -1011 -1563 -1200 -892 -1368 -1239 -1055 -687 -681 -917 -1071 -1361 -1786 -1053 -1092 -1049 -819 -1581 -1285 -1081 -1347 -848 -1291 -1391 -1187 -1745 -971 -981 -1110 -578 -1092 -999 -1593 -789 -706 -1206 -969 -1190 -1655 -931 -1248 -1069 -1196 -919 -958 -1228 -1320 -914 -1489 -981 -1916 -1062 -1129 -1225 -1115 -825 -1045 -839 -965 -1275 -1048 -906 -1147 -1089 -1304 -1066 -865 -1022 -934 -1090 -1004 -1571 -1022 -1043 -1377 -341 -780 -1252 -1249 -1221 -1219 -803 -1258 -1419 -1004 -746 -1337 -785 -1616 -1057 -773 -1104 -1114 -579 -1028 -647 -601 -1292 -1276 -1430 -1138 -1238 -957 -952 -1137 -1067 -1501 -1361 -871 -1179 -1071 -1714 -1358 -997 -1021 -801 -625 -1328 -852 -1006 -948 -992 -1691 -1103 -1404 -1060 -1133 -902 -842 -1212 -786 -885 -896 -954 -1143 -684 -1290 -1430 -949 -1294 -786 -1102 -936 -935 -551 -760 -1038 -561 -1072 -1462 -980 -1311 -938 -1079 -1062 -775 -846 -1056 -1179 -1104 -792 -1124 -1625 -761 -1012 -1049 -717 -1340 -915 -1501 -1241 -608 -1258 -1230 -961 -904 -931 -1022 -821 -1359 -783 -1558 -984 -1123 -1091 -521 -1002 -1052 -1159 -1257 -1188 -1198 -676 -1066 -1327 -887 -1080 -967 -948 -882 -769 -1151 -1208 -1129 -1320 -632 -1045 -731 -992 -1329 -1289 -1002 -818 -997 -954 -1190 -944 -1010 -838 -1596 -946 -713 -1256 -1870 -872 -1280 -817 -1298 -867 -1009 -1000 -1345 -1018 -1135 -948 -943 -709 -1087 -1039 -1472 -1028 -1393 -755 -949 -795 -1632 -688 -585 -1626 -1163 -1352 -1102 -1290 -1042 -866 -778 -1105 -1210 -1043 -1006 -1853 -1179 -776 -697 -1885 -682 -1199 -1169 -1479 -746 -992 -943 -1086 -938 -946 -1137 -1131 -1313 -1187 -1474 -975 -1184 -928 -1205 -1120 -1362 -648 -1067 -998 -900 -947 -963 -1200 -962 -903 -967 -1172 -2083 -915 -1022 -991 -1072 -937 -762 -1110 -998 -1246 -838 -1324 -584 -746 -726 -775 -1118 -1121 -856 -1080 -869 -1235 -965 -1857 -1102 -1212 -1060 -1102 -1179 -1625 -945 -1109 -892 -714 -766 -1401 -535 -971 -822 -1034 -790 -819 -1176 -1061 -926 -1212 -1160 -1607 -1192 -1302 -941 -788 -954 -1428 -1340 -1240 -889 -826 -628 -871 -1104 -1204 -822 -765 -1086 -1061 -1272 -1556 -949 -1222 -787 -784 -966 -673 -780 -1163 -981 -913 -777 -661 -1131 -866 -951 -1110 -823 -1188 -1314 -831 -761 -1130 -914 -1438 -956 -1452 -645 -847 -991 -1432 -788 -768 -924 -1382 -883 -885 -878 -1306 -870 -1123 -1071 -852 -1320 -1116 -1116 -1088 -1261 -1102 -825 -942 -989 -1204 -1275 -1075 -840 -774 -1330 -930 -1127 -1128 -634 -813 -1106 -544 -617 -1109 -1205 -861 -1163 -1196 -574 -1370 -963 -1204 -979 -910 -1107 -540 -854 -1599 -1048 -1557 -1535 -995 -1321 -927 -1110 -916 -1054 -1064 -1244 -1011 -947 -722 -499 -852 -1074 -917 -960 -722 -1011 -1377 -1119 -1419 -1736 -1028 -989 -887 -599 -1360 -803 -1126 -782 -886 -1007 -922 -815 -1169 -641 -1404 -677 -1027 -1113 -541 -800 -1351 -1222 -1273 -803 -1069 -904 -778 -825 -1092 -734 -992 -1028 -1781 -584 -1244 -1309 -1172 -1245 -1272 -1216 -1337 -937 -822 -1760 -1303 -574 -1398 -1065 -827 -1423 -923 -1176 -1125 -1745 -1069 -1009 -1331 -871 -950 -1418 -1246 -928 -1266 -1054 -1250 -960 -637 -905 -1517 -1256 -1059 -760 -1267 -1106 -1290 -794 -836 -985 -1219 -944 -1392 -1142 -914 -1276 -1244 -682 -805 -1084 -1508 -732 -1781 -1521 -830 -1107 -678 -800 -1248 -889 -1159 -1075 -1539 -1239 -1096 -1017 -1208 -829 -652 -1030 -915 -1260 -1303 -870 -902 -1041 -979 -1377 -1040 -1408 -1185 -638 -1140 -1194 -1111 -1122 -982 -877 -1209 -1211 -1051 -632 -1179 -1151 -1280 -914 -1370 -841 -1550 -876 -865 -1128 -863 -1035 -516 -1034 -913 -1190 -1351 -1116 -725 -788 -1536 -1164 -1155 -1295 -1176 -806 -1079 -1207 -1051 -332 -492 -495 -687 -1625 -720 -1107 -1510 -1798 -770 -914 -876 -1909 -1326 -845 -1106 -1063 -1302 -750 -758 -1373 -1006 -982 -735 -1413 -1516 -1159 -869 -1429 -957 -1177 -620 -840 -2134 -667 -963 -898 -1072 -897 -903 -859 -927 -1312 -1588 -965 -1262 -955 -1339 -913 -1309 -928 -1340 -572 -1320 -1162 -1406 -1007 -997 -1104 -1134 -442 -890 -937 -1114 -1102 -818 -785 -1130 -1088 -895 -819 -814 -1153 -1518 -2006 -1146 -962 -1060 -853 -843 -1393 -866 -1255 -404 -807 -1258 -1103 -624 -843 -936 -851 -1059 -501 -920 -1657 -1036 -1398 -1170 -676 -817 -1101 -1401 -1003 -674 -930 -1106 -1020 -1145 -1128 -1112 -1298 -1250 -1429 -927 -1097 -956 -984 -1707 -1567 -1129 -1326 -875 -1083 -1821 -885 -960 -901 -1294 -1051 -978 -1624 -962 -1080 -997 -1459 -763 -1227 -556 -629 -1035 -1205 -554 -873 -890 -718 -820 -601 -1113 -740 -1108 -1403 -917 -1820 -1226 -836 -1241 -1094 -678 -834 -660 -1276 -1056 -671 -733 -858 -832 -1259 -1524 -614 -1013 -1253 -919 -1044 -916 -891 -1116 -652 -1843 -717 -1448 -978 -1019 -933 -1010 -1071 -1308 -1204 -1150 -1122 -693 -1250 -1394 -720 -991 -690 -1419 -658 -1169 -887 -848 -1536 -1107 -1477 -750 -1330 -1095 -1249 -1102 -488 -1030 -969 -1205 -1117 -1234 -1634 -891 -1099 -703 -1333 -1285 -1174 -1101 -841 -909 -1339 -1245 -481 -951 -1107 -1359 -1123 -1097 -1018 -1075 -1011 -802 -1151 -676 -845 -914 -863 -1546 -1364 -1108 -935 -1131 -621 -1330 -1240 -835 -1067 -955 -1070 -955 -698 -1027 -769 -1696 -1665 -1218 -958 -601 -1058 -1321 -876 -1445 -975 -882 -898 -1144 -1921 -785 -748 -968 -1138 -810 -772 -708 -816 -1221 -1363 -1513 -1117 -1446 -1069 -1572 -1705 -1033 -1118 -1290 -843 -1318 -899 -1033 -739 -863 -1083 -1570 -963 -1147 -740 -669 -932 -946 -994 -446 -998 -965 -790 -1347 -1132 -1030 -1218 -952 -819 -1028 -1279 -758 -1644 -955 -861 -1143 -1137 -747 -938 -1322 -734 -1564 -1637 -1178 -653 -1150 -1021 -1067 -1219 -566 -1166 -488 -1230 -603 -1482 -1347 -927 -694 -1063 -802 -902 -674 -1187 -1651 -1338 -1705 -901 -1185 -658 -1181 -1062 -863 -1029 -662 -1038 -1178 -1056 -853 -1241 -927 -1667 -1603 -1132 -1058 -1141 -1510 -1326 -1164 -1144 -1050 -1135 -1361 -1023 -1095 -1690 -881 -1126 -613 -766 -897 -1112 -1268 -1495 -916 -1259 -1345 -649 -724 -998 -872 -1184 -1205 -784 -981 -668 -982 -670 -1047 -1163 -518 -1241 -1176 -973 -1143 -1102 -803 -1522 -714 -942 -1341 -1742 -758 -821 -940 -937 -1537 -648 -1374 -634 -810 -792 -801 -1506 -1473 -1536 -671 -926 -735 -1071 -871 -912 -802 -951 -1007 -844 -980 -968 -952 -823 -771 -965 -1008 -1499 -837 -527 -904 -1100 -854 -1114 -829 -1049 -1285 -1062 -844 -1145 -1095 -926 -1299 -530 -1269 -935 -892 -894 -1343 -938 -1157 -1162 -1255 -1107 -587 -814 -1028 -1236 -1306 -598 -643 -917 -991 -1100 -975 -1389 -786 -1433 -702 -846 -1330 -1251 -1013 -974 -631 -1569 -734 -833 -1290 -940 -1045 -1584 -1088 -1302 -1543 -786 -1823 -1290 -905 -1103 -833 -1340 -876 -729 -654 -1081 -909 -1089 -1232 -732 -1156 -783 -989 -588 -734 -566 -975 -1477 -1710 -1170 -868 -1080 -1115 -1054 -1008 -642 -1008 -1553 -725 -960 -906 -1306 -860 -529 -764 -732 -1353 -1171 -936 -1268 -751 -791 -1430 -898 -1159 -1058 -979 -1479 -854 -918 -884 -1123 -590 -642 -995 -1062 -1159 -1385 -1513 -1090 -1223 -737 -1231 -1432 -873 -1292 -1068 -1333 -831 -1364 -1002 -1500 -993 -1166 -603 -1021 -982 -1621 -1288 -1045 -1440 -1261 -1315 -1024 -1385 -1129 -1126 -952 -941 -885 -1155 -1516 -1050 -877 -1361 -1344 -844 -1216 -929 -1052 -1420 -1438 -740 -837 -836 -1112 -1336 -897 -853 -1354 -896 -1093 -707 -1403 -1001 -1211 -845 -1041 -1502 -986 -1554 -1286 -1203 -1075 -1153 -1424 -1271 -670 -976 -673 -828 -946 -1588 -995 -1180 -796 -492 -1168 -1388 -1336 -1084 -1657 -784 -891 -871 -909 -1014 -760 -1128 -1392 -1190 -724 -951 -734 -988 -1206 -1116 -885 -1187 -1229 -786 -1020 -880 -1974 -992 -669 -1661 -1537 -939 -739 -1665 -1162 -475 -1189 -1466 -702 -953 -1148 -935 -1092 -1185 -671 -1109 -1493 -1397 -1128 -1025 -1092 -669 -1518 -982 -1061 -1917 -1010 -747 -1200 -1281 -795 -1187 -1238 -787 -1031 -1171 -706 -693 -975 -695 -1472 -1010 -1060 -1580 -1091 -1217 -820 -1049 -937 -652 -646 -773 -1195 -1067 -1404 -930 -1292 -1031 -533 -1467 -1324 -690 -934 -733 -853 -1008 -1372 -1264 -1152 -1507 -1204 -1510 -558 -1185 -1106 -1218 -723 -871 -1141 -960 -1364 -966 -1067 -1179 -811 -1257 -1124 -762 -959 -744 -1039 -1066 -728 -848 -1395 -1259 -952 -1148 -1422 -1140 -942 -982 -456 -1351 -740 -1340 -1506 -1731 -909 -901 -723 -901 -788 -1579 -1260 -883 -1088 -1454 -809 -1175 -1047 -595 -973 -974 -1131 -1265 -1208 -1060 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/optimal.txt deleted file mode 100644 index a862722e1..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -898 -933 -967 -1997 -622 -961 -993 -1346 -1112 -1169 -867 -1419 -1252 -885 -1318 -1545 -1107 -1219 -1352 -1377 -1167 -869 -1074 -846 -799 -986 -687 -1039 -733 -1095 -1180 -762 -1287 -1315 -906 -886 -1032 -906 -763 -1143 -792 -993 -1593 -1525 -994 -784 -784 -1267 -472 -1147 -1623 -1503 -896 -601 -923 -1079 -1431 -1233 -772 -1429 -956 -1126 -896 -1285 -812 -1884 -1058 -767 -635 -862 -1138 -871 -933 -1093 -957 -942 -935 -1338 -1442 -722 -851 -1776 -1251 -1823 -1006 -952 -1063 -1041 -747 -1076 -732 -925 -1257 -985 -1107 -1007 -1071 -1067 -923 -1147 -843 -983 -1217 -1760 -935 -897 -1309 -1045 -1068 -1463 -1032 -1187 -1228 -1016 -1336 -725 -1163 -1091 -740 -1324 -785 -1031 -910 -1252 -698 -1038 -1074 -1004 -1124 -1186 -1236 -943 -1509 -1218 -806 -1099 -1403 -970 -1148 -671 -1076 -782 -1141 -553 -1506 -825 -1015 -1010 -1316 -945 -526 -748 -852 -974 -737 -921 -934 -932 -1072 -840 -735 -1024 -1022 -1171 -1487 -1012 -1077 -746 -1335 -904 -1182 -1081 -757 -1295 -519 -914 -1005 -1303 -1186 -1844 -812 -488 -1536 -1028 -1443 -1212 -1031 -1267 -847 -830 -939 -1141 -735 -992 -1158 -1135 -1635 -820 -1145 -805 -1041 -1396 -1167 -1624 -950 -1766 -898 -1086 -876 -1034 -1380 -1802 -694 -856 -796 -1103 -1150 -863 -633 -1202 -830 -877 -1084 -792 -837 -1080 -1442 -1400 -663 -954 -1225 -1170 -845 -476 -1030 -1175 -820 -1117 -817 -760 -1009 -1401 -1060 -940 -1034 -1204 -794 -1213 -966 -1373 -1171 -1248 -1090 -1097 -1189 -915 -885 -1124 -932 -1030 -889 -1726 -1013 -1264 -911 -934 -1500 -1317 -1219 -628 -792 -783 -1104 -907 -1596 -961 -1062 -1135 -935 -950 -1031 -933 -1411 -1039 -447 -1164 -1632 -811 -780 -1050 -1194 -922 -812 -1057 -989 -687 -925 -959 -653 -1007 -1064 -1195 -1959 -753 -932 -1242 -1060 -1149 -1248 -1314 -1393 -1271 -1622 -1320 -1074 -880 -1030 -1451 -1481 -638 -936 -1246 -792 -793 -1297 -928 -1174 -833 -1033 -796 -954 -1341 -1016 -1638 -519 -1037 -1135 -780 -1236 -1117 -751 -1208 -1077 -872 -1465 -1035 -1212 -1165 -1131 -1015 -1034 -1062 -957 -1213 -640 -1162 -1425 -849 -1103 -958 -660 -963 -1081 -1422 -1362 -1018 -1231 -1138 -972 -974 -647 -643 -902 -1319 -1260 -1799 -1279 -1043 -1105 -806 -978 -1014 -1087 -1505 -680 -989 -746 -850 -716 -861 -732 -1306 -802 -1085 -935 -780 -1438 -831 -840 -972 -725 -1296 -731 -1423 -943 -1700 -1005 -952 -1361 -1090 -876 -977 -1278 -1487 -872 -1404 -995 -813 -1175 -1662 -1292 -847 -915 -881 -1376 -1239 -530 -972 -1172 -1006 -797 -1531 -1174 -1139 -999 -1248 -897 -752 -620 -1256 -989 -1177 -1422 -1477 -951 -954 -953 -711 -1372 -950 -1206 -1712 -1028 -842 -1014 -973 -1063 -1684 -1041 -760 -719 -688 -1458 -1144 -1063 -1503 -978 -941 -1037 -1037 -728 -698 -754 -1149 -1295 -837 -1293 -1294 -821 -962 -726 -1040 -1631 -1332 -1329 -797 -1181 -1118 -932 -560 -688 -727 -643 -606 -908 -920 -665 -741 -1336 -1030 -937 -728 -1144 -1298 -1072 -720 -1029 -1430 -1002 -1088 -643 -1392 -970 -812 -1361 -976 -959 -1075 -1169 -974 -1408 -848 -666 -952 -767 -911 -1165 -1037 -1052 -1463 -927 -1105 -1292 -1363 -1047 -857 -753 -1015 -723 -911 -658 -1337 -855 -1306 -1047 -634 -1192 -1246 -1033 -870 -1387 -868 -819 -995 -877 -1112 -923 -665 -975 -1519 -609 -935 -1132 -1346 -587 -1197 -1169 -872 -1506 -1575 -857 -974 -766 -1029 -941 -1613 -1252 -1021 -937 -1204 -1515 -973 -1456 -1211 -767 -671 -879 -1262 -868 -922 -767 -984 -960 -1540 -1100 -853 -632 -1033 -697 -1277 -971 -1394 -1252 -973 -1231 -825 -1316 -497 -852 -1163 -999 -1436 -967 -805 -1127 -1603 -1313 -1180 -1481 -918 -968 -695 -1096 -822 -1166 -632 -653 -1333 -587 -1311 -1144 -846 -1270 -742 -707 -505 -1064 -1257 -796 -1092 -1362 -992 -808 -786 -1125 -733 -775 -833 -1742 -863 -1021 -1183 -1295 -1230 -787 -895 -1416 -809 -572 -1498 -923 -601 -876 -888 -1062 -532 -1536 -1014 -1747 -1065 -1216 -1807 -536 -1272 -1131 -817 -953 -1103 -1111 -1248 -1597 -856 -981 -946 -1149 -1327 -874 -1148 -752 -810 -930 -963 -1150 -666 -796 -873 -1879 -1062 -886 -1662 -1056 -968 -1142 -648 -1004 -1312 -860 -716 -592 -895 -1489 -590 -1276 -525 -783 -952 -846 -1055 -1151 -822 -1052 -1220 -1094 -1166 -1188 -1525 -1148 -1140 -780 -696 -1158 -881 -1009 -789 -860 -1201 -843 -1291 -1497 -941 -1501 -780 -1072 -1197 -942 -1600 -1129 -581 -1061 -1751 -993 -1312 -999 -729 -1116 -996 -715 -1094 -853 -1046 -840 -717 -925 -960 -1025 -1160 -1122 -1281 -839 -1191 -967 -1331 -1179 -1188 -946 -1299 -839 -1370 -1116 -1133 -903 -1212 -1016 -952 -1418 -987 -748 -1294 -1016 -1567 -1292 -911 -1199 -1201 -962 -736 -1472 -1554 -1089 -893 -1447 -1003 -1507 -1109 -982 -1187 -1091 -613 -1221 -1039 -1033 -1112 -1211 -912 -924 -1020 -603 -2337 -950 -1172 -911 -1186 -800 -866 -1234 -1068 -729 -1099 -913 -1458 -1106 -983 -1043 -930 -1097 -1274 -866 -923 -1396 -723 -1173 -892 -1093 -1105 -1254 -1275 -1352 -1027 -788 -479 -1534 -774 -948 -1428 -1299 -718 -956 -1071 -1125 -1776 -1517 -856 -1283 -1016 -807 -933 -894 -725 -1270 -1193 -1227 -1373 -1190 -1351 -1565 -585 -1114 -936 -1483 -1193 -1027 -1209 -1374 -961 -1032 -870 -957 -1094 -1405 -740 -444 -917 -830 -894 -1252 -910 -947 -1164 -1201 -1322 -1362 -832 -512 -881 -615 -852 -734 -1655 -1187 -883 -1260 -1670 -980 -1182 -1056 -992 -809 -746 -1028 -1310 -1311 -1350 -816 -1093 -1287 -1152 -1069 -1234 -789 -734 -949 -988 -1539 -1246 -1226 -429 -1039 -1157 -880 -1472 -1093 -1213 -735 -678 -1266 -921 -1081 -869 -1254 -1512 -1055 -720 -1056 -788 -1126 -808 -416 -1087 -1164 -930 -1067 -853 -905 -470 -1206 -709 -973 -1009 -1031 -1147 -934 -1016 -1226 -860 -999 -809 -1537 -1513 -1319 -518 -1332 -951 -1079 -1016 -1060 -1198 -1287 -1068 -1071 -1457 -1510 -832 -733 -984 -763 -809 -777 -634 -1528 -1180 -746 -1209 -1147 -1388 -789 -1257 -725 -1469 -854 -632 -958 -926 -802 -890 -1194 -783 -980 -1070 -848 -1413 -1131 -865 -1514 -1011 -945 -1183 -1152 -1032 -912 -1141 -1140 -762 -856 -1841 -1609 -1112 -921 -1282 -599 -1040 -1013 -1111 -1128 -1055 -1149 -1068 -1115 -1276 -792 -1050 -1364 -1325 -1084 -1235 -1139 -607 -1026 -1009 -848 -1317 -872 -1519 -1369 -861 -1017 -678 -1132 -1417 -936 -862 -940 -977 -1152 -744 -1271 -1200 -1317 -1206 -1157 -914 -1672 -1021 -832 -1084 -1213 -1279 -919 -1240 -684 -742 -656 -1434 -1252 -1624 -1087 -1228 -1087 -861 -694 -1515 -936 -697 -1599 -645 -1032 -965 -1430 -960 -1443 -884 -1571 -658 -1031 -1089 -1387 -1232 -997 -756 -1299 -943 -1203 -993 -1088 -762 -1228 -820 -1038 -929 -1114 -1428 -769 -1046 -624 -1223 -751 -1001 -1416 -938 -1169 -887 -676 -792 -1003 -1202 -1364 -1035 -1304 -1130 -959 -1276 -939 -568 -835 -1185 -1052 -1168 -905 -995 -710 -1385 -940 -1041 -699 -845 -842 -1058 -1263 -618 -1227 -1937 -858 -1347 -1365 -666 -1077 -1304 -1078 -898 -1243 -1059 -820 -1152 -917 -1288 -1159 -723 -551 -838 -959 -649 -1141 -1007 -1154 -835 -1063 -982 -1291 -978 -1336 -1372 -802 -1617 -1277 -613 -1111 -1226 -850 -1157 -1172 -1045 -990 -871 -684 -1241 -948 -1048 -528 -928 -999 -852 -1602 -1450 -1547 -934 -1218 -691 -747 -970 -734 -635 -920 -1349 -971 -1022 -1464 -927 -1459 -1290 -977 -858 -1280 -872 -364 -826 -1281 -1182 -1597 -911 -1724 -1143 -927 -1466 -1074 -1253 -1881 -913 -937 -765 -989 -1023 -810 -875 -959 -906 -1134 -814 -1347 -1443 -1076 -668 -857 -945 -1268 -1023 -1326 -1797 -1000 -1023 -1042 -962 -1168 -941 -1038 -840 -769 -822 -879 -979 -1507 -702 -1507 -553 -1083 -1105 -1267 -1108 -1365 -1014 -849 -819 -983 -920 -1512 -1220 -1125 -1066 -1038 -753 -845 -728 -1224 -610 -1181 -1064 -1525 -1091 -953 -845 -1010 -960 -1364 -716 -1488 -1116 -1021 -1578 -1020 -1208 -1272 -823 -1201 -893 -887 -1321 -1168 -558 -1126 -1000 -1068 -1292 -974 -1249 -999 -1192 -1245 -1003 -743 -1543 -1369 -1440 -932 -678 -857 -1333 -813 -888 -993 -733 -1473 -1223 -1679 -1096 -865 -468 -1504 -866 -606 -1651 -1232 -1049 -849 -756 -1008 -1308 -1451 -1428 -644 -1159 -1045 -1207 -1154 -1502 -964 -1184 -942 -928 -1097 -1118 -1141 -1003 -638 -1048 -884 -835 -1152 -1241 -1047 -1214 -1330 -1653 -578 -1096 -702 -1037 -988 -1115 -1145 -968 -1013 -1020 -1264 -861 -1052 -1139 -1177 -1288 -671 -909 -922 -1608 -847 -958 -995 -989 -1089 -875 -1044 -977 -734 -575 -898 -1416 -885 -903 -1287 -1087 -864 -1125 -831 -1128 -617 -1110 -1065 -1331 -1108 -1011 -1059 -1117 -879 -919 -1111 -884 -536 -1245 -1341 -1141 -1049 -1321 -1237 -1045 -1188 -1407 -1277 -1074 -908 -1555 -1323 -1183 -1514 -810 -1157 -1394 -1215 -785 -871 -883 -1020 -1105 -996 -1068 -1031 -809 -1389 -1223 -545 -1121 -899 -811 -739 -1479 -915 -943 -1369 -749 -945 -1168 -1136 -475 -1014 -613 -936 -1123 -916 -765 -857 -639 -754 -1146 -1482 -1266 -999 -709 -1292 -714 -1001 -698 -1216 -2022 -1045 -984 -528 -1574 -1357 -1019 -1380 -1256 -796 -705 -1406 -921 -924 -1326 -1334 -845 -1769 -1067 -1218 -1164 -1087 -904 -1341 -1045 -1094 -1010 -794 -1024 -1123 -933 -1121 -1170 -737 -997 -1515 -1626 -802 -813 -813 -587 -1107 -1344 -1187 -774 -848 -746 -881 -959 -1218 -976 -1049 -858 -1000 -1103 -1139 -1370 -953 -831 -594 -1428 -1057 -751 -1258 -774 -962 -1104 -1378 -1106 -804 -1295 -544 -676 -1088 -966 -1346 -1047 -1020 -1628 -845 -642 -650 -1135 -880 -913 -1002 -809 -677 -1345 -1311 -720 -774 -1196 -659 -414 -1077 -800 -1113 -776 -792 -1103 -866 -1051 -1375 -970 -747 -813 -1536 -1118 -1042 -897 -802 -828 -884 -850 -636 -1356 -927 -1078 -972 -787 -1124 -639 -1050 -1356 -972 -1044 -1391 -738 -1579 -1099 -1474 -943 -1628 -755 -1318 -472 -1028 -1499 -1318 -962 -818 -919 -1059 -661 -790 -1047 -1145 -884 -923 -711 -927 -585 -1004 -1053 -1324 -963 -1068 -793 -1681 -947 -1163 -842 -858 -1014 -935 -1166 -716 -1467 -1127 -1497 -1046 -835 -891 -1015 -952 -1169 -752 -1405 -815 -937 -1041 -896 -863 -1067 -1053 -1238 -854 -1251 -1033 -1259 -895 -1001 -562 -1548 -969 -1045 -1407 -485 -1241 -914 -1301 -1589 -1270 -1087 -716 -946 -1574 -1465 -935 -1232 -1163 -750 -908 -1123 -631 -725 -1320 -1039 -1477 -627 -1211 -1061 -1373 -1329 -972 -562 -1006 -1108 -1178 -964 -1538 -699 -746 -720 -1152 -818 -849 -950 -1126 -1406 -950 -837 -782 -974 -1369 -1414 -969 -950 -1112 -1090 -484 -873 -776 -890 -1134 -668 -704 -825 -859 -1101 -1395 -697 -765 -1164 -1816 -1393 -935 -995 -1074 -1235 -1149 -1056 -600 -1109 -1027 -1187 -1589 -1166 -1093 -1518 -1007 -759 -1465 -868 -772 -1034 -1148 -890 -1009 -740 -1348 -1198 -1088 -1191 -1312 -1225 -1147 -647 -880 -1012 -1181 -1487 -933 -1248 -972 -911 -798 -902 -1299 -861 -774 -1395 -1295 -1199 -445 -1044 -826 -1329 -1015 -875 -1014 -656 -678 -1262 -1088 -836 -692 -1203 -957 -943 -1031 -827 -1064 -1143 -1066 -1043 -1183 -1746 -1168 -1313 -942 -1203 -1203 -884 -1070 -1103 -1274 -1864 -1464 -815 -1218 -508 -1249 -679 -670 -1032 -1173 -814 -988 -1102 -1055 -578 -1094 -1181 -776 -1380 -719 -1284 -1468 -1132 -768 -1079 -930 -461 -676 -1347 -791 -973 -1053 -718 -1095 -928 -953 -871 -1304 -977 -1243 -1149 -776 -1291 -1431 -1161 -859 -792 -1054 -953 -1025 -873 -1048 -892 -952 -1049 -1246 -924 -1018 -869 -1204 -902 -581 -405 -952 -1063 -726 -1054 -895 -1578 -1182 -1534 -733 -600 -551 -871 -936 -1407 -1239 -745 -902 -1137 -1048 -1205 -1113 -661 -951 -888 -835 -1363 -975 -1700 -1589 -1124 -962 -1298 -1357 -1361 -991 -1270 -715 -1508 -1163 -1212 -684 -1120 -872 -1495 -877 -1185 -839 -1474 -1428 -1259 -977 -798 -928 -816 -1243 -794 -887 -1238 -949 -1173 -1286 -987 -849 -913 -1092 -1394 -1183 -851 -870 -709 -987 -1283 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/random.txt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/random.txt deleted file mode 100644 index 8cec03755..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -6352 -11123 -7196 -5975 -5567 -10788 -5634 -8944 -5104 -8996 -7380 -8371 -9180 -5890 -5272 -3703 -4042 -6401 -6068 -8427 -6370 -7450 -8008 -6626 -8612 -7230 -7465 -7262 -6646 -5009 -8725 -6777 -5264 -5268 -6407 -7169 -7104 -5609 -8884 -4948 -8040 -5613 -5225 -6576 -8655 -11405 -9673 -10670 -7157 -9908 -5991 -9600 -7814 -5422 -7212 -5805 -10071 -8906 -9494 -4900 -6038 -5628 -5424 -5977 -4391 -5250 -4775 -5210 -6267 -2570 -8799 -10055 -8657 -7542 -7031 -7854 -6328 -4609 -7646 -6012 -5252 -6045 -6008 -8482 -7073 -7399 -9019 -7073 -8344 -7975 -9613 -6416 -5342 -8193 -7083 -6963 -7999 -7803 -6968 -8837 -3941 -8766 -7527 -6511 -7982 -6291 -11640 -7382 -8084 -5618 -6847 -10310 -3433 -6526 -9026 -10111 -6964 -6813 -6902 -6662 -6535 -7113 -10572 -6992 -7210 -10410 -4192 -9502 -5431 -6938 -6813 -6861 -5031 -9467 -7873 -6072 -6092 -8210 -3725 -7177 -6423 -5010 -4044 -9276 -7065 -9076 -6203 -7412 -6605 -6854 -7991 -7797 -9935 -8848 -4610 -7949 -12509 -7915 -5318 -9041 -5914 -9757 -7407 -5821 -7171 -5366 -4107 -6507 -9086 -6590 -10212 -4521 -7588 -9351 -5010 -5112 -7522 -11534 -5350 -5038 -8286 -8605 -5506 -5465 -9186 -5595 -9749 -5119 -7286 -6128 -11873 -6211 -6866 -5963 -6653 -5035 -8899 -8121 -11301 -8492 -4686 -9265 -9801 -6965 -5058 -4948 -5733 -8611 -6237 -5470 -3055 -10397 -8192 -7757 -4767 -5343 -4232 -5432 -6813 -7581 -2635 -7293 -5408 -9242 -8301 -6183 -6472 -8912 -5600 -8804 -7641 -6768 -5675 -7405 -5846 -5337 -6170 -7110 -9096 -7183 -7672 -4925 -7421 -9572 -5704 -9947 -9164 -2923 -10293 -4365 -4567 -7116 -10374 -4363 -6630 -3887 -8771 -6582 -9079 -7426 -10168 -5542 -6939 -9099 -6510 -9341 -7908 -8097 -3183 -7561 -5197 -8428 -9918 -7503 -5983 -10346 -5947 -6966 -9217 -6603 -7867 -7235 -8411 -7250 -7537 -8534 -6698 -8745 -7646 -4541 -5607 -7462 -13140 -11427 -5908 -8339 -7092 -4071 -10369 -3971 -8015 -6635 -10950 -5869 -7919 -7659 -6435 -4710 -9174 -7751 -4759 -7343 -9449 -5315 -7307 -6681 -6324 -6239 -5654 -7127 -7276 -7685 -6339 -6698 -5640 -7703 -11495 -5223 -6118 -4853 -7321 -6607 -8258 -7343 -8883 -5906 -7367 -9332 -9021 -5000 -6869 -12649 -4068 -7872 -7323 -3256 -6999 -8543 -6111 -9675 -10237 -8575 -4917 -7231 -9450 -9928 -7934 -9288 -6729 -4546 -6926 -5932 -5827 -4999 -7327 -6287 -6565 -7474 -9373 -4421 -9107 -5117 -11303 -6136 -6502 -6664 -10124 -5527 -6239 -7882 -7344 -7118 -6101 -5814 -5835 -3475 -7762 -8536 -6893 -8995 -8114 -9653 -11322 -6493 -8785 -6144 -5728 -7765 -6670 -7999 -7278 -7753 -4416 -6476 -4701 -5892 -7697 -10841 -5273 -8469 -7431 -6840 -8005 -9405 -5949 -5456 -11723 -5488 -7606 -9563 -6316 -6403 -5469 -8882 -7983 -8223 -4773 -7561 -6025 -8274 -4600 -6499 -4208 -5330 -6018 -6220 -4716 -8628 -8764 -9988 -6915 -4884 -4538 -4767 -8802 -8936 -5241 -6591 -9598 -6868 -5764 -6141 -5992 -5649 -7939 -7855 -11426 -9131 -6831 -5861 -5186 -6358 -6367 -10950 -4649 -6219 -5413 -5484 -4503 -6406 -9534 -3309 -9719 -5870 -7964 -5348 -10092 -6111 -4995 -6905 -8898 -7407 -6813 -4204 -5073 -9128 -7717 -8884 -7003 -6480 -7500 -10025 -9981 -7542 -5559 -6912 -4578 -5490 -3667 -8410 -7102 -8546 -6888 -4997 -7700 -7585 -5980 -8780 -8901 -9600 -6394 -8334 -9595 -4496 -4436 -6118 -5836 -3285 -5837 -5611 -4934 -9668 -7669 -8802 -6985 -5818 -7415 -3860 -7452 -4390 -8719 -5348 -6554 -5853 -5493 -5625 -7600 -5322 -4891 -10390 -8562 -6962 -6142 -6800 -4710 -10549 -8078 -6768 -5641 -7540 -11427 -6181 -9874 -9468 -5029 -10372 -6537 -8802 -6552 -8797 -7447 -4452 -9396 -8168 -7231 -7521 -10004 -7828 -6369 -6928 -6665 -7608 -5080 -6265 -5148 -5462 -11144 -5497 -5569 -6711 -5875 -11612 -3803 -10496 -7616 -6403 -4116 -8351 -7716 -5044 -8208 -5911 -3319 -10730 -9670 -6891 -7826 -8208 -4551 -11974 -4652 -7254 -3422 -5425 -8989 -8479 -5786 -6665 -6063 -7600 -4924 -6875 -7548 -8799 -9634 -5336 -5134 -8158 -5478 -5338 -4359 -4858 -6810 -6727 -7746 -7467 -7648 -9573 -10283 -4621 -7316 -8845 -8920 -10154 -8492 -7024 -5801 -9385 -6194 -8846 -6847 -2921 -9155 -6242 -9944 -8192 -7038 -7414 -4636 -6043 -7136 -6389 -7461 -7227 -8640 -6632 -6009 -4781 -5303 -5547 -6323 -6213 -7402 -4650 -8633 -4489 -7571 -9373 -5221 -9470 -7266 -10279 -7084 -8672 -9659 -4971 -3581 -9245 -4882 -4942 -8004 -8976 -9899 -7315 -7819 -6445 -5965 -6842 -5799 -6029 -10700 -6594 -4978 -5960 -5779 -5186 -10872 -7380 -9132 -4153 -7008 -5647 -6179 -3717 -7797 -6165 -11359 -8821 -9488 -9766 -5693 -6191 -8364 -8436 -4628 -9007 -8143 -7238 -7749 -5831 -5136 -8830 -6382 -8501 -7593 -7947 -5152 -10746 -7522 -6386 -6492 -7612 -5108 -5558 -6621 -7119 -11364 -10076 -4702 -4404 -5224 -8131 -7350 -6734 -4681 -5915 -7735 -8361 -8334 -6421 -8592 -9336 -8171 -4984 -6252 -8743 -2903 -7620 -7229 -7467 -6293 -5070 -7031 -7830 -4019 -5718 -5503 -5287 -7157 -3525 -4732 -8786 -3273 -4518 -5215 -4053 -5525 -5662 -5895 -8464 -3673 -5390 -8948 -7630 -8370 -6068 -6416 -4691 -5990 -8431 -5529 -4096 -7023 -8444 -5903 -7107 -7088 -6142 -3131 -4999 -8316 -5059 -6693 -5470 -5426 -6475 -3325 -7970 -5287 -7960 -7083 -4938 -7447 -7972 -8833 -5683 -6268 -6344 -5114 -6930 -7531 -7164 -6282 -5839 -6072 -8272 -6342 -6847 -7789 -6927 -6887 -7598 -5841 -6897 -5773 -8414 -6572 -6960 -7431 -8826 -5261 -6589 -10633 -6131 -6107 -4539 -6515 -7865 -7864 -6591 -5209 -5932 -6537 -4870 -3039 -10418 -8984 -4729 -6131 -9077 -11142 -10926 -5234 -5408 -6093 -6722 -4114 -4173 -5018 -5678 -6016 -5115 -8663 -8102 -5629 -6109 -6200 -6156 -9230 -9473 -6913 -5166 -6687 -11807 -6431 -7468 -9811 -8673 -6206 -10255 -7084 -7537 -5645 -9094 -7834 -6749 -5806 -5796 -4610 -7891 -8072 -9379 -6867 -6205 -7525 -7771 -6441 -8530 -6776 -9822 -6537 -6243 -7698 -5884 -7423 -10558 -4930 -7220 -3784 -7614 -6269 -5442 -7235 -8825 -9229 -9607 -9253 -5272 -6075 -6142 -6679 -3772 -8499 -5460 -8011 -5628 -6841 -7398 -7461 -9136 -5081 -8211 -7228 -5911 -7515 -7715 -7929 -4388 -4199 -5719 -6069 -6908 -6451 -8882 -5503 -12124 -9377 -6563 -3406 -4007 -6892 -5276 -5088 -7226 -8074 -3940 -5626 -11620 -6750 -10267 -8479 -3168 -5040 -5242 -7173 -5909 -7899 -8138 -7795 -8428 -4607 -6332 -5190 -7483 -4914 -6168 -5538 -5575 -5538 -5732 -8857 -8836 -10471 -4986 -4287 -5687 -10524 -10833 -7978 -5657 -5976 -8735 -7024 -9823 -4736 -7776 -4774 -5079 -8307 -7480 -6611 -8348 -3855 -4968 -7405 -2678 -8258 -7280 -3174 -6712 -8752 -5472 -9710 -7962 -4921 -8385 -5962 -7056 -5729 -7812 -10137 -5008 -7024 -7728 -6681 -7950 -5809 -5064 -7176 -5364 -6256 -4048 -8810 -5200 -10623 -2789 -9336 -3561 -10562 -5524 -10338 -4719 -11103 -3042 -7981 -7050 -6608 -8446 -6591 -10839 -6857 -6871 -4398 -6402 -13230 -11864 -8872 -6312 -5603 -10055 -10849 -8542 -8442 -4657 -2869 -8385 -4224 -8596 -4909 -6510 -5686 -4897 -8245 -4562 -7143 -6619 -7314 -6596 -9164 -7510 -6364 -8035 -4457 -8864 -8058 -11786 -6543 -4658 -4902 -5834 -14679 -9951 -6423 -6468 -8250 -10715 -7326 -8596 -7878 -7270 -11760 -9927 -6740 -4876 -9103 -9428 -6674 -6250 -7952 -3861 -5019 -7162 -6661 -5780 -7310 -5565 -4783 -3905 -6372 -11032 -8849 -7719 -9040 -6542 -7737 -6079 -8896 -5058 -8588 -8754 -7858 -4694 -8723 -7394 -7684 -5764 -6383 -7918 -8127 -8704 -3753 -4937 -5765 -5586 -3152 -7117 -6412 -6699 -8350 -8548 -4952 -11873 -4948 -6893 -3802 -10913 -4486 -5417 -10726 -8693 -5271 -5037 -5938 -5916 -4187 -4808 -5218 -4667 -5124 -7541 -8317 -11319 -6758 -5560 -5424 -6839 -6555 -8140 -7299 -7014 -6917 -8014 -7887 -5151 -7336 -11332 -5401 -11210 -5448 -5969 -6820 -7764 -8282 -5632 -10051 -3934 -12952 -7245 -3007 -6747 -8187 -7049 -8271 -11201 -6721 -5371 -6223 -7527 -5837 -4859 -10526 -9005 -4539 -7939 -4529 -5598 -8589 -8775 -8264 -5217 -9714 -6589 -8985 -7664 -7082 -5787 -7217 -9275 -8264 -11723 -4670 -6245 -6470 -9697 -5338 -9553 -8540 -5284 -8865 -7806 -9349 -5364 -9539 -8734 -4995 -5263 -5491 -6781 -4962 -5638 -6488 -4881 -6969 -7234 -8730 -6071 -4470 -4594 -3843 -6724 -7757 -5410 -3331 -7029 -7416 -8410 -6318 -14611 -9889 -5642 -8825 -6963 -7595 -6109 -8437 -4314 -6593 -4923 -10267 -11262 -7123 -5004 -7165 -6320 -7440 -8776 -6050 -9330 -7607 -9200 -10575 -5852 -5140 -6678 -8491 -7136 -6777 -9880 -11922 -7582 -5047 -9188 -4034 -5161 -9145 -6720 -8463 -7913 -3945 -5326 -6152 -4609 -5935 -7661 -6175 -9594 -5513 -7338 -6431 -4741 -7699 -6865 -9397 -7521 -11589 -7373 -5659 -8011 -6293 -5356 -5461 -10996 -10120 -6979 -8710 -9290 -5894 -6917 -9796 -6870 -11320 -7801 -8854 -9701 -4283 -2767 -7104 -9313 -10466 -4739 -7895 -4228 -7654 -7011 -5324 -7664 -6959 -6164 -6852 -4758 -3482 -4494 -8270 -5455 -5676 -8816 -5970 -7844 -8650 -7911 -8428 -4825 -9254 -10236 -8211 -5133 -6323 -6436 -8783 -10141 -8842 -6272 -5657 -6131 -2741 -5379 -4249 -4788 -9529 -7078 -11003 -6462 -8008 -4908 -7400 -6394 -5719 -5664 -4460 -8462 -6157 -8105 -6612 -5055 -6568 -6075 -6519 -5760 -7730 -9126 -5022 -4674 -8890 -7255 -6005 -8922 -4985 -7260 -9365 -5635 -6277 -10545 -5986 -9240 -8015 -9172 -4727 -5193 -8841 -4837 -4841 -11542 -4208 -4473 -7100 -5636 -6295 -7758 -5599 -5364 -8533 -5694 -6871 -4804 -6411 -4509 -7623 -6388 -7065 -10143 -10300 -7104 -9138 -7059 -4577 -7224 -5743 -5467 -8315 -7804 -7695 -3937 -10154 -8593 -8042 -11112 -6514 -9223 -7807 -9196 -7257 -6915 -10660 -4944 -8113 -7219 -2944 -5193 -6606 -11134 -8717 -4656 -9468 -7375 -6988 -7570 -7746 -10703 -7431 -6522 -5883 -9811 -3045 -6406 -5529 -10369 -5044 -9262 -5965 -8816 -4067 -4570 -5891 -6307 -8534 -6763 -7865 -6977 -7049 -9142 -6186 -5117 -7580 -12917 -7429 -11073 -5392 -8443 -3408 -5348 -6277 -8355 -4874 -6045 -3076 -3621 -9235 -10076 -6298 -6437 -6214 -6086 -6155 -7034 -7273 -5889 -8829 -5388 -8487 -6274 -8232 -6342 -7983 -3253 -6591 -4493 -7510 -5878 -7516 -8385 -4015 -11322 -8915 -6357 -10585 -8090 -8176 -11051 -8995 -10505 -8566 -5939 -7642 -6975 -7570 -5734 -11064 -8070 -10108 -10758 -8283 -10525 -7524 -5739 -5273 -4986 -7035 -6616 -6194 -5017 -6298 -6411 -8806 -8820 -5973 -8405 -8853 -4547 -7485 -14583 -8865 -5042 -11389 -6771 -7985 -5960 -3730 -8195 -6246 -4541 -5614 -7505 -3712 -10211 -8423 -8324 -8999 -10668 -5165 -6952 -8485 -7454 -6665 -9449 -7762 -6631 -6286 -7963 -6773 -5502 -6572 -4577 -7685 -7306 -6873 -8006 -8712 -8326 -5533 -6961 -7835 -8030 -7728 -4425 -5599 -6287 -7116 -16192 -5008 -3681 -4471 -7920 -10329 -7684 -9075 -5358 -8229 -7387 -5940 -5139 -7683 -6684 -5309 -6856 -6919 -8719 -6390 -6476 -5294 -7274 -6228 -7404 -5154 -7425 -5343 -6550 -7917 -4048 -5286 -7266 -7468 -4945 -8416 -4704 -8333 -7368 -9014 -4182 -4918 -8574 -8485 -3637 -6794 -5807 -4176 -6764 -10196 -10285 -6970 -7486 -6996 -10651 -10185 -9637 -5885 -4712 -8808 -9003 -8062 -7193 -5344 -5843 -6153 -4644 -4691 -4827 -9184 -7053 -8881 -7234 -5686 -4206 -8880 -8595 -5979 -5325 -7830 -7011 -9544 -7072 -10954 -4650 -7244 -6260 -12137 -3271 -8282 -5798 -8935 -7684 -7602 -7390 -4910 -4936 -5258 -10839 -7641 -5782 -5930 -7181 -5633 -6955 -4485 -5954 -6919 -8124 -7760 -7186 -7502 -8514 -8165 -8224 -8095 -6752 -10540 -7580 -5506 -8233 -7290 -7372 -7550 -7224 -8851 -8216 -7598 -11143 -7168 -5943 -2335 -6814 -6896 -3268 -8378 -7185 -7781 -6448 -10179 -8597 -5629 -4247 -7259 -6038 -6373 -8035 -10682 -5525 -6115 -4151 -6523 -5013 -9442 -7846 -4991 -6497 -7105 -9304 -6667 -8712 -6290 -4014 -10144 -10669 -4471 -6227 -8223 -5597 -5432 -9295 -4740 -5158 -6619 -8177 -9277 -7220 -6133 -4567 -5459 -4336 -6758 -4615 -6259 -12163 -6569 -9763 -7214 -8334 -5259 -6470 -10948 -5778 -6100 -6415 -8345 -6784 -5847 -9418 -6311 -8279 -6142 -15101 -3511 -8370 -4214 -7322 -6067 -9544 -6410 -7496 -6743 -7598 -7339 -9367 -2416 -4312 -10778 -8669 -6588 -4441 -13759 -7334 -10181 -8387 -10290 -6534 -4881 -2410 -7248 -1774 -4753 -6986 -5853 -5669 -6916 -8171 -4762 -7598 -9809 -6406 -8165 -5325 -8197 -6258 -8231 -7933 -5481 -5947 -4104 -10155 -8847 -6484 -7039 -7798 -5363 -8695 -6196 -6633 -8307 -8377 -8588 -7645 -8786 -5802 -8233 -5102 -7743 -4633 -8568 -5818 -5105 -4586 -7446 -6398 -4166 -4249 -7403 -3693 -6338 -4150 -9833 -5485 -8704 -4386 -8301 -5907 -6761 -9264 -8843 -6241 -4767 -9723 -4288 -4988 -4979 -6646 -11149 -4559 -6563 -9013 -6358 -6650 -8089 -10720 -4495 -9577 -4988 -9550 -6201 -7340 -8742 -8770 -8266 -6581 -7611 -4956 -5090 -4252 -9608 -7415 -8663 -7617 -8563 -2958 -6896 -9858 -5704 -4842 -8258 -7736 -6743 -5973 -6657 -13488 -6103 -3510 -10906 -8487 -5900 -7654 -7651 -7206 -6659 -7957 -6913 -6743 -5344 -7622 -7536 -5354 -4279 -6038 diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/best.pt deleted file mode 100644 index 5ba7832b26b79de0235e2af8b365ec0688e2e483..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14423 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 E0io5+=Kufz diff --git a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/config.yml b/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/config.yml deleted file mode 100644 index 8b6c41afb..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_evenly_spread/k8/trained_ddqn/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 1000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "OneLL" - env_class: "RLSEnvDiscreteK" - action_choices: [1, 7, 13, 19, 25, 31, 37, 43] - problem: "LeadingOne" - instance_set_path: "lo_rls_50" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/dqn.txt deleted file mode 100644 index 9f6059db5..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -803 -1200 -1101 -1409 -1000 -700 -768 -1473 -907 -1014 -1284 -1034 -593 -1125 -1098 -905 -1052 -1009 -1076 -1282 -1248 -814 -1403 -724 -786 -1039 -730 -1206 -1010 -694 -667 -1492 -999 -1058 -946 -1304 -1244 -931 -750 -747 -1147 -779 -1585 -716 -854 -924 -656 -1138 -912 -1268 -904 -1305 -1056 -841 -874 -917 -978 -829 -890 -1116 -1275 -833 -825 -758 -1466 -1210 -1671 -808 -778 -848 -1368 -869 -1108 -938 -1097 -836 -860 -1049 -1319 -1140 -1123 -806 -858 -857 -1297 -685 -678 -645 -938 -941 -1177 -936 -793 -947 -1039 -785 -1278 -1346 -747 -872 -805 -850 -1330 -651 -1420 -997 -671 -1211 -1042 -884 -1097 -1054 -1087 -986 -790 -1280 -998 -983 -1066 -771 -1323 -1376 -1065 -1399 -390 -737 -1103 -995 -1189 -670 -1000 -1054 -931 -1119 -1227 -953 -1056 -1475 -884 -1318 -945 -1069 -1257 -1251 -549 -871 -1082 -925 -1590 -1194 -931 -1162 -665 -790 -1130 -884 -989 -875 -1141 -1427 -636 -611 -877 -1795 -850 -970 -895 -1074 -833 -963 -1458 -1198 -1083 -1151 -1095 -1164 -899 -799 -1234 -854 -1295 -1621 -801 -651 -859 -844 -679 -985 -1039 -1412 -763 -1127 -995 -609 -1160 -722 -819 -750 -1277 -810 -763 -1369 -1012 -944 -685 -877 -1287 -1281 -899 -877 -1564 -399 -845 -1103 -1052 -943 -898 -661 -1102 -1030 -880 -693 -803 -991 -1145 -839 -1007 -919 -1095 -1015 -866 -991 -1055 -878 -927 -1539 -1295 -1026 -476 -763 -793 -1298 -1039 -1060 -605 -925 -1061 -1076 -1078 -1206 -1053 -1377 -1493 -744 -1001 -864 -625 -764 -903 -548 -897 -1131 -948 -609 -1020 -914 -969 -1149 -1356 -897 -587 -1261 -1062 -808 -1187 -1012 -971 -1039 -909 -966 -1198 -768 -1354 -865 -1129 -1104 -886 -815 -1148 -1038 -859 -1028 -1164 -724 -898 -959 -1440 -1133 -946 -1009 -1132 -523 -946 -1135 -728 -1152 -1140 -1062 -1067 -1452 -924 -1616 -865 -1101 -849 -867 -885 -654 -612 -987 -835 -1029 -942 -795 -857 -1103 -868 -785 -865 -1327 -1123 -1105 -735 -682 -1315 -532 -965 -827 -877 -1214 -1561 -1311 -1096 -838 -1469 -894 -667 -1011 -1537 -801 -760 -919 -1226 -1079 -1240 -923 -994 -671 -561 -674 -507 -768 -779 -1483 -594 -367 -790 -791 -1101 -1173 -1019 -817 -853 -1550 -1522 -1117 -962 -856 -558 -583 -837 -728 -613 -831 -1026 -1360 -921 -1022 -1434 -932 -942 -822 -1110 -1336 -758 -1058 -790 -1006 -1384 -1126 -1065 -544 -1249 -816 -575 -974 -1206 -948 -839 -915 -1000 -1243 -807 -884 -888 -800 -678 -1296 -1518 -1025 -1350 -652 -803 -947 -1669 -682 -724 -1427 -559 -1221 -1268 -1242 -874 -1051 -988 -1537 -1195 -1417 -788 -1403 -1004 -968 -948 -881 -915 -775 -1487 -862 -917 -1699 -1058 -1347 -874 -696 -902 -969 -645 -795 -803 -1288 -1036 -982 -655 -812 -1009 -691 -1123 -807 -1410 -1208 -885 -952 -1135 -1447 -743 -1194 -1033 -683 -907 -1218 -1570 -1162 -696 -1182 -920 -526 -1081 -880 -1342 -1179 -1224 -1159 -1208 -785 -920 -627 -730 -1245 -1451 -1585 -927 -414 -1154 -932 -1084 -854 -1166 -1036 -1217 -904 -757 -1586 -808 -800 -1484 -893 -1387 -1213 -855 -849 -985 -1229 -1422 -725 -1157 -1251 -817 -1200 -1097 -1012 -1203 -1168 -1017 -856 -686 -1439 -977 -697 -567 -928 -939 -652 -808 -1004 -822 -934 -1238 -815 -966 -732 -757 -966 -737 -1234 -1004 -1220 -579 -770 -1064 -940 -900 -794 -840 -1156 -1076 -1011 -1076 -1030 -553 -1645 -1156 -843 -605 -1171 -958 -993 -657 -1041 -1045 -669 -1489 -672 -1222 -1374 -625 -794 -993 -1271 -658 -1294 -891 -1064 -1131 -1103 -973 -1037 -1381 -1140 -1096 -1308 -867 -953 -541 -859 -725 -1114 -1305 -2014 -689 -1186 -1271 -1536 -1418 -627 -912 -512 -1448 -1129 -932 -1400 -674 -652 -878 -740 -711 -986 -853 -644 -1343 -628 -1650 -907 -895 -553 -1037 -935 -1248 -1679 -905 -974 -1204 -631 -1101 -1284 -704 -1377 -940 -1053 -825 -927 -1191 -746 -826 -1000 -1275 -502 -879 -1025 -1051 -1102 -1288 -748 -1280 -926 -1521 -862 -846 -1283 -907 -1049 -783 -880 -799 -906 -1123 -716 -825 -932 -1059 -731 -1583 -1092 -1315 -1276 -895 -781 -1122 -988 -1428 -1173 -1153 -1478 -783 -642 -813 -960 -1632 -670 -1019 -1453 -1044 -832 -960 -756 -1790 -1382 -1301 -1423 -905 -694 -749 -835 -1170 -1464 -729 -964 -1148 -1406 -1182 -766 -1514 -855 -677 -889 -1337 -797 -1205 -844 -624 -934 -822 -1157 -875 -917 -976 -875 -1644 -1073 -1263 -1542 -1019 -916 -1097 -895 -972 -808 -690 -979 -887 -1020 -921 -802 -1276 -857 -971 -1252 -1093 -380 -747 -591 -916 -1396 -807 -653 -934 -1361 -644 -1068 -1058 -673 -989 -646 -1333 -706 -681 -1368 -1085 -1103 -1099 -662 -906 -800 -586 -972 -1274 -844 -955 -1007 -547 -1182 -1048 -972 -999 -847 -1105 -1098 -1096 -1206 -1358 -663 -769 -749 -845 -1016 -787 -803 -905 -874 -716 -1290 -557 -963 -1363 -1073 -885 -1314 -704 -877 -947 -1172 -709 -796 -1489 -898 -856 -812 -832 -1619 -910 -776 -899 -1296 -1065 -880 -1239 -744 -948 -1062 -1000 -1293 -942 -845 -727 -666 -815 -757 -762 -579 -1202 -697 -1379 -1015 -1109 -1176 -771 -900 -1154 -1223 -845 -729 -822 -1100 -1191 -507 -1088 -779 -1175 -776 -1055 -1021 -942 -944 -975 -764 -1003 -1143 -795 -1289 -595 -1021 -1238 -1166 -1745 -821 -905 -1088 -1014 -624 -679 -965 -532 -917 -1339 -1351 -781 -732 -1137 -1307 -1109 -1211 -1405 -1321 -1309 -1049 -1075 -1050 -494 -1276 -926 -1131 -952 -1353 -794 -592 -861 -787 -704 -607 -627 -1194 -860 -1332 -817 -1545 -1687 -1115 -1132 -1716 -996 -1021 -827 -1184 -777 -1167 -777 -939 -836 -965 -1196 -1160 -580 -1468 -754 -1133 -472 -1236 -1408 -1646 -1141 -829 -365 -890 -830 -899 -1048 -1185 -908 -1488 -1392 -822 -1873 -1040 -991 -1085 -1295 -886 -851 -1108 -1219 -1140 -1253 -1714 -752 -1323 -1081 -1013 -1288 -1344 -1136 -951 -868 -1215 -1204 -836 -1255 -1073 -1087 -960 -986 -945 -822 -1208 -845 -1111 -1100 -1487 -1107 -922 -1044 -1044 -1003 -1029 -1006 -1712 -1002 -1077 -1048 -1547 -1323 -973 -922 -629 -1018 -1007 -901 -958 -1848 -1278 -1045 -1549 -800 -1166 -1425 -460 -1321 -578 -1216 -1125 -953 -1500 -947 -1143 -974 -1111 -1170 -709 -940 -911 -1332 -557 -1106 -469 -1422 -1201 -723 -844 -1421 -1207 -1316 -789 -996 -1450 -828 -1038 -1177 -1565 -1016 -1004 -654 -710 -1040 -1261 -1013 -875 -1089 -758 -768 -1125 -845 -1421 -1092 -1227 -1001 -820 -901 -660 -1275 -945 -978 -1032 -985 -587 -1396 -1272 -1260 -1053 -1889 -1103 -836 -891 -890 -904 -937 -837 -944 -1344 -1099 -1272 -907 -1100 -714 -925 -749 -1029 -1064 -809 -940 -575 -1080 -930 -822 -921 -1093 -1011 -1018 -944 -578 -685 -735 -1092 -1159 -1226 -662 -1099 -1112 -1499 -655 -845 -651 -1189 -866 -992 -1209 -751 -470 -810 -1172 -1209 -1063 -1002 -979 -726 -1198 -591 -1048 -1230 -1040 -1078 -847 -1020 -1242 -1054 -775 -1072 -921 -701 -1059 -1096 -974 -1036 -868 -943 -831 -1155 -1345 -697 -1110 -803 -387 -1135 -1354 -734 -980 -1053 -562 -548 -795 -1102 -1510 -1253 -1042 -1096 -1141 -1295 -402 -1146 -914 -747 -846 -1218 -950 -1047 -745 -615 -851 -1161 -531 -1372 -930 -1368 -853 -718 -804 -1009 -1143 -1173 -997 -1049 -887 -1052 -932 -954 -841 -871 -1135 -977 -826 -1057 -1026 -852 -1026 -832 -733 -1705 -1571 -1120 -1150 -1238 -852 -1028 -851 -1214 -864 -729 -878 -1132 -565 -2036 -1274 -1142 -859 -522 -1599 -1248 -1069 -887 -789 -876 -1066 -607 -1125 -968 -861 -1639 -839 -739 -711 -710 -975 -1000 -569 -1176 -809 -1579 -1070 -1710 -651 -1126 -944 -974 -1320 -1221 -1118 -1214 -1282 -826 -713 -865 -959 -1457 -1051 -973 -1031 -1006 -923 -861 -1654 -662 -699 -1120 -1155 -1160 -1038 -759 -1143 -771 -1190 -917 -1129 -1308 -1455 -1186 -888 -1836 -925 -1231 -870 -842 -816 -960 -1373 -1100 -1094 -875 -1214 -892 -1137 -991 -981 -915 -1488 -973 -631 -985 -1271 -815 -675 -828 -1082 -1155 -1047 -547 -1309 -1037 -1384 -823 -1192 -754 -1219 -605 -1163 -1192 -977 -970 -656 -397 -1012 -737 -618 -1080 -1219 -1373 -1042 -793 -897 -836 -1073 -999 -999 -812 -1024 -1591 -787 -876 -1640 -432 -1176 -1442 -1178 -624 -1647 -804 -1034 -1615 -924 -1495 -1255 -391 -982 -846 -661 -1325 -768 -910 -1326 -1244 -1304 -434 -1092 -1533 -1483 -856 -1663 -998 -814 -803 -869 -1052 -1038 -1342 -1311 -1025 -869 -1331 -633 -1046 -755 -1073 -991 -743 -686 -1471 -906 -1654 -651 -969 -971 -609 -1577 -679 -786 -1058 -867 -941 -644 -863 -1162 -1059 -1000 -1077 -1016 -1283 -1424 -729 -931 -1099 -1310 -818 -995 -903 -1715 -1481 -963 -1044 -927 -914 -1226 -1186 -693 -771 -1087 -763 -1323 -1112 -1071 -1093 -864 -1017 -1214 -865 -643 -857 -1130 -1384 -609 -807 -1236 -1051 -884 -1011 -1056 -882 -944 -1345 -946 -1075 -1389 -793 -1103 -938 -717 -1116 -1340 -1033 -1012 -1049 -1571 -1028 -625 -1027 -1310 -1400 -1218 -829 -540 -674 -1072 -937 -682 -1109 -865 -1038 -1166 -823 -1496 -1192 -776 -716 -1242 -1038 -1011 -703 -1320 -1087 -724 -1329 -729 -817 -796 -1263 -824 -1393 -778 -1338 -1273 -1398 -814 -1082 -861 -1370 -816 -1283 -1618 -1505 -695 -945 -813 -1147 -1002 -1304 -761 -806 -936 -1416 -1399 -742 -1362 -1052 -797 -969 -917 -1120 -1037 -855 -1161 -1103 -736 -1121 -1571 -860 -619 -823 -1310 -1097 -928 -1210 -926 -1380 -1247 -1085 -1381 -1159 -1379 -927 -808 -1402 -1564 -929 -826 -1224 -882 -1188 -965 -1348 -1481 -1127 -1291 -1462 -942 -1691 -1323 -1384 -416 -853 -1065 -860 -1096 -930 -1147 -1106 -1598 -915 -619 -1017 -872 -1202 -986 -1143 -833 -750 -1170 -1194 -918 -1200 -1103 -690 -1334 -1284 -563 -1132 -872 -808 -1507 -1054 -1028 -995 -801 -805 -719 -1062 -1410 -744 -919 -910 -1159 -1071 -974 -1038 -1459 -854 -1089 -1158 -694 -814 -1077 -947 -1231 -749 -1001 -1231 -881 -1331 -1214 -982 -852 -667 -1134 -915 -955 -965 -565 -1136 -1478 -916 -644 -1516 -560 -1299 -1196 -1213 -1004 -889 -684 -1104 -1337 -1347 -812 -936 -848 -1360 -1229 -1349 -929 -732 -962 -1128 -1104 -1032 -983 -846 -1180 -1788 -878 -1145 -337 -976 -519 -878 -840 -1135 -1039 -1022 -800 -1052 -1178 -1272 -924 -1200 -1683 -1261 -1397 -1529 -1176 -1512 -1464 -1332 -939 -938 -700 -864 -1099 -846 -1389 -1053 -1184 -822 -773 -1090 -1284 -895 -1086 -572 -943 -1183 -1100 -850 -1077 -1179 -827 -1161 -947 -1113 -1080 -772 -1139 -585 -992 -795 -1055 -973 -1064 -748 -985 -1060 -1063 -1034 -869 -1598 -817 -969 -1123 -1038 -1036 -958 -1326 -636 -711 -717 -1199 -866 -1308 -1377 -855 -1009 -910 -777 -1537 -1494 -1332 -788 -877 -1542 -1259 -955 -909 -834 -1023 -745 -477 -934 -811 -1411 -951 -1331 -1119 -834 -1045 -1158 -1245 -814 -922 -1383 -800 -1082 -1098 -592 -768 -528 -901 -979 -765 -739 -879 -682 -1186 -1671 -472 -870 -787 -1320 -981 -1207 -1522 -1119 -1345 -912 -967 -1357 -877 -1165 -995 -1018 -968 -1034 -1401 -1567 -1270 -1374 -889 -1045 -1395 -1345 -1014 -1255 -518 -898 -1271 -1087 -716 -825 -1508 -837 -1420 -864 -1054 -1152 -748 -782 -1011 -1204 -823 -1014 -1258 -1223 -1478 -1181 -642 -719 -418 -1041 -962 -1293 -785 -942 -848 -1079 -990 -1256 -1023 -967 -1608 -786 -928 -1111 -1268 -1065 -1081 -868 -1081 -716 -1006 -978 -935 -1186 -556 -477 -1301 -779 -862 -785 -1068 -1534 -1287 -844 -928 -1131 -1055 -1217 -841 -1166 -1129 -1257 -984 -1011 -1164 -1065 -1168 -832 -966 -900 -1184 -892 -1449 -950 -1250 -705 -1651 -1108 -782 -683 -532 -1617 -1043 -1036 -1497 -802 -594 -1377 -649 -1560 -1128 -905 -1393 -870 -808 -978 -1046 -1166 -614 -1681 -996 -781 -1114 -1168 -603 -943 -1006 -999 -1188 -901 -952 -953 -779 -1257 -1047 -1100 -1431 -981 -1519 -1191 -657 -896 -1286 -1617 -826 -1038 -961 -750 -1146 -536 -1292 -724 -1147 -908 -911 -839 -918 -1308 -1309 -952 -699 -1235 -1405 -716 -772 -744 -935 -877 -1422 -1324 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/optimal.txt deleted file mode 100644 index 797eeb63e..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -963 -730 -1025 -679 -775 -988 -1199 -1047 -898 -1208 -908 -786 -986 -937 -523 -1482 -921 -830 -1295 -1327 -981 -1157 -1222 -623 -801 -971 -1065 -942 -609 -999 -854 -1149 -1443 -1170 -1221 -774 -755 -1334 -1200 -778 -1121 -914 -1084 -997 -1047 -1321 -1241 -1393 -1073 -925 -948 -933 -1202 -1209 -1045 -1039 -883 -852 -669 -848 -1441 -1023 -899 -996 -831 -1237 -1029 -1071 -658 -1283 -1421 -1114 -811 -915 -984 -1112 -1159 -1187 -1399 -974 -1228 -743 -726 -1070 -1231 -811 -1340 -1022 -1027 -941 -704 -1126 -985 -960 -1274 -641 -1074 -1596 -579 -972 -1292 -1090 -1316 -1390 -1009 -1120 -1019 -1048 -1607 -1033 -876 -790 -813 -1305 -901 -1201 -1033 -1383 -740 -726 -1232 -1053 -746 -1104 -1104 -1238 -569 -1102 -1174 -750 -726 -1427 -790 -908 -1080 -1275 -684 -1229 -1031 -788 -743 -1317 -1384 -708 -676 -1207 -1431 -724 -933 -1015 -963 -1197 -1158 -1288 -1025 -1409 -572 -1127 -913 -822 -794 -1126 -712 -730 -1085 -1531 -1654 -755 -819 -1534 -892 -758 -675 -1289 -954 -1360 -1409 -833 -839 -953 -665 -1341 -763 -828 -924 -400 -876 -1152 -1099 -1043 -810 -1248 -1124 -1052 -955 -884 -805 -1761 -785 -546 -609 -961 -1271 -889 -1116 -489 -1261 -1358 -1337 -954 -1077 -1136 -1292 -907 -695 -1253 -1188 -921 -872 -1031 -1099 -1044 -1194 -848 -794 -958 -955 -1199 -1287 -798 -878 -1442 -1092 -1726 -589 -1133 -1003 -730 -1216 -1080 -882 -1064 -1231 -1346 -521 -1311 -1121 -1265 -1322 -1109 -1053 -1033 -801 -1202 -691 -750 -784 -667 -855 -668 -1034 -972 -908 -717 -689 -939 -1069 -1215 -1294 -1019 -989 -886 -962 -735 -776 -1161 -565 -601 -1191 -967 -789 -664 -1087 -974 -988 -1001 -1049 -661 -1221 -1172 -1503 -774 -935 -1070 -1231 -1279 -865 -995 -995 -726 -911 -1098 -973 -1241 -679 -1088 -807 -1017 -1030 -908 -1677 -1291 -1155 -603 -987 -1003 -1365 -1198 -776 -1238 -570 -1309 -1157 -970 -689 -1556 -536 -784 -1082 -1738 -1035 -1159 -752 -1045 -867 -1013 -1106 -722 -691 -852 -715 -935 -1244 -1336 -789 -970 -749 -779 -1444 -941 -1354 -1355 -1253 -939 -935 -1189 -853 -1363 -1023 -636 -881 -1035 -1442 -1437 -679 -807 -1321 -1017 -1196 -1145 -1049 -696 -899 -856 -1006 -788 -1143 -1059 -893 -957 -1007 -591 -996 -540 -802 -616 -1098 -892 -579 -894 -704 -1450 -1125 -364 -1041 -1096 -512 -1108 -992 -834 -808 -918 -847 -1101 -1030 -877 -1138 -1213 -767 -785 -1089 -932 -1415 -1364 -1395 -1057 -891 -640 -953 -1033 -830 -1089 -746 -670 -1221 -935 -1208 -1126 -1363 -1123 -787 -716 -831 -1144 -731 -1078 -864 -1087 -573 -905 -935 -1044 -974 -979 -1030 -1000 -952 -1053 -685 -1242 -1022 -1055 -1066 -1031 -1125 -1452 -1180 -1278 -854 -1143 -709 -866 -703 -1125 -300 -646 -1324 -1227 -1336 -884 -733 -838 -945 -927 -1329 -1297 -1205 -1108 -850 -921 -981 -1347 -718 -1369 -1003 -1046 -1265 -943 -1085 -1018 -632 -1072 -955 -748 -1042 -924 -828 -1261 -1198 -1076 -1082 -1008 -737 -824 -1102 -708 -832 -1056 -837 -831 -1005 -1123 -635 -1140 -989 -1465 -1096 -994 -876 -1639 -1027 -601 -873 -901 -1613 -1166 -1093 -728 -936 -1192 -511 -1102 -1020 -1186 -1599 -1280 -1133 -1089 -1015 -1101 -908 -1192 -807 -1867 -920 -1190 -1456 -918 -1037 -885 -1124 -1018 -806 -916 -1169 -1167 -808 -1391 -1230 -1155 -974 -583 -917 -1493 -1233 -805 -1225 -441 -1105 -757 -1274 -1035 -941 -905 -1028 -795 -958 -598 -1385 -1177 -601 -545 -792 -1041 -1135 -1074 -1505 -965 -932 -1352 -1374 -854 -1002 -1264 -828 -428 -896 -1387 -1342 -1359 -723 -1247 -1356 -1034 -770 -606 -1162 -1081 -1044 -1311 -1214 -1089 -1016 -876 -1114 -1081 -625 -1156 -1057 -1083 -784 -833 -1380 -910 -1222 -1263 -1101 -818 -905 -844 -969 -763 -1151 -1453 -691 -766 -768 -963 -1219 -594 -919 -724 -1070 -917 -935 -1402 -602 -781 -777 -835 -757 -1556 -956 -1109 -742 -1451 -885 -888 -384 -1065 -1285 -1471 -935 -782 -630 -1176 -1076 -1348 -1363 -1113 -1299 -863 -1060 -1064 -830 -1078 -882 -714 -930 -435 -1045 -1467 -689 -1029 -1190 -1069 -930 -651 -810 -1129 -781 -1109 -1041 -942 -1111 -687 -767 -1149 -1848 -767 -847 -654 -994 -867 -1280 -658 -1154 -715 -880 -655 -1197 -906 -651 -862 -1024 -1049 -808 -991 -1326 -1272 -711 -1653 -1332 -768 -1846 -909 -879 -1029 -641 -1425 -789 -1113 -978 -964 -1083 -1156 -919 -1528 -1078 -1069 -708 -1666 -1221 -995 -855 -746 -611 -1056 -953 -1050 -769 -954 -1306 -861 -1097 -978 -1251 -1074 -1136 -832 -1093 -1183 -1252 -847 -973 -1011 -1336 -1424 -473 -464 -586 -1291 -776 -1430 -1062 -769 -1035 -936 -995 -1121 -999 -803 -1422 -1315 -1478 -1149 -1359 -948 -1604 -833 -1019 -885 -1076 -1137 -660 -945 -960 -687 -1115 -715 -847 -1143 -1056 -981 -974 -647 -1211 -1068 -754 -1348 -856 -921 -1107 -1178 -720 -725 -1100 -1016 -1053 -1099 -952 -717 -509 -1027 -911 -1314 -940 -637 -1216 -698 -1075 -1007 -1122 -934 -790 -732 -1208 -544 -693 -1198 -655 -1231 -984 -1396 -1043 -604 -1096 -745 -531 -1164 -1140 -835 -1032 -1501 -1534 -1365 -1147 -1003 -1400 -1148 -878 -635 -903 -1784 -896 -765 -901 -2094 -991 -1215 -1059 -805 -1070 -791 -980 -1058 -1040 -1069 -664 -638 -930 -967 -919 -852 -638 -1151 -1210 -1228 -1421 -1199 -931 -930 -904 -1033 -557 -488 -1243 -770 -541 -1080 -913 -1113 -754 -910 -1157 -902 -1113 -811 -1301 -915 -1203 -879 -1532 -1207 -865 -940 -1049 -1066 -689 -779 -1141 -986 -882 -1089 -1125 -1342 -848 -1019 -564 -917 -662 -626 -850 -548 -1062 -1042 -1267 -1301 -1102 -708 -915 -710 -1316 -597 -986 -1095 -852 -579 -1016 -830 -1291 -738 -818 -1073 -772 -910 -836 -693 -705 -933 -1127 -1076 -1265 -911 -1007 -809 -1349 -1153 -1149 -1096 -1232 -990 -1053 -693 -966 -1124 -644 -747 -1439 -1298 -887 -1235 -1191 -879 -827 -969 -1069 -1054 -860 -841 -1328 -962 -1040 -1149 -517 -605 -768 -736 -1104 -1032 -868 -1046 -714 -1114 -602 -998 -1304 -1144 -1294 -1124 -1206 -937 -896 -1358 -1194 -762 -1194 -1162 -1002 -786 -1068 -804 -811 -486 -1521 -841 -1149 -1593 -1431 -693 -1308 -780 -820 -939 -1259 -818 -1152 -1137 -462 -1159 -1069 -999 -628 -1205 -894 -800 -1187 -1408 -982 -1085 -1116 -1265 -1214 -1011 -421 -1129 -793 -1317 -712 -1510 -1234 -811 -856 -803 -1058 -1286 -1232 -1276 -1440 -909 -1336 -890 -926 -764 -1130 -1581 -1002 -658 -1074 -750 -820 -1526 -827 -1083 -1537 -990 -1110 -1237 -1161 -955 -1157 -1163 -923 -949 -804 -703 -1721 -774 -533 -975 -830 -991 -1098 -1367 -1340 -716 -1174 -569 -871 -1273 -618 -918 -1216 -968 -1281 -923 -916 -1619 -1148 -915 -827 -739 -1442 -907 -1309 -882 -911 -765 -1239 -728 -1141 -1608 -953 -1090 -1007 -1239 -872 -795 -771 -807 -1291 -801 -1131 -1036 -1273 -703 -683 -368 -1192 -498 -1176 -908 -1027 -864 -1375 -1054 -1036 -1000 -1295 -1455 -745 -1091 -990 -1761 -1210 -1178 -866 -1148 -796 -666 -635 -1372 -1153 -1068 -885 -826 -772 -849 -818 -1235 -589 -1246 -1118 -902 -954 -589 -810 -719 -1220 -1105 -827 -1046 -610 -605 -846 -898 -1150 -527 -954 -985 -1397 -977 -861 -1557 -2279 -915 -1122 -925 -1087 -980 -918 -1299 -782 -1094 -1358 -851 -1303 -930 -945 -1168 -1176 -786 -1292 -995 -737 -938 -693 -1354 -1776 -910 -1114 -1091 -675 -906 -987 -831 -1192 -1154 -1302 -1016 -1174 -694 -491 -756 -666 -510 -939 -1374 -602 -909 -977 -731 -883 -1018 -1401 -1911 -1004 -1073 -955 -652 -608 -724 -1416 -905 -939 -721 -1329 -806 -1244 -1616 -967 -986 -1179 -806 -1139 -1263 -900 -662 -1014 -860 -894 -1021 -858 -624 -1364 -1275 -1166 -986 -934 -675 -1162 -1066 -1013 -1045 -954 -1345 -1034 -1045 -1042 -1139 -755 -962 -1679 -889 -1425 -658 -892 -643 -678 -1116 -918 -1119 -635 -1177 -822 -880 -988 -1160 -1185 -876 -787 -1044 -1151 -969 -625 -1110 -1202 -622 -1189 -959 -1124 -1142 -1250 -1378 -737 -787 -795 -1109 -1054 -1482 -1413 -1266 -1313 -683 -587 -605 -1165 -832 -674 -1099 -704 -1560 -1110 -1029 -895 -1095 -966 -1111 -1003 -505 -1033 -824 -697 -1095 -1143 -841 -805 -917 -1666 -1509 -914 -1371 -827 -807 -609 -809 -675 -723 -1048 -748 -1440 -1291 -1052 -591 -1302 -1192 -980 -732 -1355 -787 -1068 -879 -621 -1394 -1123 -672 -1269 -931 -854 -1044 -601 -976 -1104 -1235 -1235 -1224 -668 -998 -961 -1153 -1029 -963 -1061 -1029 -752 -1125 -1626 -911 -1343 -1210 -1140 -627 -1031 -756 -596 -1180 -1310 -873 -851 -1322 -1877 -860 -1299 -1012 -1230 -984 -1301 -1091 -787 -1038 -1010 -869 -972 -989 -1067 -715 -1595 -884 -991 -1306 -1307 -1099 -1415 -1410 -1000 -1159 -1349 -1075 -609 -944 -747 -931 -1322 -1031 -738 -875 -1028 -974 -673 -960 -1185 -989 -825 -917 -1137 -790 -1215 -563 -723 -776 -693 -941 -1028 -1027 -995 -956 -931 -769 -731 -870 -1312 -1152 -929 -1210 -1625 -920 -1185 -483 -958 -1233 -1511 -1071 -1061 -989 -1192 -1193 -831 -877 -1246 -1162 -1238 -821 -742 -1282 -1102 -1068 -1367 -871 -1202 -1362 -983 -1004 -710 -1331 -1025 -1046 -922 -787 -855 -943 -1217 -787 -930 -888 -628 -1612 -1490 -1400 -1370 -1244 -863 -1069 -979 -957 -953 -1087 -1048 -1141 -742 -946 -939 -820 -316 -1278 -1193 -1177 -975 -916 -868 -1245 -1015 -931 -632 -1069 -859 -866 -913 -834 -1206 -1264 -611 -1146 -983 -656 -1074 -1127 -1201 -863 -740 -1461 -1039 -1049 -1418 -1073 -790 -914 -1294 -969 -919 -815 -862 -1037 -991 -1643 -1100 -1175 -877 -1138 -1069 -841 -1185 -1114 -600 -863 -947 -1344 -456 -1220 -837 -1296 -1317 -1035 -1151 -812 -1310 -1134 -1052 -872 -816 -888 -559 -929 -1402 -1224 -822 -818 -1200 -1162 -1193 -1069 -424 -1400 -674 -1279 -1294 -538 -742 -843 -897 -934 -804 -711 -771 -1031 -1308 -1429 -660 -1274 -1368 -1167 -1328 -1014 -861 -1066 -903 -1169 -687 -978 -1026 -726 -921 -928 -1167 -643 -965 -758 -1438 -732 -474 -961 -380 -825 -961 -928 -816 -1527 -1212 -1479 -1190 -1131 -1173 -1239 -826 -711 -1494 -1031 -791 -1245 -1530 -935 -1064 -883 -1147 -829 -1122 -936 -962 -1324 -971 -970 -1112 -945 -1145 -731 -776 -953 -979 -1355 -955 -990 -1022 -1235 -1057 -1234 -1215 -1053 -943 -1127 -1140 -1122 -924 -802 -363 -1087 -672 -818 -1068 -912 -999 -1505 -812 -1074 -1035 -1014 -665 -821 -1202 -711 -897 -1339 -1035 -1019 -739 -1057 -970 -596 -572 -1009 -1083 -1612 -647 -451 -1274 -975 -727 -689 -771 -1612 -662 -1205 -782 -1079 -1182 -801 -907 -1135 -1423 -1136 -947 -1128 -1097 -1116 -1438 -970 -1142 -873 -1505 -658 -957 -814 -779 -1093 -1080 -1080 -829 -670 -1089 -1019 -1098 -1261 -1487 -1015 -1021 -1104 -1771 -1311 -1059 -927 -1257 -692 -1018 -967 -1106 -734 -1201 -1093 -1215 -883 -1283 -1131 -700 -803 -1255 -1090 -834 -850 -845 -712 -1027 -927 -919 -877 -874 -605 -1130 -988 -874 -604 -1017 -1046 -1215 -1051 -1044 -1479 -1172 -1084 -856 -1200 -1208 -984 -1067 -988 -1117 -800 -990 -1149 -744 -793 -1330 -548 -1147 -1423 -927 -1054 -908 -909 -1231 -896 -1451 -1112 -784 -1047 -825 -702 -974 -1004 -1058 -1636 -940 -770 -560 -748 -1068 -848 -848 -912 -1453 -1321 -793 -850 -1214 -628 -893 -1610 -1107 -1265 -593 -1086 -1011 -984 -1023 -1354 -919 -1058 -1509 -1370 -571 -1266 -1153 -828 -692 -650 -893 -1032 -804 -1533 -814 -1195 -1300 -708 -847 -1229 -1108 -1201 -1112 -1404 -1626 -1147 -1128 -723 -1425 -1154 -624 -1342 -751 -790 -949 -904 -1256 -1187 -1065 -874 -763 -1138 -1016 -1231 -1280 -893 -1094 -853 -739 -684 -939 -1192 -829 -922 -1066 -1041 -1173 -616 -929 -764 -773 -986 -1352 -864 -794 -610 -903 -1085 -1027 -853 -984 -941 -1223 -1139 -1095 -1301 -1072 -632 -626 -972 -1228 -1203 -687 -725 -934 -938 -890 -973 -1297 -1070 -778 -851 -1342 -696 -957 -723 -1633 -1007 -937 -1272 -508 -777 -558 -722 -746 -663 -770 -789 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/random.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/random.txt deleted file mode 100644 index 36fb8b614..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1231 -1639 -1970 -1399 -1105 -1384 -1590 -2156 -928 -1920 -1554 -2117 -2474 -1767 -1376 -2072 -808 -2260 -1173 -1058 -693 -934 -1662 -2310 -1460 -1555 -1652 -1073 -1033 -2583 -1684 -1658 -1843 -1599 -2530 -1820 -1352 -1462 -1448 -1323 -1530 -1857 -2336 -1227 -1790 -1577 -1409 -2208 -1858 -1301 -1790 -1353 -1407 -939 -1381 -1483 -2219 -2806 -2051 -1606 -1321 -930 -1520 -1342 -1716 -2307 -1319 -1799 -1760 -1144 -1733 -809 -1376 -1472 -2254 -1121 -1660 -1378 -1985 -2079 -1501 -1653 -836 -1900 -2553 -2093 -1517 -1598 -1494 -1769 -1458 -1903 -1869 -1543 -1421 -2257 -1367 -2450 -1469 -1043 -1555 -882 -1935 -1431 -1196 -3130 -1284 -1553 -2104 -734 -2566 -1552 -1617 -1385 -1868 -2270 -2270 -1907 -2549 -1794 -2249 -1274 -2334 -2349 -1991 -1820 -918 -1027 -1910 -1855 -1574 -1365 -1350 -2117 -1472 -1970 -1501 -1873 -2269 -933 -1576 -1721 -1961 -1249 -1469 -1356 -1316 -1879 -1786 -1372 -1461 -2326 -1462 -1900 -1715 -1580 -2028 -1611 -1985 -1040 -1785 -1059 -3182 -2460 -1967 -1761 -1424 -1037 -1164 -2289 -1977 -1343 -774 -1556 -1381 -1713 -1862 -1559 -1839 -2047 -1235 -1517 -1628 -1922 -1972 -1330 -2021 -1962 -2709 -1733 -1642 -1278 -1860 -1331 -2154 -2064 -948 -1343 -1690 -1734 -1822 -989 -1950 -1789 -1023 -1200 -2385 -985 -1198 -1088 -1728 -1272 -1306 -1493 -1871 -1244 -1981 -1554 -2472 -1943 -1453 -1684 -1121 -1455 -1305 -1866 -1729 -1637 -1719 -1820 -1884 -1137 -2195 -1553 -1483 -1501 -1921 -1429 -1724 -1775 -1810 -1488 -1191 -920 -1417 -1771 -1473 -1727 -1118 -795 -1003 -1479 -1865 -1683 -1455 -1330 -853 -1840 -1556 -1331 -2585 -1810 -1218 -1267 -1554 -1610 -1818 -1376 -2701 -1302 -1370 -2351 -1515 -1448 -1408 -1123 -2082 -1803 -1354 -927 -1586 -678 -1140 -1169 -2481 -2691 -1154 -1732 -2620 -2206 -1778 -996 -1132 -1689 -1557 -1698 -966 -1436 -661 -1032 -3087 -1359 -1274 -1856 -1437 -1366 -1030 -2421 -1643 -1043 -1332 -2203 -1458 -892 -949 -1803 -1641 -1246 -1953 -1277 -1761 -1687 -1769 -1153 -1994 -2269 -1347 -1372 -2039 -1344 -1534 -1384 -2322 -1731 -1859 -1149 -1913 -1611 -1455 -1734 -1451 -1716 -1754 -1030 -2380 -1605 -1684 -1370 -2301 -1223 -1945 -1051 -1685 -2026 -1887 -1834 -1281 -2354 -1095 -1625 -2142 -1747 -1811 -2064 -1062 -1712 -1885 -1596 -1096 -1518 -815 -2086 -1642 -2136 -2116 -1633 -1742 -1467 -1294 -1934 -2128 -1192 -2148 -1820 -2246 -1898 -1267 -1120 -2163 -2107 -2415 -678 -1779 -1419 -1649 -1684 -1690 -1773 -1277 -1303 -2051 -1905 -1002 -1354 -1247 -927 -2176 -1716 -1002 -1480 -1589 -2224 -1577 -1502 -2327 -1348 -2178 -1674 -1950 -857 -1303 -1933 -1901 -1118 -2097 -1478 -1566 -1180 -1002 -1710 -1578 -1534 -1634 -1612 -1748 -2359 -2189 -906 -1475 -1263 -783 -2892 -1151 -1795 -1366 -1545 -1800 -790 -941 -1669 -1383 -1949 -1595 -1147 -1431 -2068 -1815 -1582 -999 -922 -1821 -2896 -1774 -1503 -1853 -2079 -1357 -1503 -2042 -911 -1555 -1492 -1905 -3058 -2993 -2584 -1069 -1602 -1412 -1490 -1936 -1283 -1398 -1873 -1849 -1059 -1846 -1263 -1404 -895 -1750 -751 -1905 -1760 -1700 -1157 -2303 -1713 -1634 -1172 -2188 -1705 -1906 -1438 -1617 -1767 -1185 -1924 -2206 -2335 -1702 -1492 -2925 -1498 -1264 -2140 -1124 -2259 -1270 -2299 -1135 -1530 -1974 -2964 -1702 -2252 -1777 -1794 -1233 -2232 -968 -1757 -1431 -807 -1415 -1649 -1460 -1869 -1686 -1903 -1724 -2168 -1584 -1645 -1621 -2510 -1574 -1097 -1165 -836 -2317 -1231 -2428 -2064 -1098 -1736 -1052 -1384 -2490 -1739 -1677 -2977 -1560 -1769 -1637 -1491 -1933 -2191 -1939 -1709 -1400 -1642 -1771 -1911 -1898 -1655 -1677 -864 -1177 -1695 -1399 -1287 -1143 -1875 -486 -1766 -1351 -2356 -1373 -812 -1991 -2163 -2222 -1814 -1334 -1547 -1872 -1661 -1057 -1779 -1336 -1855 -1248 -2530 -3158 -1031 -1840 -2300 -1361 -1280 -955 -1258 -1463 -1268 -1514 -1621 -1960 -1209 -1638 -1966 -2096 -1461 -2405 -1718 -1679 -1488 -1138 -1601 -2462 -2229 -1440 -972 -1002 -1627 -1243 -2228 -897 -1502 -1462 -1481 -989 -1513 -1644 -2239 -1749 -1704 -1811 -1732 -1982 -1389 -1868 -1432 -1545 -1393 -2003 -2108 -1866 -871 -1073 -1193 -1164 -1832 -2336 -905 -1103 -1400 -1770 -2291 -1827 -1090 -1700 -1313 -1341 -1103 -1593 -1875 -1900 -2133 -1074 -2576 -2715 -1691 -1360 -1141 -2488 -1940 -2357 -1490 -1595 -1852 -1729 -2262 -1055 -1272 -2046 -2299 -1886 -1729 -1441 -1588 -1005 -2588 -1580 -1350 -1465 -1695 -1425 -2157 -2005 -1577 -1685 -1516 -1886 -1571 -3552 -1854 -1190 -1631 -1632 -1035 -1606 -1581 -3024 -1546 -1091 -1934 -1753 -1373 -2529 -1474 -1202 -1914 -1425 -1505 -1270 -1919 -2818 -1326 -2068 -3045 -1726 -675 -1359 -1654 -2062 -1425 -1177 -907 -1402 -1727 -2272 -590 -1299 -2494 -2786 -1130 -1859 -1496 -1031 -1697 -2112 -2171 -1950 -1889 -1317 -1062 -1254 -1374 -1444 -1620 -1964 -1341 -1634 -1342 -1238 -1570 -1174 -1377 -2153 -1798 -1503 -1659 -2371 -1610 -2207 -1754 -2234 -711 -1375 -1890 -1924 -1078 -1236 -2126 -2205 -1200 -2358 -2283 -1272 -651 -1845 -1162 -2012 -1639 -1521 -2489 -1709 -1116 -2086 -849 -1151 -2124 -2263 -1859 -1704 -1585 -1344 -2312 -1754 -1634 -1954 -1366 -1394 -1392 -2138 -1412 -1502 -1154 -2028 -3245 -1151 -1309 -1325 -1822 -1938 -1163 -1401 -1685 -1667 -2162 -939 -1479 -1604 -2077 -1470 -983 -1872 -1324 -1124 -1681 -1463 -1607 -1102 -2111 -2045 -1215 -1274 -1724 -1778 -1762 -1447 -1893 -1687 -1882 -1296 -2386 -2545 -1507 -1596 -1890 -1467 -1462 -2777 -1169 -1447 -1702 -2053 -831 -922 -1685 -1953 -1168 -1184 -3226 -1510 -2070 -1866 -1237 -972 -1297 -1764 -1856 -1011 -971 -1670 -2383 -2212 -1527 -1725 -2211 -1889 -2138 -1332 -2330 -1827 -2181 -1387 -2007 -1438 -1566 -1761 -2045 -1791 -1345 -1122 -1413 -2109 -1073 -2674 -1470 -1584 -1702 -2094 -1990 -1352 -2989 -2281 -1124 -1694 -2096 -1465 -2872 -1053 -709 -2729 -1451 -1755 -1666 -1619 -1045 -1125 -1562 -1297 -1156 -1742 -2243 -1523 -2049 -1954 -1653 -2389 -2366 -1602 -1356 -1874 -1863 -1847 -1050 -1624 -2644 -1213 -2497 -1574 -2186 -1472 -2537 -1286 -1460 -1501 -2388 -1775 -1752 -1740 -1743 -2207 -1940 -1690 -1491 -1697 -1596 -1247 -1797 -1993 -1943 -2116 -1795 -1683 -1632 -3143 -1713 -2476 -1385 -1271 -1767 -1190 -1972 -939 -2413 -1776 -1971 -2064 -1405 -1794 -1273 -2673 -2098 -1123 -2490 -1757 -1978 -2038 -2048 -2162 -2349 -1173 -1877 -1360 -1077 -1648 -1432 -1051 -1520 -2363 -2053 -1433 -1361 -1999 -3092 -1045 -1659 -2136 -1242 -2121 -1714 -1721 -1040 -1526 -1203 -2063 -1550 -1601 -1288 -3694 -1405 -1209 -1884 -1331 -1512 -2101 -1704 -2201 -1082 -1125 -2151 -1320 -2137 -1919 -1666 -1452 -1127 -1403 -1731 -1071 -1537 -1630 -1394 -1900 -3236 -992 -1542 -2309 -1073 -1133 -975 -1380 -1539 -2300 -2010 -1077 -2479 -1200 -1816 -1525 -1728 -1428 -1450 -1590 -2177 -1819 -1173 -1724 -2139 -1721 -2047 -1563 -927 -2129 -1473 -1483 -1717 -1847 -1297 -2313 -2386 -1380 -2532 -1826 -782 -1911 -1274 -1905 -1719 -1215 -1037 -1448 -1678 -1475 -1931 -1694 -1286 -1497 -1507 -1637 -1605 -1843 -1146 -1577 -1302 -1699 -1728 -2045 -1665 -1494 -2145 -2702 -1261 -1211 -1531 -1186 -1548 -2129 -993 -1475 -1366 -2396 -1887 -2323 -1877 -1057 -1839 -1359 -959 -1335 -1716 -2094 -1229 -1691 -1279 -1523 -1454 -1393 -2602 -1493 -1835 -1265 -1355 -2556 -1457 -1465 -1769 -1787 -2010 -2162 -1593 -2148 -989 -1384 -1593 -1753 -1301 -1977 -1701 -1106 -1109 -2219 -1639 -2381 -1747 -2324 -1652 -2048 -2366 -1512 -1639 -1289 -1399 -2188 -1780 -1773 -1604 -1370 -747 -1223 -2344 -2482 -2278 -1999 -1273 -1512 -1876 -1661 -2402 -1931 -1905 -2485 -2425 -1597 -2399 -2782 -1620 -2281 -1141 -2026 -1195 -1627 -1581 -2779 -2282 -2111 -1195 -1700 -1958 -1461 -1430 -1413 -2416 -2098 -1801 -3757 -1882 -1426 -1540 -1403 -1460 -1805 -1215 -1712 -1304 -1296 -2040 -2025 -1228 -1670 -660 -1054 -2864 -1282 -1913 -1256 -1990 -1327 -2034 -1798 -1332 -1980 -1944 -1951 -1691 -1737 -2127 -1203 -2275 -1759 -1805 -1484 -1081 -1094 -2472 -1562 -1632 -1716 -1307 -1476 -1610 -1959 -1006 -1395 -1321 -1422 -965 -884 -1212 -1433 -1947 -2514 -1536 -1382 -2110 -2338 -1537 -971 -2411 -2414 -1951 -1433 -1799 -1261 -1413 -2326 -2187 -2418 -2398 -1405 -1296 -2089 -1575 -1346 -1570 -1121 -1898 -1467 -1380 -1835 -1366 -2066 -2021 -1504 -2233 -1913 -1532 -1866 -1648 -928 -2747 -1501 -1610 -765 -2459 -1402 -1239 -1202 -1076 -1569 -1694 -2015 -1499 -1800 -1542 -1923 -2068 -1575 -1040 -1903 -2144 -929 -1365 -1896 -4486 -1688 -2087 -1271 -1990 -1601 -928 -1038 -1114 -1568 -1590 -1275 -1808 -1735 -1516 -2108 -1258 -1621 -2615 -1222 -2591 -1958 -1840 -1467 -1713 -1789 -1413 -888 -2160 -1992 -1223 -1449 -1117 -1678 -1694 -1621 -2943 -2043 -2231 -1525 -1201 -1079 -1265 -1381 -2575 -1168 -985 -1441 -2196 -1506 -2231 -1634 -2135 -1699 -1107 -1923 -1489 -2385 -1387 -1729 -1412 -1856 -2821 -1827 -2344 -1028 -787 -2286 -1573 -1981 -641 -1890 -2360 -1148 -1237 -1707 -1419 -1277 -2238 -1593 -1724 -1245 -1968 -1113 -1253 -2178 -2650 -1433 -2309 -1153 -1741 -1887 -2100 -884 -2874 -814 -1442 -587 -1941 -2199 -1661 -1302 -1320 -1502 -1385 -1452 -1101 -1375 -1122 -1565 -1986 -1282 -1468 -2283 -1330 -1943 -1711 -1276 -1818 -1730 -2671 -1900 -1517 -1337 -1090 -1424 -2018 -851 -1771 -1666 -1573 -2444 -1779 -1295 -959 -1521 -2094 -1747 -1324 -2832 -1119 -1443 -1717 -1620 -1421 -1222 -1912 -1649 -1114 -1821 -1787 -1162 -1681 -1423 -2105 -2264 -1353 -2063 -1437 -1231 -1235 -1267 -1560 -1539 -2417 -2588 -1449 -1353 -1200 -1485 -1854 -2381 -1070 -1678 -1867 -2621 -1098 -1417 -1734 -2025 -2246 -1876 -2196 -1369 -2591 -2368 -1533 -1510 -917 -1474 -2068 -1454 -2433 -1458 -1714 -1097 -2219 -1277 -1347 -1806 -1360 -1364 -1378 -2140 -1700 -1784 -1787 -2273 -1864 -1328 -1531 -2387 -1535 -1477 -1492 -1829 -657 -1558 -1593 -1510 -1593 -1140 -1327 -1202 -1673 -1804 -2621 -1717 -2523 -2116 -1646 -2081 -1658 -1383 -1167 -1395 -1927 -1796 -1255 -1225 -2323 -1823 -1487 -747 -936 -1329 -1127 -1851 -1058 -1545 -1337 -1090 -889 -1800 -1626 -1666 -1055 -2076 -1963 -2152 -1045 -2056 -1178 -2142 -1604 -1146 -1891 -1550 -1096 -1496 -1400 -2054 -1920 -972 -1538 -975 -1264 -623 -1897 -1382 -1598 -1611 -923 -1417 -2197 -1949 -1059 -1561 -1375 -1501 -2326 -1757 -2040 -1658 -2270 -1705 -1677 -2119 -1718 -1383 -1059 -871 -2845 -1207 -1294 -1894 -2076 -1179 -1315 -1504 -1021 -1042 -1942 -2078 -1791 -2713 -820 -2073 -2800 -1922 -1632 -1856 -1076 -1752 -2390 -1540 -2721 -2625 -1626 -1432 -1590 -1103 -1903 -2111 -1453 -1218 -2437 -658 -2470 -1626 -2324 -1795 -2005 -1397 -1219 -1294 -1754 -2445 -1370 -1670 -1699 -1039 -1452 -2580 -1084 -1901 -1916 -2342 -1568 -1947 -2036 -1145 -1617 -1721 -2066 -2601 -1824 -1754 -2161 -1357 -1127 -1512 -2162 -3119 -1094 -1937 -1380 -1312 -1471 -2268 -1895 -2291 -1714 -926 -1629 -1289 -1930 -2015 -1506 -1453 -1227 -2310 -1329 -1878 -1247 -1299 -1743 -2184 -2486 -1280 -2045 -1858 -1627 -2017 -1345 -2277 -1708 -1999 -2358 -1784 -1643 -1427 -1917 -2593 -1674 -1084 -1285 -981 -1702 -1205 -1785 -1450 -1448 -1518 -1936 -2033 -2199 -1828 -1471 -1297 -1375 -1682 -1203 -1642 -1527 -1353 -1081 -2338 -1545 -1341 -1160 -1476 -1398 -1597 -1788 -2152 -1065 -1362 -1331 -986 -1425 -2029 -1509 -1415 -2172 -1446 -1710 -1974 -1342 -2206 -1460 -1671 -2626 -1613 -1942 -1398 -1633 -2044 -1780 -1873 -1651 -1014 -1673 -1280 -1463 -1411 -1498 -2116 -2559 -1302 -1068 -2486 -1240 -2784 -1676 -1435 -1001 -1885 -975 -1000 -1070 -2282 -2717 -1111 -1421 -2257 -1354 -1980 -1525 -2080 -1289 -1431 -1220 -1838 -2043 -1684 -1103 -1461 -1979 -1345 -2335 -1498 -1113 -1678 -1297 -1541 -950 -1629 -1009 -1357 -1398 -1578 -963 -1472 -1469 -1889 -1828 -1538 -2094 -1354 -1198 -2006 -1248 -938 -1344 -2066 -1499 -2115 -1783 -1804 -1292 -817 -1439 -1205 -1151 -2537 -1476 -1244 -2034 -1774 -1428 -1256 -1557 -848 -1403 -1498 -1528 -1178 -2220 -1083 -1266 -958 -1450 -2001 -1878 -1710 -952 -1293 -1942 -1503 -1734 -1620 -1096 -1186 -1841 -2043 -1726 -2083 -1344 -2567 -1362 -2057 -1659 -1735 -1950 -1085 -1724 -1024 -1847 -2036 -3077 -1233 -1373 -1082 -1861 -1137 -1481 -1624 -1762 -1674 -1997 -2357 -1593 -2058 -1285 -1683 -1826 -1188 -1554 -1471 -1940 -2012 -729 -1744 -1303 -1144 -980 -1428 -1219 -1202 -1252 -1319 -2456 -1315 -2218 -2150 -1545 -1294 -2033 -1236 -1886 -1165 -1760 -645 -1477 -1650 -1519 -1499 -1983 -2003 -1408 -1570 -2269 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k3/trained_ddqn/best.pt deleted file mode 100644 index 8320b6ff58cefae24887e1453b3df41e9fef83ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13669 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 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/dqn.txt deleted file mode 100644 index 21bb0c85c..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1025 -823 -942 -1117 -664 -997 -1226 -1336 -1120 -1283 -599 -1250 -862 -663 -1006 -1174 -1112 -1330 -1197 -1288 -869 -732 -804 -746 -1245 -1081 -1013 -827 -1104 -1065 -1182 -1135 -982 -998 -1090 -871 -546 -1274 -965 -1067 -1137 -1537 -963 -957 -1272 -869 -907 -1002 -982 -1136 -1339 -930 -1164 -580 -794 -949 -1010 -863 -647 -1327 -972 -829 -917 -769 -1031 -931 -1589 -1003 -895 -879 -890 -656 -1084 -1308 -1044 -990 -906 -1076 -1195 -473 -715 -1067 -763 -1047 -1013 -1278 -666 -1155 -1157 -1327 -908 -1302 -694 -829 -964 -1244 -754 -1010 -855 -865 -1311 -808 -1166 -872 -1206 -1069 -1376 -863 -1044 -891 -841 -1097 -996 -1076 -808 -951 -1624 -972 -1468 -1301 -1115 -859 -947 -1207 -1305 -1158 -787 -749 -712 -857 -1223 -722 -1170 -880 -1152 -959 -1044 -1106 -719 -1269 -1242 -712 -937 -795 -1002 -1225 -1188 -722 -1282 -870 -1033 -1191 -948 -1142 -875 -864 -1185 -1072 -730 -1383 -913 -445 -1620 -1259 -1141 -619 -794 -645 -1480 -1353 -1392 -803 -861 -1444 -908 -1570 -1600 -913 -974 -916 -844 -908 -1022 -923 -1065 -1059 -1602 -888 -735 -1153 -894 -639 -888 -959 -1267 -1450 -717 -624 -979 -664 -1139 -1309 -957 -977 -880 -1205 -900 -813 -874 -1074 -1521 -1114 -883 -1047 -911 -1277 -871 -732 -990 -1785 -755 -1466 -1018 -1794 -1487 -773 -1340 -1404 -759 -933 -744 -986 -1281 -678 -590 -860 -1488 -837 -769 -762 -1337 -1518 -1190 -1068 -1138 -857 -876 -975 -729 -956 -1290 -1510 -820 -980 -742 -553 -964 -1108 -1061 -749 -869 -856 -582 -831 -981 -1982 -1048 -750 -1416 -1085 -1178 -1102 -760 -1693 -1134 -1172 -1084 -1443 -1531 -1351 -1074 -1125 -759 -1388 -642 -535 -803 -946 -1148 -759 -1565 -1776 -690 -531 -869 -1162 -1018 -849 -1538 -750 -868 -1527 -883 -1483 -1232 -1243 -804 -1379 -808 -1128 -1598 -809 -1111 -1494 -1168 -1146 -999 -803 -1135 -737 -1150 -933 -1081 -1156 -609 -1365 -1251 -939 -938 -863 -919 -1283 -638 -1076 -675 -961 -654 -1235 -842 -1292 -1340 -1327 -866 -858 -946 -1180 -1326 -1560 -891 -1025 -789 -1333 -1130 -1245 -1243 -1254 -818 -1199 -2040 -791 -959 -872 -718 -1011 -1063 -836 -874 -763 -1228 -667 -796 -1138 -746 -855 -1013 -1616 -1020 -644 -1121 -1374 -918 -1107 -926 -1050 -847 -771 -1070 -1236 -984 -1044 -1080 -692 -728 -1149 -732 -892 -849 -1028 -1377 -1230 -757 -1115 -1367 -771 -1328 -924 -1245 -723 -1159 -829 -1054 -782 -1268 -1389 -1566 -809 -932 -791 -1007 -978 -579 -600 -746 -1115 -721 -862 -1108 -975 -911 -1230 -856 -978 -971 -937 -1233 -1177 -1029 -1060 -904 -899 -590 -1209 -845 -1033 -1238 -999 -972 -754 -459 -1195 -995 -1333 -1079 -915 -803 -1005 -869 -1253 -1258 -1337 -1082 -838 -1236 -1001 -1098 -759 -755 -1146 -1024 -1592 -887 -1629 -1348 -944 -1025 -815 -1009 -888 -893 -1349 -1224 -1395 -1010 -1136 -1301 -1296 -986 -984 -1132 -717 -1146 -738 -1655 -914 -759 -1091 -974 -1201 -611 -1138 -1156 -1015 -808 -789 -1455 -692 -938 -997 -935 -951 -660 -1032 -1100 -907 -849 -1237 -813 -755 -1165 -1187 -1260 -966 -839 -699 -1103 -772 -1120 -989 -1123 -830 -720 -480 -998 -1095 -1418 -882 -872 -896 -1083 -1451 -816 -975 -1222 -1169 -1562 -1340 -1080 -708 -1439 -647 -874 -793 -1009 -1195 -824 -908 -1305 -1455 -1702 -1397 -771 -881 -697 -1258 -1158 -1012 -1333 -870 -737 -1178 -1178 -919 -859 -1094 -666 -1000 -800 -850 -1110 -958 -1256 -1144 -992 -883 -826 -1168 -1112 -1095 -593 -642 -1160 -1019 -439 -1292 -444 -1099 -902 -1057 -829 -1024 -1159 -788 -1008 -980 -996 -908 -923 -873 -1050 -723 -647 -1016 -1174 -1199 -991 -725 -916 -712 -648 -1107 -1097 -1156 -1144 -543 -1037 -997 -1320 -691 -876 -1292 -1049 -1302 -1242 -964 -1029 -1028 -975 -947 -849 -979 -570 -1234 -1123 -1342 -1082 -1174 -1033 -952 -999 -1598 -1856 -853 -1084 -1523 -861 -935 -1261 -789 -1020 -1279 -1133 -1157 -1104 -963 -1243 -999 -1165 -634 -767 -958 -1102 -1467 -1205 -902 -1190 -593 -1159 -796 -979 -1684 -1258 -1315 -1153 -871 -1159 -751 -1047 -1324 -968 -623 -1117 -1343 -578 -1263 -684 -897 -1228 -1517 -802 -1442 -1263 -659 -1191 -1167 -1076 -1228 -952 -524 -1023 -1024 -846 -758 -1307 -1004 -755 -914 -530 -685 -1290 -1154 -1024 -876 -1108 -1198 -943 -963 -759 -921 -1063 -478 -847 -1251 -1074 -762 -1365 -666 -1151 -1156 -1167 -424 -674 -1683 -651 -1109 -1328 -648 -972 -728 -1103 -639 -1015 -1409 -1025 -887 -723 -996 -626 -1111 -728 -1017 -711 -1062 -672 -1294 -578 -1254 -917 -901 -1060 -842 -1002 -879 -968 -1078 -1117 -667 -608 -893 -1018 -1319 -856 -1631 -776 -996 -1194 -1332 -688 -894 -1104 -1343 -1017 -917 -884 -627 -1047 -1468 -997 -1296 -901 -1056 -1398 -1647 -520 -1468 -971 -1110 -866 -1147 -857 -1035 -1178 -1184 -1259 -1048 -1667 -1224 -1146 -867 -1467 -599 -946 -743 -804 -669 -1183 -655 -1201 -1318 -1265 -1148 -807 -919 -1202 -815 -745 -1306 -1394 -742 -1053 -973 -572 -1132 -1357 -1329 -1113 -1259 -1031 -806 -1192 -1157 -1365 -620 -1402 -2084 -1193 -1629 -982 -576 -704 -798 -1234 -837 -808 -958 -904 -1288 -1351 -956 -754 -771 -1146 -804 -753 -1219 -735 -1086 -1197 -1295 -1062 -1079 -775 -1357 -1584 -546 -1445 -740 -1072 -1246 -1519 -874 -525 -1014 -646 -845 -1301 -1175 -760 -1317 -689 -920 -1129 -1386 -1065 -966 -1125 -492 -1210 -1260 -1432 -1022 -804 -851 -862 -861 -855 -775 -697 -738 -901 -833 -1080 -1041 -1546 -1272 -1094 -1269 -890 -1158 -1141 -1092 -1062 -916 -1283 -1276 -1052 -1147 -948 -1160 -1440 -953 -1030 -1093 -1110 -1182 -778 -1073 -1392 -1548 -795 -720 -598 -1117 -1078 -1135 -784 -1032 -1324 -1483 -980 -935 -1014 -822 -1594 -1095 -653 -566 -1101 -1437 -693 -1565 -737 -905 -1366 -1164 -1302 -774 -1465 -747 -764 -498 -1241 -1048 -902 -1189 -1349 -1162 -782 -633 -1159 -1117 -842 -1205 -1064 -1223 -972 -1070 -1101 -1142 -1021 -994 -1093 -1070 -1143 -863 -991 -1051 -1250 -794 -1037 -1119 -982 -912 -1035 -677 -825 -1060 -1286 -1370 -619 -1082 -1103 -765 -1397 -862 -1019 -967 -1782 -993 -1031 -1349 -896 -998 -1452 -1138 -955 -1236 -848 -608 -1122 -1790 -764 -955 -750 -1039 -1034 -794 -1602 -742 -1499 -916 -774 -1386 -820 -909 -1033 -693 -794 -881 -921 -973 -863 -1098 -1115 -808 -695 -931 -1405 -1188 -1228 -892 -754 -828 -824 -923 -1040 -953 -539 -738 -1079 -1094 -974 -727 -1141 -810 -1158 -1053 -1127 -1096 -1094 -820 -1034 -1312 -1215 -1631 -923 -781 -1423 -928 -635 -1055 -726 -1506 -1027 -916 -1380 -917 -865 -990 -1058 -885 -686 -984 -1321 -1378 -1330 -896 -1306 -1000 -1214 -1005 -669 -843 -692 -1257 -1206 -1224 -883 -553 -570 -1017 -563 -1043 -1201 -1244 -746 -1025 -585 -851 -1215 -1003 -898 -1272 -808 -1150 -696 -1030 -966 -603 -1018 -568 -1073 -1173 -1327 -981 -1500 -979 -859 -878 -1001 -944 -1166 -728 -1000 -553 -1424 -1071 -1430 -1345 -942 -1067 -727 -1051 -1100 -1442 -1375 -1409 -1292 -895 -1098 -1339 -1017 -1120 -825 -1637 -486 -834 -826 -805 -850 -1049 -863 -1056 -1218 -748 -629 -747 -1095 -1982 -905 -708 -957 -810 -584 -1117 -1489 -536 -1197 -718 -945 -957 -767 -878 -900 -845 -1633 -952 -937 -909 -864 -845 -1871 -1074 -964 -1385 -971 -1025 -890 -1014 -1795 -1063 -879 -1296 -723 -1335 -681 -1255 -1168 -913 -1789 -1020 -817 -743 -1305 -703 -763 -778 -730 -736 -1239 -1080 -1009 -1447 -469 -1026 -740 -994 -836 -724 -986 -1142 -1146 -1094 -996 -835 -1156 -1173 -725 -851 -813 -1173 -597 -571 -1858 -753 -625 -1251 -627 -956 -938 -565 -1008 -594 -1041 -709 -691 -1153 -1072 -879 -1028 -1087 -1132 -1020 -1545 -950 -957 -827 -973 -1481 -1114 -1276 -1611 -892 -976 -1510 -1153 -1010 -956 -1355 -703 -1077 -1503 -1291 -940 -945 -1249 -845 -853 -1146 -1091 -1204 -765 -969 -1508 -1406 -1078 -746 -796 -918 -700 -965 -875 -1135 -1005 -679 -515 -878 -1007 -937 -775 -951 -460 -1030 -690 -1124 -643 -851 -890 -1391 -1112 -1323 -801 -1167 -1150 -946 -784 -943 -1190 -1390 -964 -686 -1072 -823 -1307 -1048 -1099 -1045 -930 -898 -1192 -1228 -1322 -603 -780 -1109 -883 -1060 -772 -882 -1403 -973 -970 -999 -904 -1052 -1097 -759 -1239 -1216 -911 -846 -1180 -1263 -972 -1034 -964 -1229 -1012 -780 -612 -977 -790 -1242 -1855 -499 -1084 -959 -1097 -948 -1090 -1024 -1004 -799 -829 -755 -1527 -588 -948 -771 -1133 -981 -676 -643 -743 -766 -806 -887 -950 -1127 -807 -943 -933 -866 -740 -578 -811 -862 -663 -1054 -912 -951 -802 -1189 -808 -959 -761 -1012 -1057 -1222 -850 -858 -817 -1185 -1171 -1198 -1117 -896 -862 -1086 -816 -950 -551 -928 -716 -932 -1184 -630 -1412 -1070 -883 -1380 -998 -951 -555 -1063 -1399 -727 -1263 -888 -1112 -749 -873 -1016 -949 -1026 -1286 -1007 -1101 -1838 -1245 -754 -1074 -1155 -1108 -1075 -781 -703 -912 -1245 -1159 -1207 -1661 -1260 -703 -989 -912 -985 -972 -981 -925 -1637 -702 -1153 -891 -1235 -773 -1305 -1185 -767 -1211 -1100 -1378 -849 -1056 -1015 -1330 -918 -1207 -1337 -923 -943 -1689 -1208 -692 -922 -1314 -1263 -849 -1258 -799 -1493 -1004 -1139 -737 -997 -719 -1052 -792 -700 -687 -617 -967 -996 -780 -1074 -1094 -1077 -804 -1045 -735 -1098 -1008 -830 -747 -1073 -934 -941 -732 -1261 -1370 -505 -1545 -1089 -581 -909 -812 -1206 -915 -831 -555 -627 -918 -1763 -1088 -1178 -1099 -1227 -876 -1000 -1669 -979 -1214 -1494 -1024 -1309 -1101 -786 -1072 -831 -861 -533 -1209 -997 -801 -1172 -900 -1098 -1736 -761 -866 -1062 -1449 -996 -958 -1380 -695 -913 -981 -734 -1116 -833 -1057 -2118 -733 -1733 -1210 -1207 -958 -1421 -1079 -1064 -810 -1134 -690 -897 -1148 -740 -766 -749 -1324 -1263 -1176 -1188 -837 -815 -718 -948 -1047 -896 -1602 -1063 -1416 -903 -1306 -1119 -1319 -1194 -669 -935 -1077 -895 -1375 -1120 -1404 -1400 -658 -1036 -1320 -1076 -1022 -1196 -1290 -1139 -931 -745 -1512 -909 -1271 -1189 -593 -1251 -730 -730 -1922 -866 -1098 -1079 -1101 -898 -977 -729 -779 -1120 -1131 -996 -1028 -609 -1047 -979 -736 -1333 -782 -1186 -912 -898 -1118 -1253 -1022 -1032 -1366 -863 -1117 -842 -938 -956 -1175 -882 -973 -1477 -1240 -1006 -873 -916 -1230 -1138 -1112 -760 -1291 -1225 -594 -1220 -1040 -1227 -784 -1522 -864 -1092 -1283 -771 -582 -644 -1298 -801 -683 -1017 -731 -1029 -1041 -944 -1002 -1018 -1143 -1072 -1056 -868 -1131 -840 -879 -1676 -1215 -1116 -1275 -914 -1223 -1206 -845 -913 -498 -1231 -1089 -947 -857 -1205 -687 -1391 -1060 -608 -1237 -1114 -978 -593 -760 -1183 -831 -1230 -855 -967 -1357 -1080 -1366 -766 -734 -1271 -1042 -896 -775 -1181 -1031 -1030 -1240 -1699 -745 -847 -1046 -902 -818 -1628 -1355 -995 -815 -849 -1213 -1078 -803 -1186 -979 -1016 -948 -894 -597 -820 -1315 -1105 -1225 -1312 -761 -1455 -798 -929 -775 -1331 -1197 -457 -461 -1153 -1006 -1159 -1462 -1047 -724 -1218 -1062 -1077 -780 -779 -789 -905 -1592 -851 -1116 -1121 -757 -1303 -1101 -1050 -1118 -736 -682 -889 -956 -685 -980 -1054 -816 -740 -786 -1299 -855 -1479 -686 -866 -1026 -1005 -923 -1197 -1374 -1033 -697 -649 -648 -518 -1074 -820 -794 -1260 -1262 -1201 -1366 -1021 -1026 -796 -1298 -910 -1144 -1014 -594 -1430 -909 -1020 -1199 -1164 -869 -974 -1041 -1225 -1077 -1083 -1244 -1635 -1095 -528 -1370 -832 -954 -763 -1007 -1070 -677 -1225 -852 -877 -1029 -857 -1055 -1247 -795 -853 -1693 -1069 -761 -972 -1002 -813 -766 -1392 -871 -1124 -1396 -977 -1425 -1676 -1370 -941 -880 -1045 -911 -1165 -1052 -885 -792 -1303 -821 -798 -1233 -991 -671 -1392 -1157 -1219 -1178 -1314 -1089 -1186 -1396 -1237 -746 -845 -977 -1136 -930 -862 -806 -1057 -957 -1455 -949 -600 -830 -1291 -861 -1080 -1036 -1193 -1065 -822 -895 -549 -1086 -1340 -942 -972 -1009 -1118 -936 -643 -776 -722 -965 -901 -1472 -1395 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/optimal.txt deleted file mode 100644 index 708379ff5..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -606 -1070 -962 -1044 -832 -627 -1000 -1055 -836 -1086 -925 -549 -1111 -1135 -942 -1093 -717 -1291 -1364 -898 -1043 -829 -1161 -896 -1422 -740 -947 -1104 -835 -1033 -1101 -1110 -591 -920 -505 -670 -503 -1092 -1159 -1458 -811 -905 -1000 -1204 -877 -948 -1113 -710 -981 -506 -1354 -1289 -1022 -1003 -1025 -692 -1133 -1027 -1053 -697 -889 -562 -751 -892 -663 -891 -994 -965 -1105 -1204 -1320 -1476 -679 -1088 -895 -1130 -1151 -842 -1220 -853 -1036 -1234 -1013 -435 -647 -832 -699 -855 -1086 -1234 -910 -1237 -610 -1314 -893 -1456 -706 -866 -1443 -457 -1432 -800 -1288 -1024 -1056 -709 -958 -502 -809 -1051 -1010 -665 -1067 -1267 -988 -1349 -691 -686 -877 -1271 -1194 -982 -849 -1052 -1328 -842 -1648 -1090 -778 -930 -1015 -750 -964 -929 -1069 -1257 -1225 -1355 -1295 -1240 -1527 -1323 -963 -739 -1012 -1325 -1032 -705 -1020 -1001 -817 -1414 -941 -1043 -708 -699 -831 -1418 -1364 -912 -867 -1393 -1185 -1165 -1244 -892 -736 -1116 -960 -1283 -1167 -1510 -1268 -1578 -769 -800 -793 -815 -1409 -765 -678 -1148 -1543 -955 -941 -926 -1076 -697 -663 -1253 -1391 -767 -1082 -697 -988 -779 -1215 -797 -1063 -731 -757 -899 -893 -1215 -1171 -1246 -821 -1508 -1600 -981 -918 -1368 -1247 -782 -778 -1086 -1061 -1476 -851 -1105 -700 -786 -1232 -1139 -1313 -934 -801 -1022 -853 -789 -1212 -692 -1349 -1071 -730 -696 -801 -1058 -1216 -803 -1064 -1023 -1562 -580 -1011 -552 -820 -1372 -1180 -1304 -1206 -670 -958 -1112 -595 -1110 -1271 -743 -1221 -1305 -652 -1049 -690 -1196 -1503 -1690 -862 -892 -500 -707 -1131 -1187 -982 -1094 -1105 -1462 -1056 -799 -1539 -988 -1152 -848 -910 -965 -1162 -1667 -1001 -840 -1107 -1009 -1166 -879 -1544 -1381 -1374 -982 -746 -1239 -1052 -714 -750 -1105 -995 -1404 -815 -1372 -1139 -1321 -944 -1090 -1042 -885 -594 -985 -892 -837 -1087 -1073 -461 -870 -792 -735 -1362 -1464 -1198 -878 -549 -1190 -1330 -1054 -1051 -1042 -874 -1147 -974 -1056 -951 -1093 -1027 -1113 -775 -1260 -983 -1347 -713 -1030 -621 -1164 -960 -1171 -1205 -1239 -1304 -1118 -1141 -481 -550 -1174 -729 -1566 -658 -794 -1051 -1197 -1099 -868 -523 -995 -1222 -790 -1027 -860 -647 -711 -1051 -1321 -770 -1079 -1148 -1166 -926 -507 -963 -1095 -1282 -1473 -656 -1370 -912 -1221 -734 -843 -1174 -1058 -897 -681 -847 -1075 -737 -860 -701 -1372 -706 -570 -355 -1251 -735 -1173 -871 -976 -1590 -708 -788 -989 -1030 -1122 -968 -1169 -803 -691 -865 -1043 -769 -1323 -1101 -1150 -926 -1465 -580 -1069 -732 -631 -991 -428 -963 -849 -860 -1266 -1249 -1086 -975 -701 -671 -570 -1109 -1264 -864 -1203 -690 -666 -1132 -634 -1229 -1071 -1342 -1093 -787 -1268 -843 -1118 -1049 -879 -1207 -747 -743 -1271 -1192 -1105 -1010 -1027 -1443 -1472 -723 -842 -527 -984 -950 -1130 -782 -842 -987 -978 -484 -955 -1397 -1225 -990 -1143 -1451 -1063 -646 -549 -935 -783 -814 -715 -957 -1037 -832 -1087 -959 -1026 -1420 -803 -792 -1479 -1179 -1532 -657 -865 -705 -901 -1102 -1345 -1266 -1169 -945 -1149 -1170 -956 -843 -665 -1338 -1064 -933 -785 -1177 -749 -1100 -943 -987 -651 -986 -1258 -730 -1234 -781 -753 -1336 -918 -1197 -1033 -1032 -813 -1287 -1041 -1422 -1336 -876 -1073 -1093 -1086 -1200 -894 -1425 -885 -1030 -1187 -1379 -1605 -931 -694 -894 -879 -999 -1307 -811 -1199 -1451 -931 -1031 -1307 -865 -875 -1198 -999 -1141 -887 -752 -928 -974 -1171 -479 -1225 -1345 -897 -829 -662 -1122 -1064 -925 -1085 -1001 -865 -1273 -856 -872 -903 -1235 -984 -907 -988 -684 -1269 -1181 -1181 -457 -1231 -1033 -828 -751 -618 -974 -686 -943 -1107 -982 -1268 -1058 -1357 -907 -983 -1003 -1079 -1118 -1052 -1600 -746 -1229 -1237 -838 -1231 -1094 -1138 -838 -1710 -1228 -706 -1365 -585 -1695 -1045 -892 -1123 -788 -1078 -1516 -859 -1632 -837 -926 -950 -824 -1454 -876 -843 -1002 -1095 -622 -1422 -997 -794 -1611 -896 -889 -1000 -798 -999 -1045 -919 -1113 -1069 -967 -1168 -680 -567 -1047 -1043 -557 -723 -698 -508 -822 -863 -838 -872 -1264 -1039 -895 -1116 -1387 -966 -812 -1338 -1353 -1161 -1418 -870 -940 -1254 -876 -1270 -1037 -713 -1197 -1045 -1064 -812 -1349 -960 -1245 -502 -919 -785 -702 -631 -1167 -713 -715 -1174 -1014 -728 -1154 -1413 -846 -985 -906 -751 -871 -1100 -980 -1127 -732 -1015 -1246 -853 -1060 -1126 -1307 -992 -1006 -898 -1065 -1699 -972 -1164 -650 -558 -600 -812 -1076 -957 -965 -1128 -646 -852 -1080 -668 -1156 -903 -752 -1176 -1449 -950 -928 -1344 -990 -718 -856 -1303 -933 -1169 -714 -1018 -578 -840 -556 -1069 -628 -1296 -506 -704 -1069 -1132 -1350 -750 -1149 -962 -1017 -913 -701 -834 -779 -1011 -1135 -1668 -1055 -1239 -1031 -772 -789 -1135 -1061 -1136 -1143 -1394 -705 -972 -1138 -1205 -830 -439 -371 -758 -1484 -1552 -812 -1075 -1026 -1277 -1269 -723 -1141 -1308 -1010 -1218 -785 -600 -657 -978 -931 -1014 -917 -813 -1236 -1037 -679 -1258 -964 -607 -901 -1234 -1294 -1063 -1219 -769 -812 -918 -1099 -1464 -1159 -730 -1244 -1253 -760 -885 -1026 -571 -1088 -887 -629 -519 -1410 -968 -970 -1082 -1281 -954 -1084 -904 -885 -708 -1132 -825 -1116 -1083 -724 -1156 -1229 -1090 -712 -1286 -1405 -1108 -1111 -865 -756 -969 -1030 -1176 -980 -708 -911 -1583 -1227 -1129 -871 -801 -708 -732 -771 -845 -1027 -772 -822 -773 -1673 -1419 -1004 -916 -990 -1501 -640 -867 -1348 -1088 -864 -1311 -629 -661 -1274 -855 -1149 -976 -1040 -1073 -931 -1074 -948 -932 -1232 -698 -1363 -1039 -1153 -1057 -1411 -1134 -1026 -885 -670 -939 -1306 -1049 -599 -753 -994 -1416 -1005 -682 -592 -933 -1057 -1111 -842 -661 -1073 -680 -890 -1042 -741 -1120 -1531 -1574 -733 -984 -1230 -1078 -1148 -1034 -1103 -965 -815 -982 -917 -1181 -1423 -931 -1032 -605 -1074 -818 -1439 -682 -1116 -1138 -811 -693 -1117 -1309 -770 -694 -1363 -1163 -710 -532 -899 -598 -980 -962 -971 -1295 -751 -924 -873 -1031 -785 -838 -1040 -741 -787 -687 -738 -892 -1083 -908 -777 -1186 -1053 -830 -1362 -748 -1191 -917 -1058 -1113 -762 -687 -843 -793 -663 -743 -919 -528 -689 -1117 -1156 -890 -1006 -1286 -744 -1084 -1232 -807 -517 -587 -1108 -1064 -880 -1426 -1220 -777 -552 -848 -1040 -1308 -790 -755 -1125 -1110 -1211 -1189 -1009 -740 -1067 -1176 -874 -816 -1062 -1288 -636 -730 -730 -637 -1367 -853 -564 -713 -1320 -470 -1225 -954 -725 -829 -963 -1281 -908 -1277 -866 -750 -1063 -668 -1195 -896 -1047 -627 -1097 -1129 -948 -311 -1155 -1311 -1319 -964 -1238 -1019 -757 -1213 -1010 -1114 -1011 -945 -1127 -1111 -726 -747 -1113 -1033 -1111 -1160 -819 -714 -1398 -1113 -942 -901 -1271 -587 -991 -1191 -975 -1047 -1315 -1411 -746 -1060 -464 -955 -1346 -900 -1202 -785 -624 -1284 -820 -1226 -1087 -991 -1232 -1149 -1209 -1082 -763 -1477 -698 -751 -1263 -767 -979 -850 -1265 -1138 -1205 -1077 -1012 -1332 -1255 -1122 -660 -910 -1062 -981 -884 -805 -938 -1480 -517 -855 -416 -776 -626 -787 -1104 -1199 -1010 -867 -1247 -902 -857 -484 -980 -925 -704 -1277 -1248 -1187 -1221 -1031 -835 -1213 -1015 -1184 -1300 -1261 -1035 -858 -732 -1441 -1589 -1011 -788 -1057 -1214 -871 -1087 -652 -1303 -1290 -892 -1362 -516 -746 -980 -434 -969 -1029 -911 -725 -1002 -861 -664 -956 -1095 -1070 -427 -774 -956 -975 -835 -1323 -617 -810 -1094 -798 -1272 -962 -876 -992 -861 -916 -955 -796 -1103 -752 -842 -1468 -1351 -693 -1117 -1202 -730 -1000 -1335 -997 -777 -822 -1461 -698 -637 -351 -1470 -425 -1842 -1075 -1149 -906 -635 -656 -866 -1069 -929 -715 -764 -953 -971 -1028 -982 -1229 -1509 -823 -811 -882 -908 -955 -457 -1024 -793 -1312 -1011 -964 -1077 -868 -741 -955 -783 -1111 -563 -1187 -1000 -1054 -631 -2099 -923 -731 -637 -1092 -958 -752 -1092 -1030 -1011 -520 -1107 -1241 -1000 -924 -1103 -674 -1030 -666 -1307 -749 -786 -1243 -856 -693 -584 -870 -613 -808 -1376 -1174 -1104 -773 -995 -1124 -1210 -816 -1119 -1562 -1247 -853 -712 -875 -1044 -1235 -716 -840 -773 -1140 -1076 -577 -1231 -722 -870 -1245 -816 -882 -594 -1112 -1133 -889 -1334 -675 -1151 -1155 -763 -733 -717 -623 -858 -1074 -1190 -984 -1635 -1197 -921 -795 -835 -1623 -498 -1071 -767 -768 -1211 -879 -1129 -818 -761 -957 -1047 -924 -1189 -964 -996 -1407 -902 -564 -982 -820 -1024 -791 -908 -794 -611 -612 -710 -979 -1202 -931 -974 -1091 -1062 -842 -1517 -1335 -686 -794 -1235 -1062 -924 -1118 -468 -1644 -804 -1106 -1102 -876 -602 -1093 -592 -1195 -1008 -1213 -1319 -1268 -676 -829 -1107 -1092 -863 -963 -631 -1078 -754 -1180 -939 -1300 -1651 -1092 -527 -1202 -935 -923 -757 -745 -1215 -920 -1126 -700 -1038 -1323 -774 -779 -1042 -801 -710 -484 -816 -571 -913 -965 -526 -766 -1293 -867 -859 -996 -1585 -1180 -990 -1017 -800 -581 -839 -1011 -763 -1576 -983 -871 -1395 -705 -826 -792 -1013 -765 -889 -916 -806 -1172 -1099 -992 -1250 -1004 -1244 -883 -1344 -813 -889 -1367 -1198 -992 -931 -398 -1122 -1302 -674 -863 -1234 -1238 -1061 -823 -793 -761 -840 -760 -729 -519 -1242 -778 -997 -1415 -936 -1290 -1180 -695 -1368 -823 -1079 -971 -1335 -688 -1185 -939 -841 -1201 -1070 -1321 -839 -1032 -820 -1745 -771 -504 -1126 -700 -738 -908 -908 -1348 -1085 -1094 -894 -1292 -1060 -1473 -895 -828 -902 -1003 -1004 -838 -666 -1011 -441 -856 -795 -1425 -1437 -926 -786 -1501 -636 -772 -1462 -860 -808 -897 -1096 -1333 -575 -1132 -1174 -901 -927 -954 -1472 -1554 -672 -1491 -1190 -857 -1349 -801 -774 -890 -915 -1598 -1245 -1212 -1106 -1213 -1298 -1800 -1400 -1093 -1174 -1175 -1219 -960 -889 -1052 -843 -1184 -1544 -1158 -729 -1274 -809 -1142 -1221 -1172 -1481 -1394 -1077 -978 -965 -553 -1100 -1026 -1166 -907 -907 -1166 -1001 -815 -827 -817 -990 -951 -1260 -886 -1505 -969 -1168 -1185 -1281 -1109 -1097 -1049 -889 -1046 -1061 -991 -971 -677 -906 -870 -1001 -686 -1284 -776 -1309 -1016 -1667 -755 -827 -1994 -803 -767 -917 -635 -1013 -855 -1334 -1028 -1488 -927 -905 -997 -699 -1083 -1232 -1092 -829 -669 -811 -707 -1576 -937 -1354 -856 -1136 -1067 -1340 -923 -1247 -903 -635 -996 -1105 -1385 -657 -1432 -929 -979 -1078 -829 -1222 -614 -1056 -1133 -1105 -1580 -671 -1365 -962 -909 -1345 -1359 -840 -744 -860 -892 -1038 -1107 -722 -1129 -951 -963 -1202 -1063 -986 -1204 -821 -739 -1230 -1484 -710 -1014 -1241 -985 -564 -934 -961 -1362 -803 -1227 -543 -1279 -1154 -1091 -741 -555 -543 -721 -651 -930 -1160 -903 -1253 -889 -1003 -484 -871 -751 -988 -845 -774 -570 -920 -916 -909 -1290 -645 -830 -967 -1119 -719 -1074 -1123 -1063 -808 -890 -1102 -1052 -1195 -414 -1333 -1136 -996 -1123 -825 -1076 -1034 -789 -761 -1479 -704 -928 -984 -1032 -647 -1316 -985 -1098 -797 -987 -577 -625 -768 -729 -564 -1166 -1278 -1022 -919 -697 -1401 -1575 -670 -787 -725 -1040 -1039 -962 -665 -1227 -821 -730 -781 -950 -1222 -915 -781 -874 -1035 -679 -736 -1159 -796 -1037 -960 -1001 -1125 -998 -904 -960 -1391 -843 -802 -1044 -889 -1539 -1289 -598 -1409 -929 -625 -1570 -806 -1222 -797 -726 -1094 -1121 -921 -1084 -1385 -804 -711 -1080 -1049 -1298 -777 -1233 -990 -636 -934 -1260 -1133 -859 -1081 -902 -849 -1288 -505 -929 -1262 -1461 -854 -811 -1134 -846 -987 -912 -1178 -1498 -1105 -860 -1252 -697 -739 -897 -1274 -775 -795 -1090 -923 -787 -906 -1232 -1217 -1087 -733 -1041 -735 -892 -588 -937 -1290 -918 -1167 -757 -539 -1039 -1081 -919 -789 -1166 -933 -829 -727 -822 -1209 -726 -846 -422 -715 -1180 -920 -1058 -994 -1267 -535 -990 -1167 -1210 -860 -927 -671 -996 -1322 -690 -1193 -710 -1217 -1111 -929 -983 -683 -812 -688 -814 -1061 -1032 -697 -673 -1226 -1153 -599 -1262 -1078 -867 -707 -650 -577 -1193 -1095 -462 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/random.txt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/random.txt deleted file mode 100644 index 5dca02487..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1735 -2521 -2877 -2063 -1574 -1897 -2272 -1590 -1309 -1755 -1657 -2696 -2452 -1404 -1994 -3474 -1820 -2120 -2465 -2667 -2748 -1139 -2712 -1793 -3004 -1877 -3032 -826 -2832 -1520 -1595 -1339 -1885 -2167 -2544 -1780 -2861 -2482 -2179 -1750 -2115 -2409 -4181 -1854 -3065 -1824 -2068 -1982 -2722 -2628 -2861 -2822 -1544 -2845 -2687 -1855 -2275 -1762 -2365 -2473 -1867 -2449 -2166 -1419 -1615 -3294 -2200 -2275 -3495 -2753 -1995 -1647 -2694 -2001 -2281 -2198 -3614 -2469 -2502 -1231 -1715 -3423 -2019 -4700 -1490 -3849 -2916 -1552 -2978 -2151 -2840 -1042 -2721 -2751 -2097 -2511 -3355 -964 -1966 -1493 -2995 -2680 -2409 -2601 -2872 -2972 -1971 -2390 -2680 -1910 -2200 -1523 -2517 -1307 -1145 -2769 -2081 -3481 -2741 -1679 -1880 -3293 -2318 -2794 -2582 -3192 -2253 -1126 -2017 -2854 -3327 -2959 -2608 -1514 -3417 -1540 -2849 -1716 -2948 -2344 -2259 -2164 -1895 -1521 -1547 -1821 -3578 -2894 -1794 -2881 -2045 -1944 -3119 -2185 -2737 -3220 -1694 -2109 -4010 -2304 -1926 -3151 -3164 -1294 -1612 -3545 -3105 -2526 -2439 -1904 -2695 -2097 -2863 -3237 -2034 -2819 -2664 -2262 -2496 -1595 -1919 -3884 -2572 -2361 -2760 -2819 -1784 -2573 -2505 -2561 -3280 -2961 -2171 -2564 -2005 -2057 -3171 -2840 -2654 -1865 -2791 -2788 -2028 -1868 -2047 -2157 -2306 -2710 -2642 -1792 -3153 -2492 -2072 -1492 -1910 -1719 -1716 -3190 -2707 -2562 -2044 -1460 -1439 -2951 -1662 -2742 -2904 -1997 -2437 -2218 -1512 -2335 -1610 -1872 -2804 -1984 -3288 -3194 -1802 -1621 -2488 -2526 -2559 -3628 -3275 -2579 -3143 -1969 -2194 -1846 -5215 -1481 -1566 -2205 -2646 -2786 -1851 -3858 -2531 -2760 -2769 -1288 -1420 -1607 -2007 -2930 -1717 -2574 -1562 -2151 -2668 -3496 -2587 -2534 -1528 -1067 -2843 -2914 -2618 -2563 -1486 -2274 -1975 -3560 -1527 -2302 -2773 -2345 -3229 -1531 -2141 -2398 -2759 -2148 -3401 -1111 -1450 -2036 -3413 -3631 -2315 -1174 -3207 -2925 -2077 -3059 -2854 -2915 -2743 -2069 -3098 -2637 -3045 -3854 -2449 -2594 -1445 -2805 -2249 -2621 -1861 -1907 -967 -2055 -1792 -2102 -2162 -3785 -1305 -2101 -1656 -1801 -2209 -1907 -3031 -2081 -3032 -1425 -3117 -2229 -2518 -1632 -2677 -2023 -1539 -1656 -4035 -1394 -2624 -2326 -2077 -3028 -3196 -2857 -2455 -2906 -2879 -3284 -2554 -2699 -3220 -1244 -2108 -2073 -1865 -2502 -1454 -3825 -2776 -4809 -3005 -1565 -1969 -3223 -3492 -3662 -3433 -2540 -3276 -2594 -3353 -2054 -2621 -3132 -3271 -1678 -3130 -3575 -2615 -1792 -3245 -3378 -3616 -3470 -3370 -2218 -2308 -1645 -1600 -1399 -1928 -2023 -3902 -1610 -1696 -1642 -2916 -1496 -2207 -1716 -1571 -3250 -2134 -3797 -2237 -2476 -2669 -1223 -2990 -3055 -2047 -2989 -2839 -2517 -2169 -2278 -1708 -3242 -2409 -1733 -3108 -3773 -2607 -2590 -3189 -2238 -918 -2475 -2482 -2401 -3244 -962 -1064 -1553 -2001 -2295 -2388 -1610 -2074 -1587 -3195 -2082 -1389 -2581 -1493 -2056 -1528 -894 -2243 -1547 -3272 -1417 -2681 -2321 -2003 -1148 -2665 -1847 -1547 -1170 -1543 -1623 -2748 -2438 -1924 -3082 -1755 -3011 -3062 -2193 -2192 -2538 -2141 -2622 -1179 -3184 -1945 -2128 -1868 -1285 -2480 -1441 -1879 -1755 -3361 -1429 -1840 -1155 -3238 -2139 -1563 -3926 -1300 -2444 -2045 -2482 -1207 -2131 -3677 -1523 -3880 -2646 -1039 -2350 -2467 -2271 -2563 -1775 -1254 -2067 -3155 -1451 -2039 -1228 -2378 -2539 -2022 -2357 -2083 -2607 -2520 -2212 -3202 -2261 -1784 -2429 -2962 -1223 -2262 -1865 -2440 -2346 -2727 -2139 -2022 -1452 -2379 -2330 -2825 -3723 -3055 -2195 -2318 -2101 -2314 -3492 -1626 -2344 -1870 -1436 -1387 -2691 -2407 -2135 -2066 -3122 -2139 -1968 -2976 -2711 -2767 -1200 -3113 -2431 -1944 -1314 -4569 -1707 -1720 -1824 -2258 -1490 -2296 -3183 -2030 -2094 -1975 -2659 -1983 -2473 -1779 -1738 -2328 -1934 -2956 -2292 -1887 -1282 -2490 -2482 -2539 -1634 -2787 -2552 -1378 -2896 -1637 -1661 -2053 -2435 -2976 -3351 -3782 -1637 -2654 -3239 -2739 -3083 -2014 -1834 -3150 -3433 -2435 -1588 -3329 -2043 -1889 -3097 -2052 -2472 -2008 -4086 -1693 -1529 -2850 -2547 -2327 -2103 -1768 -3347 -3116 -3014 -1289 -1687 -2843 -3582 -3108 -1601 -2904 -2101 -1916 -1796 -1865 -1538 -2144 -1800 -1579 -2572 -3375 -1417 -3087 -894 -2004 -3050 -1508 -1819 -1356 -3827 -885 -2226 -2208 -1243 -2315 -2124 -2417 -2244 -3402 -2265 -1709 -3125 -2262 -2064 -3196 -2981 -1940 -2221 -1215 -3238 -2552 -1945 -2303 -1023 -1646 -1120 -2171 -2057 -2226 -1544 -1661 -2913 -1967 -4186 -2264 -1928 -2270 -2450 -2815 -2231 -3365 -2173 -2331 -2310 -2856 -2115 -2867 -2410 -1726 -3511 -1695 -3183 -2406 -2265 -939 -3837 -1282 -2165 -1859 -1537 -1917 -890 -2955 -3635 -2415 -2644 -2217 -4220 -2603 -2570 -2447 -3197 -2764 -2253 -1438 -1865 -3244 -2497 -2599 -1215 -1716 -1518 -1891 -2900 -1383 -2021 -1766 -1461 -2437 -2559 -2172 -2167 -1078 -872 -2275 -2335 -2219 -3423 -2016 -2378 -1560 -2320 -2736 -2866 -2685 -2286 -4973 -2378 -1663 -3691 -3791 -2490 -4326 -1492 -1783 -2853 -2437 -2265 -2074 -1808 -2646 -2642 -4460 -2445 -2577 -2389 -2144 -2192 -1962 -3596 -3011 -1941 -2354 -1243 -3022 -1340 -1845 -1563 -3531 -1588 -2723 -2186 -2750 -1813 -2150 -1777 -1515 -2419 -3296 -3252 -3100 -3176 -3025 -2494 -2348 -2485 -3483 -1716 -2714 -1823 -2427 -2028 -2912 -4093 -3325 -3184 -1784 -2911 -2413 -2790 -2174 -2157 -2509 -2134 -1768 -1775 -2026 -3713 -2816 -2103 -2824 -1765 -3140 -2029 -1923 -2137 -1609 -3389 -1417 -2539 -2665 -1490 -1671 -3453 -3298 -3192 -2553 -1824 -3035 -3581 -2236 -2020 -2605 -3581 -2129 -2995 -2580 -3011 -2196 -2340 -1816 -2596 -4041 -1739 -2658 -2548 -2746 -1981 -2998 -1500 -2466 -1556 -2251 -2125 -2030 -2662 -1348 -2109 -1291 -4002 -1710 -2443 -3908 -2194 -2065 -3865 -2420 -1491 -1492 -2747 -2856 -1810 -2656 -1457 -2528 -2612 -3004 -1777 -2823 -3023 -2173 -2386 -3859 -3043 -1814 -2073 -1903 -1670 -2325 -1961 -1629 -2124 -2515 -1997 -3830 -1572 -1869 -2229 -2517 -1350 -2220 -2089 -2754 -2471 -2512 -2190 -1356 -3092 -2504 -1860 -2754 -1991 -1805 -1552 -2033 -2085 -2049 -1938 -3331 -3204 -2095 -3396 -2474 -2488 -1631 -2862 -1732 -3064 -1915 -3897 -2389 -2758 -2753 -1590 -1997 -1735 -2370 -2598 -3610 -1875 -2817 -3399 -2856 -1965 -1637 -3176 -2358 -1340 -2631 -1705 -3055 -3047 -2595 -2161 -3315 -1588 -1399 -2243 -1568 -1236 -1810 -1881 -2516 -1841 -2257 -1769 -1777 -3101 -1563 -3167 -2290 -1986 -1954 -1699 -2699 -2723 -1856 -3974 -2553 -2467 -1900 -1753 -1548 -1867 -2509 -2129 -1859 -3009 -2580 -1628 -5295 -1862 -2090 -2020 -1749 -2008 -2660 -1818 -2885 -2896 -2379 -2037 -1904 -2308 -2465 -2378 -2328 -2305 -1936 -3906 -1541 -5521 -2204 -2724 -3370 -2262 -1265 -2609 -1175 -1089 -3319 -2599 -2524 -3130 -2670 -998 -2018 -1294 -1568 -1584 -4224 -2027 -1977 -2828 -3325 -986 -1164 -754 -2719 -2083 -2651 -1431 -2411 -2248 -1515 -3064 -3636 -2282 -2885 -2071 -3681 -2569 -1765 -2820 -1730 -1818 -2375 -1891 -2961 -2002 -2398 -1592 -1914 -2826 -2476 -3887 -2215 -1887 -1523 -3422 -1674 -2646 -2642 -1367 -2210 -2091 -747 -2459 -2811 -4662 -2187 -1729 -1702 -1653 -2455 -2621 -2849 -1622 -1355 -1801 -2628 -1773 -1817 -2198 -2232 -2758 -1068 -2567 -2060 -1897 -1133 -2182 -2370 -1603 -1751 -2284 -2601 -3177 -1748 -2104 -1956 -1648 -1665 -1457 -1892 -1815 -1324 -2648 -1571 -1853 -2329 -1182 -1987 -1624 -2463 -2046 -2409 -1174 -1457 -1898 -4171 -2332 -1566 -1504 -1849 -2461 -3106 -2858 -2374 -2326 -1078 -2437 -3113 -4375 -1385 -2205 -1873 -1996 -2406 -1821 -1824 -2336 -2198 -3283 -3279 -2930 -1965 -3276 -2079 -1538 -2173 -1573 -1755 -2925 -3135 -1454 -3329 -1575 -2696 -1827 -1911 -2820 -2158 -3267 -1651 -1137 -2365 -1595 -1906 -2060 -3427 -2488 -3129 -2678 -3430 -2084 -2657 -2032 -2378 -3647 -2697 -1849 -3476 -2234 -2500 -1897 -2760 -1451 -1767 -2928 -2338 -2818 -1915 -1585 -3583 -2298 -1794 -4011 -2485 -1878 -1741 -1977 -2169 -3346 -1649 -2388 -2311 -2846 -927 -2757 -2873 -3792 -2737 -2332 -2079 -1972 -3073 -2794 -2697 -1702 -3162 -1853 -1877 -3459 -2008 -2796 -2300 -1595 -1702 -2186 -2864 -2730 -1309 -2553 -4531 -2448 -2380 -1550 -1777 -2128 -1451 -2840 -2188 -2682 -2567 -2063 -2691 -2091 -2572 -2683 -2702 -1765 -3091 -2412 -2478 -2109 -2243 -2541 -4256 -1541 -719 -1264 -1477 -2330 -2705 -2140 -2157 -3056 -2398 -3328 -3081 -1371 -2140 -2444 -3402 -2806 -4276 -2599 -2841 -4318 -1687 -2341 -3023 -2528 -2774 -2071 -2327 -1243 -1947 -1665 -3165 -2477 -2908 -1813 -2150 -2904 -2026 -1916 -1526 -2773 -1658 -2391 -2578 -2144 -1675 -2596 -1403 -3006 -2661 -2703 -1857 -2908 -1932 -983 -4688 -4287 -1813 -2120 -1161 -1929 -3155 -1908 -3654 -3652 -2003 -2377 -2833 -2220 -3316 -2329 -1435 -3031 -1735 -2921 -3139 -2364 -2178 -3780 -2679 -3816 -3438 -1607 -1879 -2029 -2268 -3202 -3628 -3265 -894 -1238 -2289 -1645 -2884 -2610 -2133 -2471 -2281 -2982 -3302 -3827 -1665 -2694 -2782 -3605 -2026 -1118 -1479 -2347 -2176 -2577 -2591 -3363 -1391 -2586 -3147 -1347 -1433 -2092 -2757 -2287 -1034 -2101 -2223 -2775 -1591 -1700 -1592 -1572 -2966 -1248 -2276 -2784 -2167 -1341 -2189 -2847 -2413 -1795 -1983 -3063 -2505 -2975 -1725 -2248 -2505 -3358 -2485 -2586 -1615 -1875 -1695 -2997 -1750 -2972 -2287 -2448 -2357 -3237 -1035 -3899 -2199 -1422 -667 -2751 -2395 -1863 -1257 -2030 -1542 -2125 -2538 -2576 -3180 -1442 -2473 -2251 -2178 -1093 -1873 -3380 -4390 -3323 -2566 -2225 -1966 -3244 -3533 -1133 -2933 -3360 -1048 -3074 -1415 -2168 -2518 -2332 -2080 -3477 -2912 -2586 -1879 -1567 -3515 -1398 -2068 -3438 -3173 -1215 -2285 -1379 -2608 -3135 -3124 -1827 -2815 -3092 -1816 -2372 -2088 -3210 -2110 -2250 -3057 -1809 -2250 -3637 -2073 -1740 -2482 -1716 -2244 -2227 -2451 -1875 -1976 -2498 -1668 -3090 -2482 -2485 -2091 -1515 -2095 -1957 -2033 -4721 -2770 -1705 -2109 -2471 -2429 -2175 -2345 -1818 -2072 -2769 -943 -2075 -2725 -3585 -3185 -3852 -2718 -2462 -3703 -2244 -1975 -1985 -2412 -1792 -4777 -2081 -1802 -2757 -1633 -2047 -1360 -2232 -2505 -2660 -3263 -2821 -1649 -1598 -1885 -2148 -3362 -3302 -1369 -2782 -1539 -1891 -1259 -2577 -2127 -1956 -1751 -2334 -2053 -1687 -1892 -2762 -1243 -3149 -835 -1826 -2396 -2479 -2269 -2664 -1839 -2859 -1887 -1131 -4622 -3381 -3123 -1437 -3620 -2087 -2293 -3509 -708 -1931 -3885 -2139 -2385 -3323 -3126 -1307 -2283 -1656 -1852 -1828 -1434 -1676 -1919 -1888 -1675 -1489 -2489 -1733 -2057 -3006 -2733 -1639 -1320 -1110 -3069 -1750 -2766 -1675 -2698 -1761 -2353 -2231 -2459 -1978 -3517 -1417 -1954 -2457 -2118 -3983 -1335 -1797 -1789 -3660 -2232 -1234 -1134 -3096 -1625 -2756 -4464 -1677 -3319 -2714 -3002 -3186 -1367 -1427 -2573 -2317 -1549 -1642 -1413 -933 -3057 -3900 -3718 -2271 -2598 -3289 -2494 -1915 -2022 -4116 -2561 -3360 -2007 -1357 -1990 -3910 -2015 -2567 -2257 -1767 -3675 -2593 -4851 -3046 -4072 -2765 -2749 -2415 -2197 -1644 -2769 -1974 -2476 -3508 -2184 -1788 -2055 -2380 -2411 -3161 -1910 -2959 -1584 -2606 -1813 -2114 -2571 -1934 -2420 -2114 -2405 -2094 -2433 -2041 -3120 -2371 -2303 -1804 -1695 -1831 -2455 -3385 -2514 -3403 -3773 -1650 -1684 -2282 -3457 -1072 -1620 -2055 -3212 -2181 -3734 -757 -2644 -2234 -2691 -1909 -2578 -2215 -2990 -2110 -1209 -1913 -2520 -1383 -2502 -2829 -2260 -1951 -2925 -2277 -1373 -2654 -1382 -2676 -2644 -2181 -2479 -2235 -1884 -1636 -2323 -2654 -1421 -2985 -1976 -2432 -2082 -2084 -1876 -3853 -1396 -3037 -2270 -1412 -2898 -2266 -2842 -2759 -2198 -1874 -2204 -2524 -2160 -2290 -3782 -2216 -2165 -2255 -1912 -3568 -2524 -2208 -3151 -2075 -2236 -1550 -1633 -3393 -2065 -3621 -1544 -1853 -3163 -3099 -3974 -1444 -1929 -2671 -1856 -2667 -2509 -2343 -3136 -3301 -2774 -1010 -2033 -3714 -2255 -2597 -2155 -2898 -2583 -2437 -3083 -2040 -1731 -1905 -2422 -2655 -2477 -2869 -2651 -1183 -1900 -2931 -1879 -2516 -1557 -2402 -2155 -3636 -3546 -2623 -1334 -3005 -3019 -3182 -2016 -2333 -3310 -2552 -2213 -1770 -1836 -1526 -1898 -1637 -2358 -1961 -2515 -2603 -2089 -2400 -3682 -3195 -1831 -2539 -1748 -3498 -2003 -2549 -2486 -2363 -4251 -2175 -1415 -1195 -2014 -2119 -2244 -2255 -2898 -3139 -2286 -2441 -3834 -2163 -3208 -3408 -2813 -2393 -2232 -2247 -1142 -1773 -2401 -2649 -1616 -1146 -1896 -2182 -2647 -3205 -1620 -2299 -3659 -1534 -2391 -1351 -2368 -4441 -2880 -3188 -2287 -3040 -2343 -2196 -5044 -2684 -2916 -3611 -2682 -2710 -2891 -1368 -1496 -1885 -3644 -3283 -1602 -2306 -1622 -1623 -1386 -1808 -2705 -1729 -2017 -1700 -878 -2091 -2533 -2073 -1762 -1820 -3550 -1654 -2120 -1786 -2335 -1629 -1804 -3217 -3405 -1964 -2933 -2405 -3669 -2698 diff --git a/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_initial_segment/k5/trained_ddqn/best.pt deleted file mode 100644 index 7db98a409002e100e6ce01fd255df9b330965282..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/dqn.txt deleted file mode 100644 index b2cd46b9e..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1373 -1076 -1232 -1034 -820 -1357 -697 -924 -1089 -732 -987 -813 -686 -964 -859 -1146 -924 -672 -1385 -932 -1013 -753 -696 -1305 -572 -874 -1031 -1524 -789 -1243 -1224 -1520 -648 -1140 -1110 -781 -1023 -1052 -587 -1312 -702 -719 -1066 -781 -838 -1206 -763 -790 -1309 -643 -1172 -933 -1092 -741 -1262 -1065 -810 -721 -973 -1004 -927 -912 -1072 -827 -659 -1029 -928 -850 -1341 -1022 -998 -1000 -1436 -637 -711 -1142 -1007 -763 -1560 -925 -1151 -1089 -859 -981 -1230 -548 -749 -1225 -600 -772 -856 -848 -741 -692 -698 -1027 -1192 -961 -1506 -1260 -984 -763 -1390 -730 -774 -1551 -976 -919 -1379 -1298 -1248 -759 -1202 -718 -1645 -1525 -1302 -1378 -690 -755 -1169 -776 -1055 -1112 -861 -734 -923 -1388 -802 -824 -1076 -615 -1744 -1980 -962 -890 -573 -1169 -1096 -1311 -1230 -745 -1021 -824 -832 -1191 -711 -1163 -564 -1111 -1235 -604 -938 -1809 -1575 -1414 -719 -915 -758 -867 -938 -1155 -1028 -1482 -1429 -939 -662 -1194 -1390 -948 -1000 -1326 -1011 -1225 -927 -735 -1161 -903 -1016 -600 -625 -770 -1494 -820 -1311 -666 -996 -1287 -1164 -546 -746 -1403 -718 -1186 -1669 -1692 -711 -740 -1443 -940 -684 -1126 -816 -667 -1045 -992 -812 -1618 -1429 -786 -1017 -1358 -1157 -932 -1260 -1053 -933 -1041 -1033 -671 -1158 -1289 -783 -935 -765 -971 -1119 -1075 -953 -846 -860 -505 -932 -1486 -970 -1145 -1115 -558 -1066 -840 -874 -707 -799 -784 -832 -1018 -908 -892 -1193 -947 -1394 -832 -816 -991 -1299 -983 -659 -1814 -883 -935 -1296 -1072 -937 -976 -1392 -1444 -872 -1563 -967 -1067 -1066 -846 -1305 -1250 -1455 -875 -893 -1019 -1205 -962 -862 -1328 -1569 -476 -700 -889 -830 -837 -761 -783 -494 -929 -588 -817 -651 -1724 -826 -868 -772 -1098 -1271 -599 -1243 -880 -911 -865 -731 -1047 -518 -850 -1470 -732 -871 -726 -1288 -805 -498 -1717 -722 -1032 -1440 -665 -1614 -1306 -908 -1423 -880 -1089 -841 -1517 -1132 -844 -1459 -610 -1076 -758 -838 -977 -1107 -903 -548 -946 -478 -1086 -856 -792 -886 -1434 -1467 -773 -1311 -984 -1100 -809 -1227 -1281 -1075 -928 -691 -1297 -651 -1130 -1264 -965 -1081 -765 -1221 -707 -834 -1360 -928 -782 -1525 -759 -996 -841 -538 -696 -881 -634 -763 -828 -751 -1036 -938 -852 -1006 -1331 -860 -1112 -671 -836 -820 -1150 -965 -712 -895 -989 -1171 -1019 -1185 -1071 -945 -1348 -688 -880 -1090 -1061 -1023 -1080 -807 -831 -645 -1386 -1309 -703 -816 -1135 -796 -1189 -1040 -744 -1313 -1064 -1219 -1645 -1109 -949 -1154 -1653 -1465 -973 -1358 -585 -907 -493 -1000 -1364 -785 -1292 -1371 -982 -1033 -1151 -1310 -741 -1284 -1223 -1055 -1106 -870 -883 -808 -912 -1084 -865 -819 -935 -927 -894 -719 -890 -1027 -1308 -752 -827 -841 -539 -1132 -985 -1412 -876 -665 -608 -743 -1019 -841 -1204 -1044 -1159 -1324 -1309 -465 -1111 -1345 -933 -741 -1013 -1404 -1241 -1067 -742 -797 -972 -744 -1136 -929 -1155 -678 -873 -963 -1072 -1161 -605 -933 -1213 -1102 -1013 -633 -1332 -747 -1182 -1071 -772 -1277 -832 -701 -858 -822 -1430 -788 -1222 -1604 -1144 -689 -861 -1111 -907 -1281 -927 -726 -952 -930 -793 -651 -856 -872 -1275 -752 -1341 -666 -1812 -1460 -883 -1492 -929 -810 -905 -743 -662 -409 -815 -1195 -735 -746 -1163 -1104 -335 -1236 -1116 -1423 -1145 -746 -1420 -1071 -941 -1514 -884 -987 -1106 -489 -1590 -1684 -599 -1240 -885 -931 -752 -985 -1256 -1222 -1164 -843 -1235 -783 -951 -1012 -864 -1247 -1136 -782 -1221 -552 -1120 -670 -861 -848 -1132 -785 -634 -885 -908 -887 -862 -909 -1241 -1085 -1474 -981 -938 -1075 -1162 -940 -524 -1141 -1260 -1144 -935 -1175 -1263 -1070 -740 -816 -476 -1125 -1031 -1830 -1068 -962 -802 -1214 -663 -1035 -890 -1082 -1253 -953 -840 -870 -895 -537 -555 -949 -1306 -1469 -1189 -958 -808 -936 -1137 -636 -957 -567 -924 -873 -972 -826 -966 -993 -1549 -1280 -1007 -1024 -1059 -983 -958 -744 -1396 -840 -1190 -685 -1118 -1026 -844 -1444 -885 -730 -1264 -1184 -872 -801 -946 -1342 -971 -881 -1271 -848 -944 -866 -1026 -1279 -950 -971 -848 -1223 -1442 -1111 -995 -759 -748 -951 -1309 -535 -1134 -1387 -934 -578 -1059 -1023 -925 -986 -1439 -741 -1468 -746 -865 -1222 -1104 -965 -1174 -857 -1310 -1558 -1086 -834 -877 -1023 -625 -845 -1245 -627 -1228 -846 -731 -1155 -842 -694 -1432 -1243 -818 -952 -939 -988 -1259 -1060 -1059 -1032 -1133 -1100 -765 -714 -1330 -1057 -1405 -1097 -553 -878 -584 -961 -797 -1081 -1090 -895 -1158 -985 -1148 -859 -971 -883 -900 -1040 -737 -1141 -1364 -1088 -688 -1096 -887 -933 -1656 -805 -814 -1024 -846 -842 -1490 -827 -753 -1120 -907 -1223 -1039 -1024 -1040 -810 -788 -860 -1154 -564 -990 -642 -1053 -867 -716 -1630 -1349 -1890 -900 -626 -494 -750 -792 -785 -995 -1144 -851 -716 -654 -1407 -1080 -696 -976 -1109 -1025 -1093 -608 -784 -949 -683 -545 -815 -656 -862 -859 -819 -574 -1380 -1339 -912 -924 -1216 -572 -685 -1216 -1172 -1063 -1093 -643 -707 -1375 -767 -1403 -963 -963 -1006 -823 -1429 -827 -1163 -821 -851 -1407 -964 -1413 -925 -989 -1291 -725 -784 -1989 -997 -837 -1439 -1428 -613 -983 -729 -1056 -922 -974 -1111 -1070 -1115 -1584 -779 -994 -1110 -1100 -967 -916 -1014 -1157 -1194 -533 -995 -1311 -869 -1487 -1185 -883 -566 -904 -838 -1117 -693 -978 -675 -429 -874 -989 -1120 -1036 -923 -710 -823 -1366 -830 -604 -1073 -806 -1108 -620 -1263 -902 -804 -1108 -434 -1043 -714 -1004 -1213 -1086 -1340 -589 -504 -1427 -1674 -894 -1289 -621 -891 -1474 -908 -1404 -608 -658 -841 -871 -1205 -1389 -1013 -931 -1212 -960 -1087 -702 -1285 -964 -1040 -1094 -964 -509 -1214 -1092 -799 -915 -828 -1446 -930 -1799 -863 -719 -1092 -646 -1248 -1007 -1176 -887 -1098 -996 -729 -526 -680 -679 -988 -1026 -976 -1100 -1062 -1323 -1288 -1048 -1267 -799 -797 -804 -1390 -1241 -944 -846 -876 -1140 -901 -835 -787 -959 -1311 -1086 -1027 -938 -883 -753 -1415 -798 -755 -896 -1199 -744 -1123 -771 -1353 -774 -1083 -789 -1829 -790 -784 -902 -974 -1181 -914 -1023 -1006 -1059 -756 -964 -953 -1499 -934 -1281 -1107 -1185 -908 -736 -1063 -1271 -1387 -896 -679 -876 -1294 -750 -891 -1311 -1494 -759 -940 -1117 -1487 -1490 -1107 -1178 -803 -1077 -692 -1403 -907 -951 -737 -1082 -375 -1177 -972 -929 -1090 -1205 -769 -834 -1519 -783 -1419 -924 -1264 -1036 -1328 -1046 -1229 -897 -934 -888 -532 -1025 -732 -523 -1018 -651 -553 -925 -1174 -974 -943 -976 -1461 -816 -580 -1045 -796 -1066 -977 -900 -655 -1061 -1135 -933 -1249 -946 -1071 -574 -752 -1061 -1039 -776 -1154 -844 -1250 -1428 -745 -688 -1075 -1146 -998 -1017 -983 -632 -1291 -1099 -1163 -1046 -1252 -655 -1481 -1248 -1043 -1102 -1085 -1072 -959 -1478 -744 -839 -1926 -693 -1008 -912 -1072 -849 -1280 -710 -701 -932 -1000 -868 -1169 -765 -927 -917 -826 -915 -1311 -1129 -679 -921 -1350 -1144 -932 -585 -1323 -672 -1475 -883 -837 -1145 -871 -1431 -1125 -714 -1238 -1158 -1193 -1363 -628 -710 -714 -1279 -943 -1003 -620 -984 -960 -1059 -623 -634 -601 -1355 -1029 -1127 -1200 -1211 -837 -990 -919 -1167 -1039 -1124 -1048 -865 -944 -921 -1176 -659 -877 -1285 -1174 -916 -866 -531 -1094 -1163 -1019 -683 -968 -1294 -732 -1307 -1196 -1032 -1040 -778 -1208 -1022 -673 -995 -1041 -791 -943 -1260 -865 -973 -831 -889 -1083 -693 -901 -1495 -896 -1081 -1352 -620 -1269 -1427 -895 -934 -713 -1014 -1022 -664 -1389 -1018 -1113 -1434 -1059 -1312 -1299 -948 -664 -857 -1120 -471 -626 -727 -1160 -712 -1030 -1215 -1134 -1114 -1159 -1119 -1384 -859 -982 -1047 -1131 -1062 -1025 -958 -586 -486 -713 -1267 -1169 -733 -634 -1386 -745 -985 -811 -1445 -603 -342 -911 -871 -697 -1342 -860 -918 -932 -475 -712 -1193 -1205 -586 -889 -1341 -943 -1342 -1156 -1362 -1378 -661 -1146 -748 -713 -1296 -1303 -593 -1230 -1451 -1190 -1116 -1098 -1359 -1131 -516 -983 -946 -803 -1079 -879 -615 -1028 -484 -819 -840 -963 -1425 -948 -1050 -1004 -524 -1458 -1221 -1203 -1038 -856 -547 -782 -1212 -759 -1033 -1160 -1175 -980 -1181 -675 -864 -1021 -859 -1299 -1004 -1249 -800 -1268 -1473 -1249 -1020 -978 -739 -1126 -768 -902 -1109 -884 -1357 -748 -1437 -988 -862 -846 -1046 -853 -1046 -1274 -936 -843 -660 -1072 -1607 -914 -1059 -752 -677 -935 -783 -778 -1043 -1473 -1121 -1072 -1290 -1083 -998 -1000 -1072 -1323 -1212 -1474 -1336 -1259 -1019 -823 -907 -1365 -637 -1037 -754 -1101 -981 -977 -1563 -697 -919 -1104 -992 -1055 -836 -843 -1016 -1090 -857 -620 -638 -1290 -1000 -1116 -830 -1118 -705 -1155 -932 -760 -824 -1343 -815 -1193 -1360 -1124 -1093 -1291 -567 -1080 -1036 -973 -741 -876 -935 -633 -1397 -865 -968 -785 -1557 -1275 -784 -973 -874 -1035 -1163 -1504 -755 -553 -1364 -765 -823 -1135 -733 -1692 -1149 -1042 -466 -879 -1057 -1102 -1316 -623 -925 -1074 -891 -764 -1030 -1395 -913 -959 -1085 -908 -714 -1147 -1062 -722 -655 -1170 -1183 -906 -1141 -773 -822 -741 -1008 -1017 -1085 -776 -1238 -1256 -973 -932 -720 -860 -1144 -1187 -1363 -928 -733 -1478 -1153 -1108 -1193 -423 -850 -1214 -764 -852 -1022 -459 -1308 -923 -837 -692 -1177 -1051 -740 -918 -933 -744 -1099 -825 -923 -1070 -1094 -738 -912 -607 -735 -1239 -863 -758 -1145 -660 -1056 -676 -658 -1232 -1093 -1012 -1218 -765 -630 -638 -548 -768 -972 -747 -965 -890 -523 -1094 -692 -987 -692 -893 -586 -726 -1229 -827 -1111 -769 -650 -1079 -1049 -956 -1230 -812 -485 -596 -662 -1529 -715 -1199 -1159 -834 -737 -1212 -1627 -1048 -837 -929 -1182 -750 -906 -961 -792 -1066 -1013 -1324 -1087 -759 -467 -1020 -1334 -1259 -1443 -685 -888 -1522 -1201 -1348 -1058 -1072 -1234 -953 -578 -974 -1165 -364 -1081 -1008 -701 -653 -736 -1061 -769 -1390 -1071 -812 -859 -843 -837 -618 -639 -853 -1304 -672 -949 -810 -1266 -1077 -702 -819 -665 -688 -757 -913 -1060 -1134 -1064 -890 -957 -888 -1153 -1152 -1152 -644 -1075 -1053 -678 -1602 -1034 -1192 -1196 -420 -1222 -611 -1111 -1127 -1769 -1070 -877 -1037 -1108 -1208 -717 -899 -1023 -1263 -620 -1362 -1290 -758 -1015 -982 -1517 -927 -1122 -785 -986 -607 -870 -766 -763 -722 -1239 -1139 -824 -1352 -1159 -658 -900 -827 -593 -1369 -1320 -514 -884 -997 -1322 -1381 -1406 -949 -950 -636 -1286 -1062 -1039 -934 -1258 -583 -587 -725 -876 -974 -1453 -1177 -863 -1128 -584 -818 -830 -1132 -657 -1589 -844 -1152 -825 -1124 -1987 -1258 -1068 -969 -1397 -1206 -1252 -757 -703 -1576 -1266 -1063 -859 -682 -892 -1162 -1109 -988 -1424 -1431 -1163 -1319 -1237 -825 -1124 -981 -894 -1363 -1190 -1384 -845 -1182 -844 -627 -739 -726 -1085 -1044 -869 -730 -1013 -1372 -1062 -821 -873 -755 -731 -1123 -1178 -1252 -977 -753 -1468 -913 -937 -897 -760 -832 -1145 -788 -1301 -1183 -654 -1111 -816 -1351 -778 -1067 -955 -768 -597 -702 -872 -568 -720 -731 -855 -942 -1448 -1022 -1092 -920 -1156 -994 -785 -1066 -617 -1054 -1258 -808 -882 -883 -818 -1090 -1066 -981 -818 -847 -1446 -1332 -624 -1564 -806 -1112 -608 -853 -1213 -1076 -950 -666 -822 -858 -973 -802 -1743 -661 -1269 -1210 -894 -679 -728 -892 -1221 -874 -1217 -1048 -798 -783 -1353 -1447 -708 -1042 -994 -1163 -1024 -1030 -678 -869 -711 -783 -1341 -961 -1006 -734 -791 -768 -1154 -853 -1248 -1049 -893 -1245 -1113 -1263 -1125 -793 -961 -1239 -842 -695 -956 -785 -1028 -865 -898 -1109 -905 -824 -623 -753 -952 -684 -960 -1048 -1282 -956 -1191 -752 -978 -903 -590 -1233 -1260 -1279 -1244 -1153 -1311 -1672 -942 -1043 -992 -538 -745 -921 -874 -1501 -593 -1083 -704 -660 -1008 -1119 -1273 -1299 -746 -1048 -799 -1030 -1460 -1168 -1022 -1004 -1029 -988 -910 -819 -1220 -542 -474 -1254 -593 -866 -869 -1257 -1167 -1334 -783 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/optimal.txt deleted file mode 100644 index 140ddf19f..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -791 -1137 -736 -808 -1048 -738 -1294 -828 -1020 -1163 -922 -1507 -877 -903 -906 -817 -1204 -948 -1038 -886 -1072 -1316 -613 -1255 -1265 -1337 -594 -736 -945 -883 -1357 -305 -864 -927 -925 -633 -1619 -557 -900 -565 -788 -718 -979 -1079 -1190 -960 -1243 -1801 -1230 -1079 -1150 -1459 -784 -934 -967 -882 -1063 -922 -1174 -882 -1245 -1039 -761 -1243 -1085 -1058 -727 -611 -1152 -1107 -1294 -1046 -769 -1026 -1186 -1333 -884 -764 -809 -970 -885 -1054 -928 -918 -924 -959 -908 -915 -703 -977 -1413 -1046 -929 -1323 -1090 -817 -1278 -1023 -1469 -1090 -871 -856 -890 -1256 -1557 -539 -1289 -654 -817 -1183 -769 -1377 -710 -1038 -649 -1129 -1180 -869 -1423 -1408 -1171 -1177 -515 -925 -872 -606 -1014 -1162 -1201 -1189 -1169 -757 -799 -1631 -1072 -1089 -1170 -762 -1202 -1180 -880 -547 -804 -799 -1026 -1636 -670 -1055 -1002 -698 -1529 -1164 -879 -1116 -858 -1311 -1478 -1139 -652 -688 -1073 -1123 -1112 -1335 -605 -1309 -717 -1166 -717 -1080 -1174 -705 -1151 -1038 -867 -930 -894 -775 -863 -570 -1064 -1113 -1101 -1173 -606 -1049 -572 -936 -1686 -795 -675 -1196 -856 -617 -824 -1331 -891 -789 -1565 -443 -989 -969 -832 -784 -626 -972 -774 -887 -1252 -950 -1360 -694 -530 -877 -441 -849 -1014 -1021 -1192 -1162 -1627 -806 -1096 -1243 -1052 -969 -684 -799 -296 -586 -965 -1037 -1047 -802 -835 -1041 -1087 -1133 -920 -1225 -1149 -1422 -1113 -905 -1126 -1223 -1242 -1194 -866 -825 -972 -1303 -903 -1226 -697 -1351 -766 -1187 -1020 -689 -1009 -1092 -1366 -1304 -1016 -591 -1136 -741 -890 -860 -1111 -1576 -1046 -1058 -895 -914 -823 -1003 -581 -1290 -960 -540 -1424 -1006 -1126 -1112 -795 -914 -1086 -1166 -620 -824 -944 -741 -859 -996 -1116 -1304 -1005 -991 -1116 -1288 -1717 -731 -1578 -893 -1178 -897 -900 -1116 -1275 -893 -1020 -927 -749 -1011 -1456 -1285 -1613 -881 -1206 -910 -1101 -654 -850 -1024 -759 -651 -890 -781 -949 -1064 -984 -656 -629 -877 -975 -1137 -1250 -1464 -962 -1225 -901 -953 -1049 -619 -1351 -1063 -899 -894 -949 -1336 -708 -929 -791 -867 -983 -1142 -1214 -1452 -1164 -685 -917 -1066 -1074 -998 -1447 -1102 -945 -845 -1167 -657 -1029 -829 -505 -825 -1101 -721 -749 -775 -1224 -758 -897 -1021 -1230 -1086 -1310 -1746 -926 -1108 -752 -1028 -1620 -1234 -702 -958 -738 -1147 -886 -1027 -1308 -768 -558 -636 -1050 -614 -904 -1510 -1033 -1117 -1086 -905 -791 -868 -466 -1478 -1237 -1127 -1625 -952 -1026 -1489 -831 -1084 -1203 -890 -1431 -1018 -1404 -785 -643 -1081 -1207 -811 -708 -1113 -1061 -994 -1093 -910 -1010 -714 -879 -1299 -1219 -1326 -740 -1234 -1049 -693 -1414 -928 -980 -913 -1585 -1044 -757 -1229 -826 -763 -1392 -982 -1401 -680 -1187 -920 -1014 -1133 -1360 -891 -1246 -1876 -1335 -587 -1182 -1103 -805 -1021 -1000 -687 -1162 -1147 -896 -939 -942 -1098 -723 -933 -925 -877 -853 -730 -796 -1554 -931 -1003 -1271 -682 -943 -1574 -1391 -683 -1168 -1203 -1345 -771 -948 -709 -621 -643 -931 -982 -494 -549 -1136 -1301 -961 -1265 -580 -1410 -1091 -719 -665 -971 -688 -1046 -688 -1100 -838 -811 -697 -1175 -1114 -809 -912 -733 -1397 -817 -907 -820 -977 -840 -975 -924 -1270 -990 -1176 -1608 -1304 -766 -946 -910 -890 -946 -1044 -1403 -989 -974 -531 -753 -971 -512 -1489 -1634 -1062 -1204 -1009 -868 -505 -902 -932 -923 -1082 -753 -1009 -919 -957 -583 -1086 -1294 -810 -1230 -867 -1491 -813 -1085 -1195 -1842 -633 -1237 -948 -1205 -1171 -1229 -883 -1159 -1126 -1235 -1542 -1064 -968 -877 -815 -728 -1230 -936 -760 -1208 -940 -901 -1514 -1743 -936 -727 -766 -1240 -1118 -1040 -677 -1280 -1068 -1324 -808 -750 -995 -847 -1307 -976 -1174 -622 -859 -937 -1092 -1049 -1024 -1292 -1112 -961 -1084 -1027 -909 -987 -1299 -764 -1240 -886 -918 -875 -843 -1155 -811 -947 -863 -1296 -1435 -1180 -622 -1613 -1211 -1474 -651 -1175 -620 -851 -799 -785 -833 -1421 -952 -924 -1014 -1045 -954 -805 -1102 -1154 -944 -995 -1104 -738 -1723 -1285 -1367 -759 -823 -702 -885 -1129 -668 -889 -1069 -1092 -1326 -618 -1237 -1321 -1154 -706 -1218 -893 -609 -1041 -558 -1441 -765 -1238 -1047 -948 -1100 -822 -1109 -1152 -1284 -1891 -1187 -665 -956 -565 -499 -803 -1096 -1129 -1371 -613 -845 -1052 -1514 -1298 -1000 -529 -1260 -896 -761 -646 -1211 -899 -954 -891 -665 -849 -1006 -1217 -763 -766 -804 -522 -1013 -1075 -1418 -1379 -1047 -541 -520 -1202 -734 -1441 -729 -881 -505 -1325 -1056 -966 -899 -481 -831 -819 -1026 -997 -856 -930 -1130 -913 -893 -936 -1030 -1041 -1131 -874 -1264 -1078 -1067 -933 -651 -1502 -954 -1042 -1106 -683 -1246 -662 -1054 -733 -883 -606 -958 -1086 -799 -1375 -1348 -908 -1581 -1416 -1055 -1016 -1322 -871 -850 -826 -893 -679 -751 -1284 -1597 -958 -920 -596 -759 -1068 -1199 -755 -798 -1104 -919 -1041 -512 -996 -769 -593 -1092 -888 -1067 -1145 -984 -719 -1197 -1245 -951 -1065 -1100 -926 -385 -683 -930 -1066 -1237 -732 -1108 -799 -929 -1432 -1418 -1099 -895 -914 -609 -834 -707 -1366 -923 -804 -1585 -896 -1021 -1084 -1365 -843 -856 -1578 -868 -1039 -928 -755 -990 -564 -962 -991 -817 -1178 -799 -665 -979 -1015 -886 -937 -1374 -878 -1135 -1533 -1036 -1021 -883 -780 -911 -648 -943 -896 -937 -936 -1069 -990 -844 -792 -858 -571 -990 -614 -1007 -594 -1005 -687 -1064 -1000 -1259 -511 -935 -758 -945 -1134 -1116 -788 -810 -679 -703 -869 -846 -1264 -809 -1109 -1158 -813 -695 -1089 -1041 -777 -904 -830 -825 -731 -1176 -1043 -935 -968 -791 -1093 -1113 -846 -467 -1231 -996 -865 -865 -949 -1278 -617 -977 -1107 -623 -594 -1123 -894 -816 -856 -1066 -1320 -1420 -779 -928 -903 -1035 -980 -1435 -1029 -932 -1012 -1460 -932 -721 -780 -1080 -1206 -896 -1049 -608 -827 -1033 -1164 -1111 -1175 -1502 -1120 -1606 -1435 -1060 -565 -1045 -894 -1445 -1081 -788 -758 -807 -1080 -594 -1288 -977 -668 -726 -1262 -1547 -1546 -1036 -774 -1618 -1087 -1365 -1161 -953 -1368 -1134 -418 -906 -795 -580 -629 -874 -641 -1434 -1252 -790 -937 -1335 -478 -862 -683 -713 -1390 -1939 -856 -875 -852 -836 -1066 -1449 -1482 -942 -1207 -1337 -1441 -1012 -1134 -1024 -994 -557 -790 -893 -1184 -945 -951 -774 -798 -1293 -620 -968 -879 -1112 -1329 -625 -1126 -856 -959 -1111 -954 -950 -1593 -1419 -1166 -1276 -1118 -959 -738 -1012 -1097 -720 -1050 -984 -575 -1292 -902 -749 -866 -911 -1703 -1224 -1069 -948 -921 -589 -907 -1296 -940 -1042 -651 -1061 -1044 -891 -1032 -894 -488 -712 -1173 -822 -804 -1212 -607 -908 -805 -625 -919 -674 -1099 -1051 -902 -1302 -1384 -738 -941 -1225 -969 -1133 -701 -1250 -1303 -981 -1169 -1362 -841 -913 -1213 -1127 -1312 -702 -360 -1386 -1251 -771 -856 -1181 -373 -1305 -843 -1154 -465 -943 -620 -932 -1152 -779 -836 -916 -754 -1010 -1199 -1835 -1275 -925 -1034 -897 -1112 -1176 -786 -757 -676 -474 -1112 -545 -1164 -937 -1167 -1074 -1332 -901 -967 -1301 -1390 -880 -929 -1259 -1656 -507 -650 -1084 -1237 -737 -1125 -1645 -748 -1362 -1109 -686 -967 -1208 -1018 -641 -873 -1186 -1626 -1083 -775 -996 -893 -1294 -797 -958 -956 -757 -1367 -1078 -888 -699 -913 -1547 -785 -1062 -967 -981 -604 -1139 -928 -1203 -1043 -1288 -835 -936 -844 -1115 -1496 -861 -936 -931 -652 -787 -753 -928 -1240 -1234 -1099 -837 -821 -457 -975 -1016 -553 -1051 -1116 -916 -842 -551 -849 -791 -916 -931 -1236 -990 -898 -855 -1021 -702 -1181 -1643 -641 -1166 -860 -1057 -982 -963 -1089 -1104 -1264 -841 -918 -946 -927 -692 -1116 -889 -681 -1574 -1351 -1073 -680 -1024 -1004 -903 -780 -1257 -1126 -1104 -1227 -1075 -1071 -989 -1160 -946 -681 -895 -1124 -774 -1262 -652 -502 -989 -972 -741 -767 -1028 -1136 -632 -1124 -977 -1140 -933 -1191 -838 -1153 -829 -946 -1041 -908 -873 -966 -1109 -947 -943 -1045 -1240 -1066 -1439 -1093 -940 -574 -922 -901 -935 -1561 -1021 -668 -1240 -1034 -1283 -587 -680 -968 -889 -1147 -1091 -850 -1256 -1101 -1292 -1171 -1169 -1072 -1013 -1840 -768 -1029 -1254 -1233 -666 -974 -814 -1164 -1510 -624 -1353 -476 -1424 -398 -1197 -1003 -1454 -1532 -867 -1004 -883 -792 -1565 -1101 -1090 -1070 -580 -941 -1553 -721 -810 -1224 -1628 -560 -1190 -1377 -1130 -1305 -1224 -1037 -1695 -954 -854 -935 -1079 -916 -1007 -857 -936 -1055 -756 -952 -1136 -1240 -1609 -991 -1678 -701 -989 -892 -1284 -1191 -1069 -1145 -826 -1141 -883 -920 -1104 -1421 -1303 -807 -837 -738 -1219 -1183 -922 -984 -1564 -1401 -677 -1072 -1013 -1227 -647 -978 -1100 -1266 -1169 -863 -1097 -771 -1174 -771 -900 -975 -601 -835 -1507 -839 -1382 -954 -771 -1071 -1124 -1323 -1240 -602 -913 -571 -909 -1329 -968 -760 -868 -1065 -1890 -950 -1077 -1567 -1023 -968 -799 -828 -1393 -900 -1261 -769 -1563 -890 -1050 -1073 -1205 -856 -915 -1585 -746 -694 -1126 -1257 -893 -1627 -1657 -1364 -1539 -760 -1381 -793 -644 -825 -1134 -1496 -951 -871 -990 -1380 -1184 -772 -868 -1334 -1071 -643 -1015 -1083 -1415 -791 -1129 -1053 -971 -1454 -731 -729 -1162 -1377 -932 -993 -1443 -1172 -1026 -705 -1039 -1088 -959 -738 -1201 -1305 -801 -1205 -836 -761 -924 -549 -1089 -900 -1111 -1323 -719 -654 -1228 -982 -1586 -778 -667 -626 -1411 -1025 -935 -1061 -1698 -852 -1080 -1080 -1088 -840 -904 -694 -1203 -940 -653 -598 -1217 -570 -588 -783 -861 -1246 -889 -753 -892 -1110 -1166 -825 -1361 -1118 -1467 -760 -1551 -960 -1007 -916 -828 -1031 -1383 -1049 -951 -951 -850 -903 -1138 -1199 -1265 -953 -1981 -644 -758 -1011 -1414 -749 -1063 -973 -899 -726 -1021 -769 -1021 -872 -891 -607 -1051 -1302 -728 -949 -752 -1253 -922 -1493 -1008 -637 -740 -1096 -876 -1299 -538 -1127 -970 -810 -1127 -983 -746 -1386 -1345 -744 -762 -684 -840 -729 -656 -1122 -1120 -1321 -895 -1428 -887 -950 -1075 -1178 -1079 -780 -1056 -887 -822 -743 -798 -1139 -1141 -934 -1067 -1182 -880 -807 -923 -1130 -1412 -1011 -1166 -1332 -683 -859 -1237 -940 -900 -1339 -756 -922 -1014 -899 -1219 -1115 -1148 -515 -821 -1242 -771 -876 -736 -948 -1660 -936 -748 -940 -1045 -699 -664 -963 -654 -866 -1118 -932 -959 -1380 -991 -732 -1090 -998 -1340 -1702 -869 -1182 -1036 -818 -1182 -575 -1262 -517 -1481 -693 -398 -845 -1061 -1131 -1198 -929 -990 -1709 -991 -1341 -954 -890 -1713 -925 -1233 -1389 -1585 -1066 -1019 -1259 -1412 -937 -1103 -1339 -1208 -1118 -1518 -1543 -996 -623 -1179 -1080 -1162 -976 -1122 -1109 -1118 -1576 -1178 -996 -902 -1728 -863 -879 -843 -808 -850 -1066 -1009 -1332 -907 -630 -560 -795 -888 -817 -1485 -1286 -946 -1231 -878 -695 -1202 -789 -676 -880 -894 -907 -1024 -720 -970 -767 -967 -1296 -969 -630 -1001 -606 -835 -828 -835 -592 -1332 -1024 -1774 -1058 -1381 -797 -1032 -1642 -1171 -954 -704 -865 -1010 -797 -1469 -1099 -939 -1226 -868 -876 -1355 -1094 -1186 -711 -554 -978 -1284 -858 -992 -1585 -1309 -795 -1080 -735 -861 -712 -602 -913 -685 -1398 -1170 -817 -725 -1482 -1032 -1651 -532 -1637 -1257 -737 -1119 -1011 -962 -870 -1060 -1495 -1318 -1013 -975 -694 -1319 -1238 -1304 -1370 -1114 -1246 -1429 -604 -1141 -1922 -878 -1496 -1035 -811 -1389 -1225 -1010 -342 -1694 -943 -1297 -1005 -869 -1445 -892 -915 -1248 -951 -921 -1272 -715 -663 -582 -1015 -781 -975 -1054 -674 -1098 -1149 -694 -1068 -1316 -1219 -639 -1058 -1037 -1378 -869 -998 -876 -1263 -845 -1505 -1302 -1088 -509 -1169 -1234 -769 -1051 -898 -961 -825 -759 -1429 -930 -1109 -887 -779 -989 -1079 -1444 -1332 -973 -1045 -898 -1279 -1666 -1053 -767 -954 -1198 -738 -772 -839 -1002 -845 -1222 -1450 -677 -677 -1356 -1001 -946 -975 -1046 -690 -642 -892 -625 -1142 -1027 -952 -1600 -782 -1119 -692 -513 -630 -1312 -1175 -1030 -1015 -565 -961 -1354 -1291 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/random.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/random.txt deleted file mode 100644 index c48c353e4..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1728 -1949 -2340 -1000 -1234 -818 -1793 -2654 -1524 -1530 -1164 -1447 -2085 -2145 -2488 -2289 -2046 -1648 -1261 -1571 -2041 -1841 -870 -1783 -2048 -1029 -2192 -2351 -772 -1293 -1426 -2288 -1468 -1272 -1422 -3106 -1681 -762 -1074 -1183 -1942 -2783 -2075 -1643 -2240 -1871 -1805 -1750 -2047 -1957 -1107 -2178 -1510 -1815 -1516 -2878 -1343 -2461 -2363 -1628 -2148 -1726 -2930 -1719 -1556 -1080 -1417 -960 -923 -1768 -2625 -1698 -1564 -1319 -1402 -2080 -1481 -1003 -2202 -1216 -1133 -1954 -1680 -1928 -1814 -1445 -1938 -2744 -1490 -1810 -1254 -2559 -2000 -2627 -1351 -1796 -1629 -1398 -1374 -1417 -1557 -1409 -1478 -1725 -1950 -2446 -682 -1589 -1650 -2599 -1598 -1739 -2096 -1886 -2922 -944 -2299 -2032 -1738 -1460 -1390 -1514 -2132 -1736 -1868 -2045 -2124 -1574 -1663 -1437 -2262 -1150 -1867 -1212 -1160 -1643 -2045 -1993 -1727 -1792 -2458 -2266 -1236 -2347 -1485 -1596 -2253 -1082 -1768 -1942 -1553 -1457 -1963 -2399 -1943 -1507 -1505 -1460 -2010 -1846 -1667 -2141 -2879 -1415 -2197 -1638 -1439 -1508 -2744 -2175 -1453 -2569 -2239 -1541 -1838 -1289 -1987 -1534 -1988 -1199 -1899 -1425 -2809 -2027 -1179 -2163 -1995 -1692 -881 -2391 -1179 -1497 -1343 -2116 -1876 -1844 -1815 -1588 -2202 -2861 -1151 -2901 -1641 -1205 -2374 -1187 -1013 -1371 -1174 -2133 -2437 -992 -1752 -1487 -1690 -2519 -2017 -1411 -1327 -1428 -1614 -1355 -1866 -1356 -1773 -1479 -1763 -1407 -1590 -1554 -2430 -1640 -1899 -565 -1806 -2233 -1174 -1538 -1637 -1036 -1565 -1848 -1739 -1328 -1521 -786 -1931 -1622 -1345 -1565 -2408 -1283 -1793 -1497 -1517 -738 -2626 -1623 -2364 -795 -1538 -934 -2509 -1085 -1093 -1768 -1973 -1697 -1458 -1565 -2671 -1743 -1557 -2646 -1856 -2294 -1364 -3249 -1189 -2201 -2926 -1760 -903 -1665 -2339 -1927 -3041 -1841 -2014 -2680 -953 -2783 -1955 -1643 -1689 -1404 -2130 -1001 -1295 -1461 -1023 -2302 -1207 -2277 -1559 -2347 -1331 -2152 -3062 -2317 -1268 -2040 -2013 -1150 -1726 -991 -1401 -2293 -1475 -2154 -1461 -2418 -1965 -1676 -1405 -1857 -1685 -1629 -1634 -1694 -1401 -1211 -1336 -1207 -1446 -1555 -1866 -2028 -2045 -1383 -1659 -1737 -1565 -1584 -1514 -1111 -1497 -1476 -1642 -1835 -1812 -2078 -1413 -1752 -2067 -997 -1381 -2545 -1757 -1948 -1374 -1773 -1237 -3052 -1666 -904 -2185 -1917 -1488 -2376 -1269 -1336 -2235 -3197 -1460 -1311 -1582 -1073 -2339 -2038 -2136 -1954 -1270 -1138 -1477 -2243 -1271 -2394 -2164 -1320 -2092 -1386 -2402 -855 -2233 -974 -1417 -1857 -1890 -2052 -1722 -1087 -1296 -1840 -1525 -2092 -4211 -1766 -1905 -1608 -1862 -1139 -1602 -2307 -1784 -2873 -1104 -2126 -1853 -2655 -782 -1415 -1424 -2214 -1731 -1616 -1301 -1798 -2014 -2328 -2000 -1838 -1099 -2804 -1386 -1666 -1551 -1877 -1500 -1988 -1636 -1874 -1541 -1376 -1287 -1090 -3255 -1161 -1352 -1796 -1996 -1435 -1699 -1294 -1864 -1582 -1108 -1457 -1576 -1619 -1175 -1674 -1169 -1892 -2685 -1681 -1870 -1048 -989 -1916 -1740 -2588 -1226 -2017 -2390 -1029 -1371 -2082 -2377 -1536 -2349 -1758 -1768 -2269 -2280 -1790 -1251 -2977 -1513 -2301 -1996 -1764 -1991 -1921 -1133 -1662 -1183 -2400 -2721 -2114 -1529 -2004 -2230 -1816 -1800 -1124 -2102 -1353 -1589 -1140 -1477 -1720 -2026 -1783 -1699 -2004 -1716 -1952 -2356 -1470 -2237 -1581 -1479 -1070 -2457 -1743 -1338 -1842 -1083 -958 -2103 -1675 -1335 -2378 -2742 -865 -1510 -1394 -1737 -2111 -1376 -1403 -966 -2211 -1600 -2108 -1765 -2194 -2190 -1761 -838 -2460 -1492 -882 -1381 -1476 -1651 -1667 -2755 -2120 -1509 -1399 -1626 -1464 -1471 -1565 -1061 -1332 -2122 -2269 -2207 -1658 -1183 -1387 -2028 -2754 -1534 -2611 -1786 -1492 -1063 -2320 -2117 -1499 -1760 -1907 -1877 -1227 -2888 -1564 -1726 -1927 -1423 -1592 -2139 -1969 -1734 -1037 -833 -1006 -2046 -1740 -1983 -2181 -1588 -2210 -2875 -1227 -1389 -1331 -1858 -2655 -1806 -1532 -1680 -1081 -2136 -1580 -1768 -1500 -1692 -2190 -1916 -1698 -2543 -1614 -1503 -2304 -2312 -1164 -1750 -2075 -1517 -1549 -1764 -2674 -2868 -1409 -2087 -1510 -1547 -1019 -1868 -1874 -2053 -734 -1216 -1789 -2060 -2427 -1882 -1921 -1851 -1465 -2051 -2635 -1912 -1041 -1146 -2077 -1865 -1535 -1467 -3192 -2353 -1662 -2049 -2200 -1070 -2343 -1313 -1491 -1800 -1779 -1503 -2853 -880 -1856 -1473 -2016 -1049 -1640 -1545 -2850 -1563 -1828 -2297 -2499 -1937 -1693 -1546 -1559 -867 -1166 -1807 -1798 -1311 -2196 -1787 -1436 -1412 -1781 -1819 -1213 -1441 -1411 -1914 -1440 -1783 -1052 -1551 -2778 -1320 -2216 -1217 -1248 -1109 -1667 -1056 -1813 -1899 -2236 -900 -2124 -1114 -2545 -1320 -1875 -1326 -2649 -1423 -1484 -1191 -1705 -2270 -1786 -1793 -2460 -2776 -1235 -1496 -1838 -1665 -1945 -2213 -1097 -1412 -1464 -1562 -1139 -1419 -1818 -2616 -2387 -2058 -1732 -1759 -1689 -1445 -1162 -1459 -1397 -1050 -1773 -2195 -1282 -1442 -1251 -1046 -1543 -1291 -1708 -1510 -1903 -1328 -1370 -1738 -700 -1752 -1834 -2234 -2250 -2056 -1627 -1704 -1704 -1373 -1993 -1330 -2254 -2797 -1132 -1264 -1489 -1498 -1032 -1235 -1020 -1721 -1955 -1297 -1806 -1267 -2315 -2013 -1301 -2648 -1637 -1353 -1271 -2230 -1728 -2011 -1985 -1345 -1845 -2118 -1923 -1674 -1959 -1360 -1373 -1799 -1249 -2085 -1917 -2578 -1230 -2444 -1809 -1900 -2018 -1557 -2615 -1104 -2371 -1249 -1526 -1884 -1603 -1927 -1577 -1825 -1131 -1409 -2177 -2465 -1390 -919 -2148 -1451 -1194 -1371 -1211 -1000 -1039 -1847 -1716 -2338 -1684 -1568 -2518 -1395 -2282 -1437 -1773 -1555 -2033 -1392 -2084 -1110 -1905 -1879 -1753 -1597 -1793 -2468 -1314 -1375 -1897 -2358 -2207 -1358 -1512 -1979 -1695 -1882 -2044 -1805 -2432 -1195 -1222 -1481 -2648 -1415 -1100 -1850 -2361 -1202 -970 -1356 -1519 -1405 -1271 -1018 -1830 -1452 -1512 -1650 -1611 -2000 -1541 -1607 -1876 -1800 -1376 -1172 -2386 -1847 -2029 -1680 -1039 -1603 -1098 -1742 -1351 -1644 -1091 -1957 -2081 -1756 -2409 -1704 -1999 -1406 -1478 -1303 -1028 -1311 -1718 -1650 -1770 -1448 -1602 -961 -1438 -1454 -1978 -1628 -1691 -1822 -2236 -1594 -1563 -729 -1467 -1424 -2041 -1535 -1534 -2076 -1588 -2349 -1639 -1997 -2501 -1658 -1049 -1226 -2233 -1765 -1649 -1754 -2011 -1717 -1948 -1636 -1881 -2269 -1927 -2513 -1632 -918 -1535 -2199 -1897 -2383 -1128 -1841 -1414 -1649 -1840 -1340 -1686 -1911 -2161 -1589 -2692 -1482 -1803 -2332 -2084 -2518 -2117 -2003 -2232 -992 -881 -1916 -2070 -2021 -1264 -1891 -2599 -2153 -1628 -1378 -2192 -1700 -1254 -2765 -854 -2003 -2275 -710 -2539 -2070 -1667 -899 -1409 -2223 -1906 -1104 -1695 -1488 -2055 -2067 -1668 -1873 -2063 -2669 -1651 -2354 -1454 -1958 -1211 -1137 -2570 -2571 -1125 -1721 -1634 -2443 -2034 -1614 -2496 -2055 -2370 -2006 -1358 -1950 -1468 -1926 -2147 -1121 -1456 -1995 -1100 -1434 -1043 -1348 -2473 -1834 -1504 -1220 -1698 -1367 -1773 -1855 -1581 -2167 -2005 -1660 -1715 -1610 -1574 -1800 -2009 -1945 -1335 -1502 -1972 -1786 -1941 -1735 -2629 -719 -1321 -2128 -1376 -1009 -1490 -1458 -1209 -1957 -1885 -2276 -2445 -1073 -2005 -1357 -1013 -2294 -1345 -1273 -2415 -2756 -1241 -1519 -2791 -1245 -2032 -976 -2074 -1866 -2195 -1161 -1764 -2132 -1414 -1807 -2444 -1284 -1955 -2807 -2668 -1409 -1656 -1116 -1620 -1465 -2461 -1758 -1698 -1059 -2283 -1811 -1311 -1179 -1105 -2587 -1974 -1280 -1517 -1563 -2270 -1824 -780 -858 -1292 -2283 -1782 -2519 -1134 -1080 -1366 -1517 -2039 -2363 -1527 -3294 -2680 -2366 -2115 -1969 -1618 -1739 -1926 -879 -1899 -1606 -1750 -1319 -1940 -972 -2154 -1337 -2714 -1371 -926 -2352 -2154 -1313 -1556 -1530 -1758 -1539 -2381 -2035 -1494 -1852 -1351 -1910 -2076 -1243 -1863 -964 -1949 -1614 -2132 -1149 -1766 -1006 -1876 -2323 -1002 -1311 -993 -1271 -2224 -1265 -1596 -2021 -1287 -1918 -1603 -1522 -1555 -2079 -1120 -2325 -1801 -2561 -1196 -1882 -2410 -827 -1435 -1864 -1339 -2233 -1198 -933 -2694 -1872 -1769 -1898 -2826 -1282 -2042 -995 -2384 -1976 -1517 -1771 -2770 -1794 -1586 -3328 -1294 -2275 -3095 -1296 -1754 -1540 -2631 -1430 -1532 -1758 -2144 -1656 -2027 -1816 -1246 -2521 -2207 -2711 -1701 -2227 -1737 -1782 -2038 -1171 -850 -1339 -2105 -1098 -1533 -1724 -1612 -2524 -1230 -1965 -1268 -1809 -1387 -1833 -2090 -668 -1328 -2181 -2246 -1686 -1893 -1816 -3012 -1954 -1832 -1554 -858 -1777 -1558 -2504 -1185 -1739 -2118 -2035 -2018 -1722 -1307 -1976 -1715 -1367 -1724 -1514 -2141 -1788 -1650 -1538 -1430 -1969 -1889 -1296 -1344 -2440 -1873 -1431 -1825 -2475 -1060 -2098 -2360 -2099 -1606 -1569 -1441 -2353 -1523 -2279 -1643 -2326 -1486 -2027 -2299 -2409 -1243 -1284 -1821 -3073 -1226 -2303 -2381 -1306 -2016 -958 -1621 -1856 -2315 -1318 -2200 -2257 -2069 -2064 -2319 -1392 -2015 -1628 -2555 -1794 -1494 -1468 -915 -2464 -1678 -1624 -2351 -2948 -1365 -2125 -1868 -2135 -2475 -1949 -3041 -2121 -2027 -1826 -2913 -2088 -1103 -1625 -1407 -2778 -1551 -2103 -1791 -2332 -1874 -2270 -1142 -1720 -1232 -1448 -1451 -1568 -2019 -2448 -1546 -1533 -1831 -1473 -1458 -698 -2415 -2565 -2289 -1339 -1941 -1242 -2204 -2052 -1509 -2245 -2015 -1468 -1874 -1119 -2379 -1643 -1638 -1739 -1576 -952 -2017 -1034 -1348 -1386 -1494 -1416 -2626 -1392 -2067 -2468 -1066 -2400 -2589 -1025 -2201 -1113 -1867 -2530 -1782 -2386 -1655 -1813 -1126 -1063 -1258 -1633 -1642 -1987 -1954 -2004 -1566 -1646 -2033 -2705 -1588 -1856 -2183 -1829 -1740 -1422 -2650 -1346 -1651 -1549 -1644 -972 -900 -1301 -992 -2526 -1101 -2362 -1529 -1475 -1667 -2191 -1156 -2072 -2349 -2767 -1374 -1637 -1394 -2564 -1587 -2245 -1537 -942 -1477 -1895 -1324 -1834 -1476 -2819 -1363 -1949 -1868 -2166 -1728 -961 -1398 -2237 -1277 -1779 -1707 -2281 -1266 -2371 -1147 -1503 -2309 -1792 -1412 -1402 -1878 -2099 -2295 -1196 -1748 -1953 -1106 -1270 -1952 -1000 -2239 -1829 -1983 -1633 -1527 -1667 -3215 -1697 -1450 -1256 -2099 -2964 -1152 -796 -1807 -1992 -1419 -2373 -1620 -1464 -1343 -2101 -893 -1552 -1307 -1530 -1765 -2123 -1932 -1591 -3137 -2398 -1688 -1655 -1452 -1972 -1549 -1798 -1813 -2295 -2013 -1854 -1783 -1289 -2546 -2420 -1897 -1518 -2306 -1261 -1410 -812 -1592 -1571 -1683 -1448 -1790 -1892 -1409 -1989 -1525 -922 -1495 -955 -1830 -1394 -1308 -1707 -2627 -1237 -2090 -2088 -1549 -2541 -1782 -1188 -1450 -1414 -1491 -2752 -1745 -2777 -1719 -2491 -2450 -2012 -2607 -1775 -1633 -1488 -855 -2031 -1505 -1896 -1109 -1600 -2024 -2203 -1141 -1620 -2029 -1002 -1375 -1890 -2176 -1408 -2795 -1924 -1304 -1290 -1893 -1488 -1875 -2331 -2077 -1420 -1282 -2580 -1306 -1012 -1608 -1117 -1856 -1467 -1707 -1126 -3127 -1397 -1803 -1264 -1306 -1343 -1883 -1370 -3396 -2079 -1743 -1393 -1406 -1711 -1226 -1400 -1178 -2850 -2105 -1982 -2315 -1624 -2383 -1703 -1703 -1890 -1816 -1210 -1362 -1518 -2000 -1187 -2176 -2173 -2330 -1350 -1418 -1351 -1980 -1905 -2131 -1286 -1201 -1885 -1703 -1921 -2176 -694 -2263 -1761 -1953 -1850 -2136 -1642 -1769 -1449 -1583 -2337 -1830 -2365 -2102 -1469 -1857 -1097 -1596 -2126 -3143 -1063 -1845 -2076 -1731 -2021 -1764 -2029 -1816 -2747 -2784 -1316 -1107 -3280 -2471 -1695 -1918 -1036 -1284 -1715 -2070 -1815 -1465 -1597 -1413 -1627 -1329 -2293 -1275 -2006 -2945 -1815 -1974 -1510 -1698 -1516 -1833 -1944 -1291 -1458 -2034 -2130 -1115 -1654 -1586 -2315 -1521 -1637 -2175 -1534 -2453 -3230 -1128 -2068 -1316 -1118 -1543 -2008 -1361 -1764 -1133 -1742 -1262 -1907 -1987 -1098 -1764 -1030 -1475 -1914 -1789 -1082 -1388 -2869 -1466 -2199 -1699 -2358 -1707 -1436 -1645 -1554 -1422 -1807 -1293 -1211 -1660 -1493 -1806 -1663 -1358 -3249 -1712 -1239 -2207 -2329 -1815 -838 -2167 -1830 -1376 -1485 -1940 -1267 -2191 -1341 -1503 -1415 -1957 -1895 -1807 -1220 -1740 -959 -1904 -2385 -1617 -1572 -1931 -3166 -1814 -1353 -913 -1881 -2103 -1440 -899 -1130 -1768 -1695 -2356 -1334 -2576 -2002 -1173 -2047 -1384 -1394 -1359 -1303 -1813 -1936 -1443 -1876 -2185 -1655 -1939 -2142 -1492 -2287 -1884 -1404 -1307 -2065 -1603 -1672 -1729 -1979 -1706 -4104 -1601 -1817 -1503 -1502 -1568 -1673 -2249 -2046 -1532 -1510 -1515 -1356 -2478 -1616 -1348 -1906 -948 -2749 -2197 -1714 -1803 -2093 -2019 -1303 -1996 -1617 -2475 -1489 -1612 -1121 -1753 -1859 -1501 -1419 -1699 -2106 -1236 -2150 -2986 -1210 -1983 -1091 -1219 -1629 -1751 -2566 -957 -1203 -1716 -1269 -2150 -2089 -1416 -1763 -1629 -1573 -3284 -1522 -1314 -1477 -2125 -1962 -1206 -1600 -3231 -954 -1048 -1031 -1333 -1866 -1693 -2476 -1455 -1222 -1187 -1468 -1128 -2841 -1641 -1447 -2288 -2513 -2853 -1220 -2199 -2092 -1447 -887 -1941 -1878 -1588 -1878 -1408 -1472 -1526 -1472 -2125 -2083 -1468 -1944 -2156 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k3/trained_ddqn/best.pt deleted file mode 100644 index c5b0c252c35f857c82878c998bc1954a472c147b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13669 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 YL34ok7T8}G0q=g)ZmBw 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 M8R6?!{oi%}7kMQgegFUf diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/dqn.txt deleted file mode 100644 index cdfa007e3..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1141 -1390 -854 -1159 -587 -1290 -884 -878 -1285 -713 -1194 -917 -672 -527 -1017 -856 -795 -1008 -1279 -991 -979 -828 -810 -669 -1281 -1355 -1102 -1321 -1042 -1303 -957 -1056 -1101 -1475 -1023 -1058 -1343 -826 -1062 -1034 -713 -1488 -970 -951 -1250 -1396 -1485 -696 -752 -446 -891 -953 -1618 -618 -1402 -1133 -1428 -868 -1102 -1446 -651 -1046 -1079 -877 -995 -1082 -1532 -1333 -1065 -1186 -926 -1399 -954 -1212 -1119 -813 -1302 -479 -1358 -1214 -555 -1376 -939 -1152 -1155 -925 -1253 -1310 -1525 -1344 -954 -929 -885 -1262 -839 -840 -1298 -987 -992 -994 -1179 -852 -1231 -1156 -1140 -820 -948 -942 -549 -793 -989 -630 -1279 -828 -926 -858 -1278 -1106 -1140 -1086 -1178 -1087 -1239 -1255 -929 -1411 -802 -1311 -1378 -590 -770 -1181 -1115 -778 -1060 -1065 -1336 -790 -1095 -1092 -908 -757 -813 -961 -878 -933 -1127 -1212 -606 -690 -1176 -634 -1123 -972 -1422 -978 -888 -864 -1221 -1232 -962 -1054 -931 -906 -1150 -1421 -929 -1046 -1380 -827 -927 -1220 -1218 -1113 -1023 -678 -1083 -923 -1244 -912 -920 -1074 -1012 -880 -878 -965 -990 -594 -1080 -1013 -1640 -1161 -708 -508 -1205 -1006 -504 -935 -1032 -854 -785 -1010 -1065 -465 -927 -1397 -1187 -942 -584 -1155 -825 -924 -744 -1127 -895 -1031 -701 -709 -1034 -1018 -1402 -588 -722 -722 -1015 -1246 -637 -1294 -1242 -997 -1193 -427 -1041 -516 -1129 -951 -1174 -881 -1181 -1069 -828 -782 -1010 -783 -1033 -1425 -1008 -631 -1101 -1732 -1530 -798 -1462 -1113 -1431 -1431 -795 -1139 -1285 -1106 -984 -1272 -990 -814 -941 -650 -1023 -982 -609 -1151 -1282 -1090 -1103 -760 -1302 -1146 -883 -1787 -859 -966 -1235 -1544 -1084 -1563 -1094 -1541 -1501 -1147 -1343 -791 -1030 -1037 -942 -1103 -1429 -891 -1025 -1334 -1382 -1107 -927 -1288 -896 -1230 -768 -1138 -1158 -950 -905 -734 -1497 -1214 -983 -583 -1159 -786 -326 -1375 -1272 -845 -835 -984 -686 -1246 -1013 -1175 -1115 -844 -619 -906 -1140 -1213 -854 -1027 -1260 -824 -958 -1060 -901 -1045 -722 -993 -1094 -885 -1220 -1102 -1180 -1031 -903 -748 -854 -920 -1109 -1056 -949 -1163 -1587 -827 -726 -876 -1219 -1123 -1245 -587 -1146 -1187 -714 -1162 -1285 -618 -941 -881 -735 -1353 -1171 -1224 -1075 -804 -640 -1010 -869 -1097 -823 -990 -775 -943 -1400 -1244 -615 -1010 -1454 -760 -927 -624 -863 -647 -939 -1135 -1228 -833 -832 -816 -1182 -1117 -990 -899 -1111 -1090 -853 -1370 -657 -1244 -999 -1081 -1291 -1368 -663 -1266 -1363 -910 -1413 -577 -1105 -1054 -1044 -1267 -1030 -817 -657 -935 -1233 -736 -717 -971 -1038 -1233 -1406 -1093 -987 -1025 -1011 -1014 -1218 -1056 -832 -1137 -800 -897 -1105 -1242 -1272 -1066 -869 -1421 -1286 -1133 -824 -1041 -1166 -583 -673 -841 -948 -1124 -1092 -1045 -676 -1137 -891 -1065 -1052 -1088 -1430 -1266 -1326 -513 -850 -1710 -862 -858 -1042 -1011 -1274 -1003 -1432 -1348 -1098 -1024 -1117 -1054 -814 -863 -1108 -968 -840 -1407 -799 -1348 -945 -1064 -984 -1014 -1145 -1226 -1588 -1017 -827 -1194 -949 -1158 -1296 -923 -1041 -1196 -1057 -958 -1437 -806 -1045 -956 -1208 -1429 -1035 -913 -707 -786 -1066 -637 -1105 -1092 -1203 -1417 -954 -1119 -1062 -1550 -1489 -862 -1296 -713 -1117 -808 -703 -1063 -1391 -1426 -794 -1177 -1329 -854 -945 -552 -1050 -633 -813 -1129 -1456 -854 -1347 -763 -668 -969 -1504 -812 -1328 -1368 -1259 -1041 -995 -1030 -1325 -1185 -907 -1320 -1113 -1047 -1175 -890 -1312 -1107 -435 -773 -712 -1142 -1095 -726 -1029 -913 -1082 -472 -835 -874 -1147 -896 -960 -1360 -868 -972 -868 -1101 -1195 -978 -1345 -867 -1213 -611 -712 -921 -882 -820 -1414 -822 -515 -1059 -781 -1103 -1633 -926 -884 -669 -751 -787 -1152 -729 -1065 -1485 -1166 -865 -837 -962 -1365 -933 -1019 -1350 -1023 -1050 -806 -963 -944 -755 -1036 -1040 -1182 -1699 -828 -1051 -783 -1067 -2085 -493 -1371 -707 -850 -927 -1080 -642 -711 -1048 -1045 -794 -594 -799 -1282 -820 -1387 -956 -683 -1517 -1153 -563 -993 -1407 -672 -987 -941 -963 -1108 -957 -730 -1145 -681 -801 -885 -700 -958 -858 -898 -1152 -877 -1244 -1001 -1224 -822 -891 -580 -1096 -1040 -699 -631 -699 -692 -1020 -1312 -1036 -944 -832 -1105 -739 -930 -1358 -1043 -704 -939 -566 -729 -1272 -997 -938 -1059 -1351 -1391 -976 -1157 -567 -1555 -1426 -698 -607 -1088 -1022 -448 -649 -1102 -1130 -967 -881 -900 -1088 -901 -1625 -633 -696 -1462 -1402 -1290 -562 -782 -750 -993 -712 -938 -697 -509 -961 -1088 -655 -838 -1021 -1126 -876 -809 -859 -496 -1094 -564 -849 -802 -1052 -1141 -1032 -1336 -1029 -1255 -902 -738 -943 -1394 -896 -739 -792 -763 -1085 -1528 -1396 -1110 -1177 -1315 -1128 -649 -1308 -1181 -793 -657 -658 -1548 -1400 -962 -881 -742 -619 -641 -1115 -1180 -1355 -802 -647 -1039 -1285 -940 -1057 -826 -894 -1086 -1189 -788 -661 -713 -890 -1003 -858 -912 -986 -1227 -1264 -745 -1216 -1132 -788 -1090 -804 -855 -866 -802 -1075 -739 -669 -681 -913 -627 -745 -857 -950 -942 -835 -689 -1089 -1442 -758 -919 -886 -1358 -1004 -1572 -1106 -686 -802 -771 -981 -781 -1201 -1208 -1165 -1045 -931 -564 -888 -754 -880 -1120 -867 -500 -1007 -937 -1061 -1312 -1328 -961 -1147 -858 -863 -779 -901 -1307 -1399 -1199 -791 -822 -645 -1387 -1096 -623 -996 -932 -1357 -755 -738 -1007 -844 -704 -765 -905 -715 -986 -999 -1533 -784 -1251 -932 -591 -1163 -839 -734 -1156 -1136 -1090 -887 -383 -932 -1130 -1056 -710 -994 -1152 -1207 -1039 -1267 -634 -1368 -1166 -860 -1036 -966 -1204 -921 -1355 -514 -819 -906 -1217 -718 -1232 -821 -890 -1324 -968 -1179 -400 -1044 -1219 -948 -1262 -925 -1342 -946 -834 -1352 -1439 -1198 -751 -1562 -850 -1124 -1201 -1101 -1837 -1070 -717 -888 -748 -1186 -1200 -467 -1237 -590 -1140 -1259 -860 -1082 -916 -590 -1041 -908 -1191 -334 -750 -921 -1095 -940 -1049 -752 -842 -908 -901 -718 -1196 -674 -620 -855 -800 -933 -1155 -1008 -1132 -780 -1681 -1217 -822 -933 -711 -1054 -829 -833 -661 -1382 -587 -902 -666 -789 -540 -840 -1105 -1113 -1175 -945 -1156 -640 -919 -747 -1437 -1121 -976 -1080 -733 -1030 -717 -1394 -934 -724 -804 -974 -1153 -800 -1020 -1375 -621 -808 -1196 -1192 -806 -955 -1021 -1401 -1251 -1077 -1004 -748 -962 -1051 -1023 -1332 -885 -1094 -1132 -919 -1153 -1095 -862 -1364 -1061 -1043 -1257 -1060 -805 -942 -641 -889 -974 -1437 -1173 -1586 -914 -1173 -793 -1177 -1081 -864 -1088 -1158 -1277 -609 -1316 -894 -876 -1051 -1231 -1061 -1188 -1468 -503 -661 -927 -1407 -865 -818 -890 -741 -795 -1490 -695 -1107 -633 -1262 -875 -1270 -1102 -1229 -993 -1320 -651 -854 -883 -652 -1192 -1210 -659 -721 -638 -1207 -1202 -1195 -868 -1143 -1144 -481 -1047 -558 -802 -1200 -833 -946 -691 -888 -923 -512 -961 -976 -810 -802 -833 -1102 -761 -928 -906 -1443 -744 -916 -1219 -541 -879 -1116 -553 -782 -1085 -1269 -1080 -1519 -683 -1461 -948 -837 -1432 -1173 -1409 -698 -1557 -1052 -868 -828 -486 -923 -1318 -1236 -949 -1149 -1279 -783 -1453 -783 -758 -1277 -1025 -359 -1128 -1019 -1396 -1575 -970 -746 -1494 -912 -627 -882 -1005 -684 -1250 -1102 -860 -854 -861 -484 -994 -1484 -1046 -898 -697 -1275 -1041 -1385 -1232 -1324 -1028 -994 -1103 -989 -1141 -873 -1202 -1436 -797 -1025 -752 -1414 -936 -956 -1476 -1378 -1104 -1367 -1288 -1057 -1022 -973 -1259 -628 -972 -914 -982 -966 -960 -1177 -521 -800 -811 -1003 -893 -870 -661 -1671 -1163 -1452 -880 -1153 -1235 -1269 -1061 -693 -965 -913 -1120 -735 -1186 -1302 -1568 -1337 -931 -1014 -1303 -585 -821 -542 -712 -883 -1405 -1144 -1057 -989 -725 -1322 -884 -857 -1465 -397 -1302 -1106 -642 -1155 -784 -824 -986 -1848 -1151 -817 -1317 -915 -1039 -1051 -1015 -1084 -943 -488 -1041 -881 -1131 -847 -853 -1161 -898 -1031 -1598 -1244 -1156 -806 -921 -1073 -1397 -1135 -634 -1203 -982 -834 -1104 -733 -712 -1466 -721 -823 -981 -1018 -1023 -1104 -1153 -1338 -1374 -1322 -1106 -812 -549 -548 -1012 -1267 -1004 -815 -905 -1177 -1020 -1384 -893 -889 -1158 -1193 -790 -1195 -524 -1079 -722 -1077 -1235 -1183 -767 -1015 -641 -866 -993 -1082 -997 -1437 -884 -1398 -616 -1652 -999 -1356 -780 -926 -593 -730 -712 -559 -1048 -1022 -847 -765 -838 -782 -715 -450 -953 -1196 -895 -1232 -1216 -1342 -1060 -889 -1369 -894 -551 -1016 -1402 -923 -1091 -1710 -863 -1345 -1159 -894 -641 -1416 -948 -947 -828 -1017 -1123 -1189 -1059 -1248 -834 -956 -749 -1112 -1309 -772 -1201 -1370 -1161 -1035 -932 -407 -1136 -878 -1065 -1266 -1088 -1131 -592 -1025 -1055 -904 -877 -1163 -1091 -928 -975 -1040 -1479 -1431 -1190 -865 -610 -650 -918 -942 -744 -1388 -1559 -601 -1083 -1134 -1149 -1114 -1276 -1018 -714 -1149 -971 -985 -816 -1089 -1027 -967 -1124 -936 -834 -1016 -721 -985 -895 -1023 -1346 -1104 -766 -1373 -1126 -612 -1157 -815 -845 -1178 -1163 -679 -1565 -1027 -1084 -971 -1452 -1112 -1381 -1467 -682 -1455 -588 -1197 -1225 -675 -1039 -928 -1079 -1002 -1604 -1012 -1251 -1006 -1749 -959 -1132 -1475 -1166 -951 -1108 -887 -1154 -1181 -968 -900 -923 -1535 -756 -1157 -1265 -870 -813 -1289 -826 -450 -954 -933 -1088 -1275 -891 -1157 -564 -1201 -889 -967 -1600 -936 -1033 -1151 -1132 -793 -1179 -1223 -1248 -931 -1214 -949 -1245 -1265 -735 -720 -1422 -679 -969 -1017 -1189 -1048 -1894 -1009 -900 -659 -793 -1168 -925 -1292 -1470 -834 -1115 -879 -1423 -868 -1017 -735 -1089 -1000 -974 -1215 -1181 -890 -747 -983 -1011 -757 -766 -1107 -1246 -979 -1313 -862 -1243 -1947 -848 -1287 -740 -1121 -919 -1190 -1043 -551 -1184 -1197 -851 -1114 -975 -828 -804 -1698 -1744 -1116 -736 -1251 -858 -720 -995 -1077 -1678 -774 -651 -1312 -802 -1473 -1126 -709 -1389 -864 -1058 -1148 -1976 -854 -1297 -1190 -1325 -1411 -752 -1278 -898 -1440 -1081 -685 -829 -820 -931 -1011 -1208 -497 -446 -850 -851 -1465 -590 -1157 -1437 -785 -1504 -1141 -1141 -1285 -1248 -1150 -1045 -981 -903 -1287 -1084 -855 -992 -1406 -1543 -429 -799 -1022 -1206 -906 -1186 -1126 -901 -1176 -810 -631 -511 -632 -845 -644 -1226 -997 -913 -814 -666 -1110 -960 -670 -909 -651 -958 -1126 -1071 -1038 -834 -782 -1508 -1214 -1133 -1379 -876 -1003 -1137 -1082 -791 -1446 -685 -1587 -676 -1513 -927 -1185 -1669 -656 -641 -966 -874 -678 -1425 -972 -1211 -1723 -816 -1177 -1583 -1037 -864 -584 -1170 -1412 -1094 -730 -660 -750 -1277 -788 -1381 -983 -645 -1275 -844 -1205 -968 -1036 -1094 -1045 -1039 -728 -1007 -1002 -948 -655 -1236 -841 -813 -839 -1486 -1364 -1005 -1345 -1029 -1056 -1226 -1162 -790 -1289 -943 -1024 -1081 -1500 -807 -954 -1037 -436 -549 -883 -1160 -1219 -1269 -1433 -701 -1109 -782 -1248 -1191 -753 -1094 -1244 -759 -1049 -837 -1065 -926 -1139 -821 -1037 -1193 -972 -1004 -903 -934 -1219 -895 -823 -1250 -957 -1005 -1176 -1605 -684 -707 -1647 -825 -1293 -672 -1174 -1266 -1143 -662 -750 -626 -1005 -905 -1200 -468 -1270 -1289 -1105 -537 -841 -1132 -1175 -1183 -1329 -1369 -1372 -1100 -1401 -749 -888 -860 -1494 -854 -1189 -1369 -638 -1023 -989 -860 -565 -683 -616 -1453 -1002 -1039 -1016 -751 -983 -899 -1268 -572 -819 -1016 -1033 -1194 -776 -1174 -459 -1298 -1257 -872 -1117 -638 -1134 -1352 -1363 -1250 -1007 -902 -811 -769 -867 -820 -1068 -1096 -1269 -859 -1340 -1121 -1200 -895 -1526 -938 -694 -830 -1514 -872 -513 -1055 -1115 -917 -724 -941 -786 -791 -985 -1020 -1072 -1169 -950 -718 -1127 -944 -1148 -971 -1042 -932 -1003 -967 -882 -1221 -676 -1323 -1522 -1172 -814 -708 -992 -948 -1574 -1241 -926 -813 -783 -1008 -1056 -844 -868 -747 -960 -622 -876 -1254 -571 -1009 -1105 -1232 -896 -992 -1058 -887 -1528 -659 -1140 -1228 -1467 -633 -1089 -703 -1240 -1104 -1288 -1137 -1455 -1151 -1459 -1602 -1454 -1191 -1489 -870 -1192 -1375 -865 -669 -1109 -1134 -906 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/optimal.txt deleted file mode 100644 index 6b83f6956..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -596 -799 -1391 -628 -1328 -694 -753 -1187 -943 -1205 -557 -1040 -646 -889 -760 -657 -804 -1034 -951 -1256 -995 -1099 -1037 -818 -1569 -661 -935 -826 -645 -1671 -949 -1135 -1032 -1220 -567 -812 -592 -687 -700 -925 -1128 -946 -1402 -1214 -944 -966 -668 -789 -607 -914 -903 -1130 -1167 -954 -898 -1608 -700 -746 -829 -773 -964 -839 -1107 -641 -741 -1226 -892 -1029 -1321 -948 -727 -610 -795 -1172 -727 -1159 -1201 -760 -898 -821 -1111 -1303 -1273 -1347 -827 -1086 -851 -819 -1062 -705 -1045 -1624 -793 -984 -936 -811 -645 -871 -891 -1172 -567 -764 -1749 -1206 -770 -584 -789 -978 -1004 -857 -1232 -523 -1232 -877 -957 -1067 -1122 -1076 -946 -1449 -1199 -1078 -748 -1662 -984 -1325 -909 -1031 -1048 -365 -962 -760 -839 -911 -1118 -1049 -973 -740 -1090 -941 -1028 -1323 -974 -831 -949 -957 -1132 -1032 -951 -1577 -1260 -731 -1032 -1077 -1102 -1194 -1294 -1574 -610 -879 -1182 -1260 -1246 -896 -1132 -1270 -786 -1162 -1189 -1160 -866 -659 -1548 -1032 -813 -728 -1506 -1276 -955 -851 -778 -584 -1115 -1077 -815 -846 -608 -721 -1270 -1101 -1242 -1061 -720 -1043 -1346 -1026 -612 -1022 -1106 -960 -1127 -1252 -1455 -485 -831 -753 -1169 -957 -973 -1122 -750 -730 -1181 -811 -855 -906 -711 -1051 -920 -1526 -662 -547 -676 -1325 -848 -1108 -1057 -1038 -1586 -558 -1004 -740 -1237 -1007 -825 -702 -916 -1238 -759 -851 -1124 -1158 -920 -559 -922 -697 -784 -1398 -1140 -700 -948 -587 -860 -1314 -937 -786 -1580 -795 -1516 -1013 -958 -1022 -847 -1223 -975 -1981 -667 -818 -959 -960 -942 -1012 -750 -908 -858 -1262 -746 -1064 -1176 -1156 -1200 -744 -862 -550 -1189 -925 -1052 -1525 -859 -1217 -1230 -977 -550 -1144 -748 -876 -1000 -1138 -967 -963 -539 -916 -754 -967 -1067 -893 -834 -1142 -1276 -837 -1040 -1365 -943 -939 -1159 -1125 -1355 -1069 -1276 -1394 -1020 -870 -935 -459 -946 -811 -935 -1234 -1017 -901 -637 -930 -870 -1233 -609 -757 -997 -843 -1156 -854 -704 -1085 -818 -1088 -1187 -643 -845 -634 -463 -1156 -1205 -746 -1117 -922 -821 -758 -1108 -1377 -841 -1120 -845 -1346 -1407 -634 -774 -1140 -814 -882 -1245 -1065 -1027 -766 -1399 -1183 -1014 -1053 -878 -1437 -1253 -859 -612 -794 -1144 -782 -936 -1047 -881 -721 -1014 -844 -1032 -1397 -879 -1148 -649 -1250 -785 -730 -987 -1163 -1238 -637 -1149 -953 -738 -685 -998 -651 -1385 -801 -925 -1322 -1378 -1033 -1039 -1089 -999 -1114 -1433 -1499 -1113 -1066 -1332 -846 -780 -675 -1419 -1469 -521 -750 -1204 -618 -920 -1152 -1099 -887 -1079 -1062 -1239 -1277 -1130 -1247 -1409 -1473 -1245 -680 -1171 -746 -1021 -837 -932 -891 -1463 -1246 -755 -941 -1197 -598 -1014 -1140 -886 -566 -1231 -598 -1294 -767 -997 -1092 -1134 -754 -1237 -1032 -917 -1105 -678 -774 -939 -1222 -1122 -1388 -1153 -1297 -1151 -1196 -1170 -926 -1038 -1073 -880 -737 -1339 -1379 -993 -934 -750 -1439 -704 -743 -1016 -617 -1108 -750 -858 -1361 -1242 -1079 -1060 -749 -1029 -1375 -717 -650 -998 -619 -735 -1130 -741 -702 -1236 -968 -1236 -1305 -1060 -1652 -634 -1140 -1076 -1306 -907 -1192 -887 -1242 -852 -582 -1072 -986 -1144 -1102 -1431 -579 -943 -1074 -973 -1325 -961 -1114 -1325 -846 -1224 -1004 -925 -1147 -1132 -1164 -614 -950 -740 -1020 -809 -1215 -759 -1373 -1214 -924 -1203 -1403 -1186 -1161 -973 -1086 -1020 -1007 -1062 -1375 -957 -1018 -803 -744 -1027 -1037 -1623 -768 -856 -1053 -1211 -940 -1091 -1032 -1201 -883 -701 -914 -976 -844 -916 -742 -710 -1199 -1496 -690 -688 -901 -1132 -787 -1441 -1217 -845 -1070 -764 -1290 -595 -700 -1327 -739 -409 -841 -1032 -826 -1118 -818 -665 -847 -1192 -1447 -1272 -1143 -756 -1246 -1016 -578 -900 -830 -966 -615 -1116 -620 -1356 -1177 -1135 -1088 -1394 -900 -1310 -840 -982 -890 -708 -918 -976 -1278 -605 -1060 -1040 -1637 -864 -930 -867 -1699 -955 -1312 -452 -1275 -1294 -899 -1232 -1003 -925 -1179 -1120 -1571 -740 -1251 -1146 -721 -1067 -927 -1034 -811 -1208 -887 -765 -1424 -1007 -1126 -873 -708 -975 -1354 -706 -875 -1045 -748 -963 -719 -850 -1022 -735 -1056 -1195 -1102 -951 -544 -779 -856 -923 -527 -930 -1006 -807 -1425 -1238 -526 -716 -1014 -620 -796 -498 -722 -964 -762 -842 -591 -1272 -1062 -1813 -1032 -865 -915 -733 -1028 -1087 -541 -1544 -597 -1265 -957 -979 -1776 -589 -925 -960 -661 -1119 -998 -1341 -957 -706 -710 -999 -1598 -705 -970 -689 -733 -766 -725 -492 -831 -1166 -783 -691 -818 -1102 -952 -937 -1004 -757 -981 -897 -1145 -1283 -542 -720 -1489 -558 -935 -765 -1460 -1600 -1203 -1040 -1132 -688 -1151 -873 -833 -1039 -617 -869 -1338 -1528 -629 -523 -1054 -1189 -1220 -941 -642 -1056 -962 -593 -882 -881 -868 -986 -1121 -1271 -809 -499 -875 -1126 -866 -848 -1483 -869 -940 -750 -567 -860 -738 -1064 -760 -982 -723 -1040 -1056 -464 -1148 -650 -1342 -613 -1486 -1242 -983 -973 -822 -1463 -514 -764 -1221 -532 -545 -1062 -669 -923 -1106 -1015 -963 -737 -449 -909 -1240 -1396 -1271 -1086 -763 -903 -970 -502 -1444 -385 -699 -867 -897 -687 -790 -970 -840 -927 -1034 -904 -1135 -896 -873 -566 -1144 -970 -1063 -612 -868 -967 -1486 -812 -831 -988 -1081 -1056 -688 -857 -600 -1075 -802 -1023 -970 -1129 -802 -762 -896 -935 -1020 -1161 -1245 -628 -837 -1157 -601 -1406 -780 -804 -1137 -610 -1011 -1126 -544 -763 -1054 -1158 -859 -1181 -1731 -1145 -772 -758 -868 -729 -1144 -1108 -1161 -627 -1396 -1302 -1148 -1233 -989 -1057 -812 -654 -726 -755 -516 -1472 -750 -911 -1591 -1029 -808 -541 -1187 -914 -1154 -922 -924 -657 -1170 -918 -702 -1029 -1705 -1195 -807 -747 -995 -1177 -1050 -973 -536 -1412 -1245 -929 -1421 -1117 -1508 -727 -564 -1093 -944 -968 -1193 -1832 -1231 -1061 -966 -776 -1163 -943 -1354 -1146 -1163 -1032 -742 -1679 -773 -960 -891 -434 -1136 -894 -979 -982 -715 -570 -765 -1433 -1338 -1030 -820 -1115 -777 -744 -1392 -1011 -1210 -944 -1094 -723 -1204 -673 -541 -1263 -1118 -842 -1043 -825 -1003 -1028 -789 -1174 -617 -969 -979 -1603 -955 -833 -989 -808 -958 -488 -993 -698 -1118 -1253 -846 -1394 -1312 -628 -638 -1557 -842 -895 -720 -677 -1187 -800 -1157 -1284 -989 -1232 -1172 -782 -1151 -1068 -1062 -706 -1332 -1584 -421 -865 -1434 -748 -1168 -683 -1032 -978 -662 -1010 -1080 -1028 -874 -878 -1163 -978 -449 -1039 -1072 -1156 -1256 -1048 -847 -1338 -1084 -1032 -858 -660 -933 -1206 -1415 -975 -1232 -1144 -1245 -836 -867 -929 -1964 -1136 -682 -972 -1068 -636 -1165 -972 -1265 -1164 -995 -650 -1768 -549 -1107 -954 -515 -744 -1260 -989 -1284 -1047 -1287 -1450 -981 -658 -909 -805 -1319 -992 -784 -1690 -1221 -1106 -852 -743 -1037 -870 -1190 -1216 -1194 -1345 -914 -1068 -1168 -958 -1145 -872 -898 -1207 -842 -1036 -704 -869 -1509 -1031 -1270 -1038 -1555 -1276 -853 -1224 -861 -875 -1449 -529 -1334 -964 -1441 -870 -1037 -1081 -1298 -890 -1626 -1134 -667 -614 -815 -656 -766 -784 -700 -1289 -948 -724 -1077 -917 -894 -1033 -860 -796 -950 -1056 -1092 -1322 -1143 -944 -939 -978 -971 -1336 -923 -1057 -901 -770 -1274 -792 -1427 -683 -1488 -912 -1250 -1070 -1447 -971 -1002 -812 -916 -1157 -600 -1419 -707 -819 -1417 -963 -1238 -736 -783 -1353 -1262 -710 -1186 -857 -1341 -1019 -660 -782 -1086 -1209 -1092 -1409 -695 -1005 -1013 -730 -986 -556 -800 -682 -1182 -820 -607 -1422 -988 -864 -526 -845 -746 -715 -1056 -948 -982 -1132 -949 -599 -1365 -1035 -1441 -692 -1156 -964 -917 -628 -558 -1199 -935 -636 -1010 -872 -1276 -566 -885 -1163 -1204 -946 -621 -990 -1138 -1008 -1352 -1224 -896 -615 -1336 -946 -978 -1037 -1165 -1004 -775 -1019 -703 -1100 -672 -1410 -856 -1140 -664 -458 -491 -665 -900 -1074 -1158 -933 -1010 -1153 -814 -970 -710 -1331 -1373 -872 -715 -700 -1265 -1182 -1640 -853 -424 -697 -980 -1000 -786 -680 -988 -1179 -533 -649 -1071 -689 -1497 -785 -1366 -1298 -735 -1249 -701 -1072 -773 -789 -1112 -1180 -780 -873 -1181 -641 -913 -737 -1020 -485 -947 -769 -1052 -957 -664 -573 -956 -930 -948 -889 -1168 -788 -805 -878 -1060 -864 -829 -565 -1140 -985 -1130 -506 -833 -633 -827 -690 -862 -962 -882 -1089 -1277 -1033 -1173 -587 -1131 -945 -1186 -560 -1203 -942 -1266 -846 -999 -1517 -963 -775 -1166 -1209 -847 -1175 -926 -1281 -820 -660 -729 -507 -1241 -1280 -1289 -1099 -1108 -1612 -930 -1290 -1308 -1029 -1090 -1363 -854 -727 -1414 -1093 -891 -584 -745 -916 -1114 -1129 -587 -952 -782 -831 -1056 -880 -1114 -826 -1046 -757 -913 -1222 -1016 -1065 -420 -1199 -617 -1081 -1118 -1023 -1035 -1152 -1081 -1197 -588 -1163 -1128 -1390 -976 -907 -890 -1198 -1357 -965 -602 -774 -1170 -866 -600 -1005 -780 -1095 -1314 -805 -945 -1114 -721 -608 -1481 -1157 -759 -1130 -1541 -1029 -814 -1163 -883 -1057 -1135 -1046 -856 -1333 -746 -920 -1197 -912 -1116 -775 -540 -775 -933 -1063 -801 -1174 -1028 -1170 -994 -933 -963 -543 -907 -919 -891 -642 -857 -1006 -802 -888 -1170 -925 -756 -1647 -763 -944 -395 -1465 -716 -961 -1085 -815 -1120 -1251 -1011 -1269 -760 -1368 -1314 -1094 -958 -897 -901 -1140 -727 -1090 -622 -1377 -1433 -987 -1293 -1287 -820 -920 -1351 -1119 -1063 -1002 -948 -989 -917 -914 -1144 -879 -851 -1231 -1119 -843 -986 -688 -799 -908 -1019 -793 -848 -1246 -586 -1008 -932 -1305 -1431 -1041 -1485 -868 -877 -762 -885 -613 -690 -769 -1230 -1136 -941 -1109 -1193 -789 -1222 -902 -1354 -1077 -1033 -842 -1097 -604 -834 -677 -883 -941 -1147 -1246 -895 -803 -919 -1220 -826 -1469 -883 -1415 -992 -869 -1126 -926 -461 -1979 -556 -762 -735 -1246 -1034 -1085 -1274 -1419 -614 -644 -1480 -876 -977 -1839 -903 -625 -724 -892 -951 -835 -840 -852 -631 -960 -1010 -990 -955 -1429 -793 -350 -943 -748 -1165 -1314 -800 -834 -1190 -903 -640 -996 -1160 -979 -1194 -845 -939 -1681 -743 -1203 -1041 -1061 -1241 -999 -982 -781 -547 -1264 -731 -983 -907 -715 -693 -1092 -1154 -759 -1194 -561 -1083 -1033 -927 -1430 -1269 -537 -988 -1109 -997 -814 -913 -988 -985 -827 -756 -743 -1215 -571 -801 -1036 -1142 -1288 -1541 -1611 -931 -1005 -539 -628 -1043 -906 -1028 -973 -1194 -764 -1033 -779 -704 -985 -1344 -987 -799 -677 -429 -1223 -1036 -1043 -731 -692 -1276 -554 -1276 -927 -608 -850 -715 -973 -886 -1066 -900 -720 -1005 -968 -1575 -1301 -1014 -752 -883 -942 -1016 -893 -1080 -693 -776 -955 -359 -1203 -947 -1460 -1053 -864 -563 -898 -1353 -824 -732 -1297 -847 -641 -939 -727 -964 -755 -967 -1116 -942 -608 -1576 -877 -559 -1113 -968 -1014 -934 -1260 -824 -1412 -1045 -771 -1543 -1528 -977 -1026 -884 -1779 -1146 -917 -974 -932 -1002 -840 -1088 -1431 -809 -1258 -825 -837 -1260 -1078 -852 -1166 -649 -1158 -1046 -1347 -922 -1096 -1047 -1100 -835 -647 -1013 -753 -1079 -406 -1138 -836 -934 -833 -1033 -853 -712 -1151 -996 -1054 -517 -1204 -1388 -1004 -910 -1020 -962 -1156 -718 -1090 -758 -731 -893 -621 -1044 -953 -1149 -1636 -1017 -1099 -926 -1061 -806 -1027 -842 -1218 -1051 -438 -920 -826 -911 -1039 -461 -1186 -864 -1172 -752 -1096 -1167 -955 -1463 -1208 -1058 -1473 -787 -975 -777 -961 -884 -568 -1013 -1146 -965 -624 -562 -663 -1505 -736 -1160 -1392 -1096 -365 -1401 -1564 -612 -1402 -741 -756 -1145 -1080 -795 -1147 -952 -1113 -1354 -1322 -871 -965 -470 -572 -1329 -946 -927 -1417 -880 -540 -1015 -890 -1074 -1334 -1139 -793 -733 -915 -1255 -856 -575 -662 -952 -1118 -622 -1169 -1269 -890 -867 -962 -1162 -1216 -1132 -992 -1584 -1243 -1046 -802 -1042 -721 -1311 -971 -1081 -1449 -1488 -1246 -977 -979 -715 -1053 -929 -913 -1740 -809 -739 -828 -1653 -942 -1127 -817 -1373 -1658 -1026 -781 -891 -815 -1190 -805 -1102 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/random.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/random.txt deleted file mode 100644 index 95985c256..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -2519 -2181 -3128 -2636 -2062 -1778 -2254 -2343 -2415 -1938 -2033 -1671 -1570 -1954 -2063 -2813 -1551 -2220 -2381 -1819 -2985 -2635 -1637 -1710 -1899 -1338 -2404 -2044 -2177 -3272 -1636 -1001 -1722 -3043 -1877 -3002 -2166 -1422 -2731 -2317 -3041 -1634 -3038 -2225 -1996 -2146 -2984 -2243 -1765 -2143 -1371 -1689 -2082 -1446 -2307 -784 -2430 -1042 -3458 -1920 -2968 -1450 -2810 -2221 -1820 -2906 -1938 -1759 -2851 -2294 -1912 -1949 -2402 -2799 -1502 -2391 -2587 -1577 -2984 -1188 -2418 -2538 -2386 -1794 -1330 -1649 -2289 -1619 -2151 -1068 -1673 -2674 -2969 -2619 -2384 -2004 -1484 -2149 -1783 -2965 -3017 -2207 -3702 -2147 -2238 -1864 -1516 -1332 -2299 -3098 -2397 -2675 -1816 -2771 -1398 -1935 -2518 -2122 -1924 -2713 -818 -1601 -2220 -2883 -1988 -1947 -1979 -2024 -1956 -1418 -838 -2030 -1955 -2005 -1942 -3220 -1830 -1936 -2984 -1080 -2089 -2607 -2402 -2934 -2125 -1604 -2449 -2576 -1871 -1301 -2362 -1986 -1555 -2111 -2592 -2492 -2260 -2211 -1809 -3013 -912 -1301 -1696 -1279 -1589 -2286 -2077 -2095 -1879 -2484 -1706 -2304 -3264 -2799 -2091 -1513 -2440 -1817 -2115 -2891 -1992 -2327 -2080 -2858 -1978 -3101 -2332 -1718 -1347 -1669 -1892 -1670 -1807 -1389 -2495 -1907 -2461 -1972 -1792 -2017 -1373 -2350 -1920 -1752 -1697 -1466 -2157 -2098 -3875 -3148 -3308 -1447 -2555 -1652 -1852 -1228 -2543 -3094 -2112 -1562 -1566 -3395 -2200 -1766 -3215 -1177 -1931 -1826 -1129 -3284 -2333 -1086 -2225 -2732 -1996 -2797 -2985 -1694 -1784 -1633 -2247 -1827 -1894 -2341 -3080 -2240 -1985 -2479 -1878 -2482 -1633 -3122 -2720 -1409 -1801 -2868 -2150 -1838 -2782 -2308 -3092 -3759 -3688 -1775 -2425 -1700 -983 -2093 -1454 -2147 -2083 -2610 -1873 -1981 -2904 -2982 -2803 -1689 -2407 -2412 -1790 -3194 -2007 -2188 -2769 -2281 -2275 -2869 -1329 -2004 -837 -1744 -2275 -2416 -2010 -2869 -2438 -3027 -2366 -2411 -2360 -2814 -2037 -2270 -1425 -1778 -2125 -2918 -2582 -2506 -1950 -2687 -1281 -1646 -3286 -2117 -1187 -1388 -3071 -1903 -1932 -2462 -2412 -1538 -1014 -1981 -2452 -1378 -2710 -2463 -2381 -1916 -2135 -1768 -1075 -1286 -1368 -1595 -2252 -1812 -2852 -1520 -2438 -1421 -2177 -2036 -2110 -2120 -2236 -2393 -1988 -1888 -2463 -2653 -3003 -1723 -2051 -2895 -1790 -2191 -2766 -2193 -2198 -2301 -3373 -3511 -2981 -1658 -2719 -2377 -2385 -1918 -2842 -3269 -2207 -2841 -1469 -2492 -2556 -1803 -2009 -2833 -1867 -2021 -2369 -1308 -2058 -1718 -2260 -2099 -1953 -2948 -2352 -1629 -1858 -1343 -1814 -2323 -2078 -1199 -1666 -1617 -2510 -1925 -1950 -2967 -1927 -2079 -2320 -1942 -2689 -2067 -2537 -2282 -2440 -3229 -2147 -1110 -3308 -2938 -2211 -1540 -2608 -1343 -2301 -2683 -2626 -2602 -2477 -2096 -1664 -1995 -2525 -2581 -1642 -1865 -2042 -2552 -1469 -1563 -2337 -2136 -2036 -2150 -1832 -2177 -2375 -2730 -2292 -2256 -2363 -1661 -2042 -2250 -1805 -2377 -1831 -1933 -2283 -1207 -1523 -1563 -1238 -2609 -3667 -3477 -2457 -1782 -1696 -2820 -2419 -1374 -1179 -2381 -2062 -1669 -1724 -2016 -3780 -1878 -2215 -2547 -2334 -2850 -1750 -1887 -1154 -2317 -2662 -2092 -1854 -1508 -2462 -2028 -2182 -1589 -3193 -1834 -1675 -1297 -1754 -2059 -2376 -1739 -1567 -2320 -1990 -2107 -3025 -1917 -1508 -2348 -2622 -2013 -2366 -1312 -973 -2455 -2729 -1312 -2196 -1298 -2193 -1403 -1260 -1458 -2842 -1511 -1963 -1070 -2868 -1673 -2393 -2829 -2987 -1831 -2287 -1867 -957 -2000 -1654 -2445 -2533 -1140 -1253 -2080 -2667 -1667 -2460 -1671 -1696 -3711 -2540 -2668 -1542 -935 -2220 -2798 -2284 -2032 -1612 -1896 -2576 -2650 -2470 -1601 -2000 -3112 -2089 -2728 -2120 -2210 -2500 -1867 -1584 -2864 -2879 -3536 -2394 -1610 -3175 -1195 -1774 -1844 -1406 -1203 -1676 -2318 -1575 -1484 -2188 -1457 -2066 -1694 -2832 -2242 -2318 -2150 -2218 -1907 -2360 -3327 -2391 -2058 -2626 -2382 -3076 -2794 -1395 -2169 -3106 -1691 -2311 -2191 -2503 -1407 -2293 -1931 -2813 -1690 -1788 -3312 -2320 -1811 -3250 -1626 -2905 -2347 -1472 -1797 -1789 -2930 -1597 -2027 -2189 -2016 -2742 -2104 -1462 -2774 -2375 -2615 -2068 -2263 -2836 -1792 -2293 -2467 -1810 -2219 -2384 -3469 -1895 -3210 -1296 -1633 -1830 -2057 -2864 -1756 -2787 -2094 -1580 -2328 -4204 -1285 -1924 -1842 -1885 -2079 -3047 -2465 -2055 -2734 -2120 -1953 -3624 -1005 -1992 -1518 -1791 -1921 -2677 -988 -1721 -3054 -1840 -2173 -2777 -1577 -1968 -1709 -1882 -2862 -3192 -1683 -1707 -2360 -2399 -1488 -1678 -1991 -2967 -1089 -3158 -1962 -1575 -1415 -2288 -3057 -2427 -1943 -1670 -2032 -2604 -2731 -1772 -2704 -1600 -3070 -2432 -2445 -1457 -3097 -2088 -1763 -1639 -1876 -2198 -1200 -1615 -1088 -1502 -2583 -1080 -2004 -2952 -2149 -2965 -2230 -2188 -1656 -1438 -1948 -2051 -2836 -2148 -1948 -1844 -2652 -3834 -1603 -1747 -1552 -1694 -2998 -2063 -2098 -2199 -3399 -2610 -2335 -1516 -1629 -1639 -2638 -1083 -1528 -3173 -2014 -2771 -2622 -1997 -1997 -1360 -1921 -2349 -2440 -2289 -2083 -2287 -1571 -1408 -2027 -2418 -2810 -2590 -1544 -2003 -1913 -2290 -1731 -2072 -1713 -2044 -2646 -3317 -2485 -2760 -1975 -2077 -1308 -2154 -2374 -1300 -1642 -1127 -2869 -2210 -4705 -2649 -1208 -1946 -2134 -2189 -1854 -1471 -2476 -1838 -1745 -1300 -2089 -1924 -2587 -1906 -2227 -2724 -2905 -1913 -3612 -1933 -2895 -1435 -2892 -1360 -2391 -1386 -1436 -3200 -2156 -2960 -2152 -1857 -2391 -3292 -935 -2656 -1444 -2747 -2042 -2413 -1716 -2014 -1996 -1673 -2971 -2976 -1852 -2512 -2071 -1970 -3360 -2805 -2900 -1406 -2378 -2333 -1725 -2157 -1749 -2121 -1023 -3373 -2289 -2121 -2924 -2372 -1956 -2074 -1530 -1869 -3116 -2816 -2563 -2422 -3017 -2156 -2601 -2110 -814 -2010 -3482 -2608 -1592 -1965 -1957 -774 -2777 -1878 -1533 -1819 -1648 -1916 -2400 -3701 -2067 -2597 -2205 -3081 -2670 -2447 -2162 -1846 -1374 -1277 -1861 -1394 -2158 -2409 -2308 -1413 -2028 -2021 -1502 -2093 -1072 -1692 -2246 -1262 -2327 -2122 -2055 -2053 -1490 -2073 -3429 -1315 -2611 -1272 -1652 -2058 -3130 -1403 -1676 -1187 -1978 -1446 -2529 -1362 -2720 -1815 -2495 -2428 -1887 -2830 -2062 -2374 -1367 -1712 -1933 -2602 -2630 -2426 -2067 -2259 -1938 -2704 -2611 -2713 -1939 -1468 -2270 -2155 -2062 -1817 -2542 -3065 -1539 -2463 -1622 -1693 -1843 -1641 -2070 -1232 -2116 -2229 -1872 -1108 -2478 -2507 -3001 -1797 -1438 -1891 -1707 -3172 -2110 -1463 -3063 -1254 -1614 -1715 -4110 -3146 -1221 -1820 -2257 -3606 -1832 -1612 -1546 -1887 -2111 -2078 -2263 -2004 -3125 -2239 -2989 -2230 -1711 -2194 -1605 -2125 -2043 -2624 -2112 -1183 -2508 -2785 -1906 -2135 -1661 -2781 -2363 -2777 -2360 -2767 -1770 -2470 -3814 -1784 -2175 -1832 -2043 -2766 -2011 -2951 -2508 -2031 -2207 -2158 -2582 -2825 -2430 -2409 -2584 -2546 -1542 -2789 -2236 -3029 -2599 -2347 -2332 -2615 -2472 -1731 -2711 -2235 -2362 -1435 -1919 -2256 -1544 -2728 -1363 -1761 -2604 -1289 -2281 -1597 -2716 -1933 -3202 -1080 -2359 -1811 -1554 -1953 -1581 -2023 -2107 -1444 -1421 -1801 -1497 -2363 -3123 -3209 -1708 -2577 -3406 -2619 -2124 -1649 -1896 -1371 -1954 -1199 -2561 -1886 -2143 -1985 -1955 -2779 -1143 -2604 -1855 -1659 -2245 -3231 -2056 -2714 -2589 -2388 -1894 -2465 -1708 -2098 -1847 -3444 -2244 -1887 -2486 -1284 -2193 -2808 -1703 -2314 -1432 -2991 -2904 -2569 -2636 -2199 -1605 -2949 -2214 -1280 -1865 -1869 -1827 -1765 -2412 -2289 -2006 -2677 -1948 -2468 -3442 -2966 -2068 -2240 -2325 -1728 -2315 -2053 -3463 -1721 -2857 -3402 -1602 -3153 -1935 -2190 -1100 -1793 -2182 -2269 -1757 -1779 -2543 -2326 -2257 -2405 -1530 -2552 -3732 -2596 -2565 -1375 -2248 -1923 -2586 -1800 -1616 -2245 -1613 -2796 -2407 -2131 -2676 -4610 -3123 -2822 -2526 -2648 -1800 -1713 -1990 -2076 -1670 -2837 -3305 -1807 -3304 -1870 -3231 -1646 -2942 -2962 -1292 -1846 -2287 -2567 -2262 -2663 -1798 -3004 -2252 -2708 -3157 -1449 -1341 -2227 -2292 -2637 -2235 -1561 -1516 -2348 -2152 -3567 -2313 -2127 -1805 -1796 -2978 -2491 -1640 -1590 -1239 -2374 -3196 -875 -2244 -2175 -2236 -1804 -2368 -3252 -2687 -2174 -2936 -1943 -2344 -1947 -1466 -2480 -1655 -3096 -2095 -2161 -3632 -1600 -1767 -1621 -2131 -2598 -2439 -1259 -2708 -1575 -2499 -2114 -2191 -1803 -2194 -1550 -1521 -2219 -2077 -1571 -2149 -1149 -1988 -2696 -1354 -2139 -2708 -3390 -3591 -3346 -2270 -2740 -2379 -2077 -2343 -2146 -2380 -1455 -2783 -1724 -3007 -1492 -1785 -2919 -2226 -2185 -2072 -3587 -1786 -2120 -4000 -2945 -2760 -2186 -3128 -3710 -1973 -3153 -1357 -2364 -1668 -3387 -3215 -2054 -2038 -2302 -3037 -2127 -1577 -2996 -2370 -1275 -2353 -1839 -2063 -3128 -1803 -2650 -3599 -1382 -1752 -2031 -2098 -2757 -2055 -2324 -2405 -2036 -3231 -1963 -2952 -1702 -3316 -2130 -3129 -2862 -1508 -4088 -2408 -2827 -1915 -2130 -2057 -2472 -1460 -2232 -3567 -2735 -2028 -1464 -2595 -1871 -1061 -2614 -1985 -2226 -3327 -1575 -2849 -2014 -2098 -2103 -1911 -1867 -2885 -1585 -1179 -2499 -1415 -1349 -2068 -1546 -2673 -1642 -1198 -2007 -2486 -779 -2060 -1327 -1324 -1776 -1394 -3955 -2277 -2557 -2133 -2467 -2318 -2391 -2587 -2273 -2082 -1169 -2285 -1286 -2736 -1561 -1571 -2219 -2687 -1836 -2407 -1740 -1846 -3248 -3141 -2449 -2664 -2041 -1971 -1719 -1988 -2157 -2215 -2125 -2482 -3432 -756 -1938 -2026 -1664 -1782 -2206 -1908 -1963 -2000 -2049 -2416 -1555 -2449 -2084 -3428 -2216 -839 -1831 -2309 -2572 -1914 -2099 -2012 -2227 -2426 -1620 -1806 -1872 -2478 -2957 -2792 -3199 -2241 -3654 -3165 -2049 -2351 -1491 -1497 -1391 -2168 -2667 -1283 -1575 -1457 -1536 -2209 -2409 -2100 -2884 -1888 -2055 -3079 -3181 -1834 -1490 -2759 -2622 -1853 -1912 -2455 -2069 -1769 -2293 -3744 -1758 -1519 -2820 -2374 -2393 -1661 -2760 -1428 -2084 -1593 -1904 -2222 -3024 -3150 -3560 -2493 -1254 -2668 -1849 -1870 -2470 -1830 -1760 -1754 -2743 -2618 -989 -2383 -2975 -1400 -2526 -3327 -2742 -3328 -1148 -1038 -1933 -1850 -1532 -2024 -2133 -1191 -1097 -1885 -1679 -2782 -2093 -3085 -3346 -2400 -1203 -2505 -2904 -2055 -2752 -1979 -2928 -1714 -974 -1687 -1073 -3124 -2705 -2824 -1362 -1752 -2276 -1350 -1986 -714 -2777 -2404 -1823 -1581 -2238 -2739 -2448 -1492 -2121 -1612 -2238 -1238 -2053 -2664 -2409 -2305 -2577 -2271 -3106 -1323 -1675 -3521 -2645 -1756 -1627 -1821 -1835 -1629 -3278 -1401 -2386 -2869 -2099 -1236 -3199 -2829 -2518 -1929 -1982 -2572 -2145 -2706 -2400 -2783 -1772 -1568 -2503 -1864 -2138 -1628 -1617 -2379 -2795 -2158 -2075 -2132 -2315 -1427 -928 -1807 -1927 -2632 -2237 -3933 -1975 -2686 -1221 -1101 -2513 -1793 -2335 -2072 -2177 -3303 -2099 -2516 -1806 -2758 -2516 -2987 -2262 -2508 -2498 -1052 -2018 -1556 -1177 -3180 -2542 -3077 -2161 -2145 -2084 -2298 -4012 -2302 -2716 -1716 -2206 -2075 -1287 -2896 -2172 -2360 -2576 -3234 -1547 -1634 -1169 -2108 -2484 -2039 -3005 -2164 -1598 -1463 -2076 -2096 -1640 -2834 -2493 -2027 -2676 -3062 -2090 -1860 -2287 -2583 -2272 -1728 -2775 -2715 -1703 -1932 -1913 -1827 -2166 -2478 -1786 -2709 -1588 -2672 -3042 -2132 -2288 -2596 -1307 -2387 -1484 -1807 -2579 -2665 -2501 -2276 -3814 -2430 -2764 -2636 -1914 -2123 -1783 -1473 -2061 -1275 -2059 -2298 -2501 -2872 -1952 -2205 -1480 -1690 -2334 -2606 -1234 -2213 -2957 -1235 -2578 -1928 -1918 -2580 -2041 -1948 -1468 -1561 -1506 -1266 -2252 -1378 -2484 -2455 -2014 -2296 -2469 -2927 -1940 -1773 -2785 -2272 -2545 -2033 -2690 -2801 -2119 -1665 -2725 -2726 -2591 -3021 -2605 -1642 -1959 -3068 -2331 -1154 -2734 -1616 -2186 -2209 -3221 -777 -2023 -2439 -2684 -1643 -1869 -1445 -2270 -1496 -2958 -2500 -2001 -997 -3731 -1317 -1630 -1631 -2324 -1652 -2391 -1878 -1754 -2371 -2621 -1706 -1495 -1419 -2000 -3536 -1677 -1629 -2925 -1923 -3068 -2221 -2387 -2400 -1132 -2838 -1900 -2136 -2447 -2459 -2112 -2432 -1493 -2465 -2116 -1194 -2226 -2133 -2590 -3376 -2009 -1593 -2898 -3607 -2447 -1690 -1484 -2108 -2421 -2155 -2454 -1750 -2241 -2928 -2635 -2598 -2323 -1714 -3111 -2171 -1116 -2409 -3011 -1623 -3590 -2150 -2580 -1590 -2465 -1449 -3009 -3087 -1924 -1846 -1557 -2538 -2311 -2077 -1454 -2884 -3420 -2748 -2312 -2026 -1597 -1634 -1780 -2522 -3654 -1851 -1279 -2947 -2060 -2589 -1173 -2197 -1998 -2927 -1937 -2161 -1057 -2150 -1745 -1623 -2121 -2774 -1162 -2162 -2531 -1178 -4042 -1650 -1944 -2763 -2586 -1257 -2655 -2534 -2760 -2608 -1930 -1950 -1749 -2144 -1760 -2252 -2353 -1984 -3334 -2440 -950 -3059 -1869 -2133 -2831 -1849 -1917 -2938 -2558 -1799 -2738 -1240 -1847 -3232 -1462 -1917 -1984 -1852 -1426 -1890 -1309 -2853 -3134 -3373 -3552 -2651 -1959 -1908 -1092 -2201 -1323 -1559 -2586 -1413 -3748 -1610 -1408 -1055 -2299 -2561 -2246 -1518 -2433 -3386 -2035 -1796 -1937 -1649 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k4/trained_ddqn/best.pt deleted file mode 100644 index 1d8fc0d4c4a8ae7c85749a0e5b979e3ac99559d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13655 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 K-{b!p`#%7d2UPn2 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/dqn.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/dqn.txt deleted file mode 100644 index 8d6a76e33..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/dqn.txt +++ /dev/null @@ -1,2000 +0,0 @@ -996 -821 -1449 -1251 -1179 -803 -780 -1140 -1139 -1173 -969 -1148 -729 -1020 -938 -873 -904 -1329 -825 -1243 -862 -1048 -952 -1257 -1292 -1538 -697 -802 -697 -828 -829 -712 -819 -1416 -1112 -1377 -1035 -1042 -440 -925 -1388 -1244 -779 -491 -1209 -1096 -367 -1209 -1111 -926 -1369 -754 -1064 -892 -1178 -1006 -1327 -831 -1191 -1119 -701 -867 -1204 -853 -1208 -985 -881 -1023 -1281 -1623 -679 -1052 -986 -896 -745 -1199 -703 -531 -1152 -904 -597 -1547 -954 -655 -1467 -670 -666 -1603 -1517 -781 -582 -1320 -913 -677 -1120 -858 -710 -1036 -586 -909 -463 -806 -793 -1168 -1228 -1183 -1094 -1230 -992 -770 -1137 -753 -1086 -918 -1442 -894 -1144 -1291 -1253 -1129 -428 -781 -1019 -621 -810 -1875 -803 -1498 -1289 -981 -1144 -844 -1191 -776 -629 -780 -1313 -910 -945 -468 -1223 -1165 -717 -1264 -948 -785 -1072 -807 -1196 -996 -842 -1665 -958 -776 -912 -777 -1011 -1405 -1074 -857 -970 -1110 -638 -1054 -1000 -863 -668 -1259 -1018 -991 -635 -1492 -1028 -882 -1136 -1166 -1025 -1017 -861 -595 -959 -933 -991 -868 -850 -564 -1127 -1458 -885 -1200 -633 -935 -1125 -612 -721 -976 -854 -818 -810 -694 -707 -1716 -969 -1266 -1197 -1015 -1757 -1302 -829 -819 -827 -1081 -861 -799 -843 -848 -782 -673 -709 -937 -1466 -900 -1081 -1250 -531 -888 -951 -1414 -758 -923 -1156 -1163 -1087 -964 -880 -1087 -621 -918 -897 -1237 -1099 -1239 -1133 -1683 -1003 -1037 -743 -895 -500 -1209 -734 -547 -1253 -900 -1454 -862 -1271 -1167 -701 -906 -1331 -718 -1087 -758 -1114 -818 -1034 -594 -1303 -1240 -965 -1072 -1286 -1254 -667 -807 -729 -1005 -804 -665 -1215 -909 -1137 -915 -1123 -1032 -913 -790 -696 -716 -949 -945 -467 -949 -1549 -840 -984 -410 -650 -1119 -1053 -1044 -874 -757 -711 -1356 -1220 -909 -750 -1006 -1270 -848 -894 -1255 -808 -982 -935 -730 -932 -474 -801 -756 -858 -1146 -1118 -1024 -1092 -1455 -1521 -1166 -1187 -854 -682 -911 -875 -1189 -855 -987 -976 -849 -1363 -1216 -758 -1312 -886 -990 -784 -697 -853 -1099 -946 -1548 -996 -977 -682 -778 -1495 -948 -832 -777 -1083 -789 -764 -875 -957 -1040 -761 -835 -1159 -756 -773 -1334 -1200 -977 -674 -898 -785 -1096 -1568 -942 -738 -842 -630 -785 -858 -765 -705 -1004 -780 -1113 -692 -892 -1101 -1187 -1328 -335 -1106 -912 -710 -1626 -788 -1026 -896 -1204 -884 -1007 -1110 -940 -641 -1281 -986 -959 -1060 -680 -729 -1020 -1409 -1384 -662 -928 -535 -1133 -1106 -947 -1171 -1774 -810 -730 -711 -784 -848 -842 -914 -1096 -1044 -837 -986 -740 -1010 -1336 -947 -745 -628 -1109 -917 -930 -1225 -1259 -1316 -876 -916 -818 -1023 -630 -656 -885 -953 -1587 -592 -1004 -1031 -1102 -882 -881 -740 -1071 -752 -528 -1048 -1059 -902 -758 -690 -973 -1168 -811 -1101 -894 -1000 -584 -912 -633 -1128 -1259 -767 -1106 -671 -1422 -1218 -1487 -1335 -741 -1017 -727 -1384 -1234 -1245 -1242 -509 -948 -1258 -929 -601 -742 -1050 -903 -1170 -1349 -888 -1134 -1343 -742 -1003 -1084 -916 -832 -1068 -1425 -1157 -469 -717 -851 -1043 -868 -824 -627 -888 -971 -558 -723 -1411 -679 -872 -975 -867 -1194 -630 -1102 -1090 -637 -820 -719 -1125 -671 -1101 -782 -710 -708 -916 -898 -814 -928 -896 -1166 -789 -954 -853 -952 -663 -715 -1037 -1125 -1338 -924 -847 -1121 -1096 -710 -782 -865 -930 -813 -1058 -627 -915 -595 -799 -623 -1017 -1287 -841 -887 -955 -740 -1223 -1018 -783 -872 -1176 -835 -935 -551 -588 -658 -976 -693 -1659 -1010 -645 -1004 -1118 -1001 -1034 -1204 -1343 -979 -602 -1183 -942 -1249 -994 -871 -1019 -1169 -1578 -425 -863 -1075 -1123 -1006 -1035 -827 -996 -882 -1318 -1325 -975 -1087 -541 -872 -987 -1409 -807 -804 -671 -802 -442 -1078 -784 -1189 -1121 -1338 -868 -1131 -800 -1103 -1103 -1094 -1489 -654 -1152 -939 -916 -1219 -974 -829 -1144 -1361 -1099 -1162 -999 -466 -1280 -945 -900 -1049 -1034 -607 -841 -1068 -608 -1367 -914 -1035 -986 -927 -1160 -755 -847 -1493 -1003 -890 -1044 -848 -1384 -906 -1118 -1550 -1101 -1226 -1271 -999 -1315 -763 -1002 -611 -740 -609 -916 -925 -557 -874 -1210 -1420 -991 -1262 -1447 -971 -1257 -1142 -905 -1367 -1180 -939 -1075 -817 -1460 -816 -1037 -949 -640 -829 -1195 -703 -865 -1095 -879 -711 -1040 -1125 -1009 -1265 -1076 -1007 -909 -885 -953 -988 -1254 -1220 -876 -1081 -673 -1222 -633 -1627 -925 -725 -860 -1113 -1016 -1124 -635 -949 -961 -616 -895 -1638 -732 -1016 -1035 -713 -904 -982 -978 -1326 -1005 -1274 -863 -713 -567 -1260 -1082 -1089 -1155 -712 -827 -1350 -933 -552 -452 -871 -1137 -870 -1056 -935 -1277 -940 -984 -1024 -1043 -766 -460 -1159 -906 -973 -1242 -764 -1315 -962 -798 -741 -711 -1248 -1024 -885 -1089 -1547 -723 -671 -767 -1259 -1119 -783 -1283 -960 -1181 -1190 -825 -882 -903 -980 -1241 -1425 -878 -889 -798 -1035 -1244 -691 -657 -1425 -1197 -1314 -726 -1144 -1103 -764 -666 -1540 -565 -1203 -1032 -887 -1237 -1069 -1270 -968 -505 -921 -968 -1234 -848 -1416 -824 -655 -1087 -1296 -903 -748 -427 -977 -1207 -961 -736 -1066 -653 -557 -1354 -921 -1201 -761 -744 -1236 -1022 -802 -732 -945 -1293 -895 -912 -1177 -968 -759 -1033 -821 -998 -1718 -927 -804 -606 -1002 -657 -784 -1101 -749 -648 -1079 -659 -730 -933 -1056 -1037 -974 -1102 -813 -907 -637 -951 -1293 -846 -1350 -1001 -1106 -669 -1142 -1008 -1304 -1087 -728 -1106 -837 -1050 -1026 -836 -739 -765 -991 -963 -613 -1103 -1323 -1362 -992 -658 -662 -1428 -799 -1014 -717 -1105 -994 -1412 -578 -819 -844 -664 -900 -742 -939 -1189 -1152 -1335 -1068 -1042 -1001 -1436 -1184 -839 -1224 -958 -1086 -925 -845 -1115 -1313 -1356 -761 -873 -646 -961 -959 -864 -738 -706 -1310 -992 -1129 -1126 -1328 -1315 -906 -947 -1128 -685 -1365 -849 -1025 -783 -1245 -912 -1399 -1395 -699 -544 -1140 -1196 -1488 -782 -682 -889 -1031 -1000 -1544 -1039 -1141 -1100 -810 -802 -1002 -755 -1093 -1083 -763 -1263 -1284 -882 -913 -810 -593 -1220 -887 -668 -1305 -818 -1637 -955 -1012 -914 -974 -803 -1262 -1140 -963 -1052 -965 -922 -968 -848 -1065 -775 -1204 -1243 -1435 -609 -678 -1532 -1360 -683 -667 -1331 -924 -1123 -865 -882 -1445 -1318 -1086 -1025 -918 -880 -915 -1712 -759 -783 -878 -973 -1269 -920 -584 -997 -913 -1252 -381 -771 -1171 -1071 -978 -896 -1420 -1108 -873 -518 -1262 -1011 -1165 -1146 -1217 -1369 -1036 -1239 -657 -947 -966 -1213 -646 -1289 -914 -576 -1227 -1040 -1005 -959 -587 -534 -958 -669 -1170 -1130 -1100 -1292 -1079 -945 -1417 -865 -759 -768 -1248 -960 -700 -370 -711 -1633 -969 -846 -991 -1142 -1005 -1021 -586 -1409 -1038 -931 -1195 -841 -947 -1548 -675 -863 -1246 -1192 -943 -1047 -924 -790 -1191 -1226 -987 -1040 -1024 -1224 -663 -832 -1271 -1335 -899 -1079 -959 -875 -1049 -599 -1393 -1119 -1221 -1012 -1269 -1015 -1006 -892 -734 -1402 -1117 -1299 -1033 -1281 -724 -697 -690 -910 -843 -667 -851 -937 -781 -977 -1437 -1250 -676 -784 -663 -849 -781 -1633 -1038 -703 -1023 -1112 -726 -870 -875 -950 -1472 -1087 -730 -706 -827 -1273 -1138 -1104 -799 -932 -1509 -1062 -1047 -1183 -1505 -1358 -751 -654 -1020 -739 -718 -851 -1182 -935 -775 -885 -855 -1129 -923 -1032 -1184 -849 -844 -807 -936 -575 -1005 -1037 -958 -862 -898 -1376 -867 -1016 -935 -1049 -968 -1543 -909 -1058 -640 -889 -1367 -681 -526 -1203 -1132 -1017 -878 -622 -1175 -643 -1282 -1016 -1114 -778 -1254 -735 -1180 -1121 -845 -1800 -1177 -779 -1171 -1142 -580 -733 -734 -1021 -766 -671 -1038 -1323 -725 -648 -1270 -1268 -862 -978 -833 -1612 -634 -1269 -962 -785 -900 -1352 -1395 -1352 -766 -1236 -950 -1201 -1061 -1130 -1769 -766 -1524 -1398 -1329 -640 -779 -588 -1092 -855 -717 -1073 -992 -967 -916 -639 -750 -1137 -1153 -1714 -737 -1248 -1143 -1316 -1271 -722 -1202 -537 -1157 -1302 -790 -1444 -870 -815 -618 -952 -712 -1180 -1524 -972 -548 -1060 -971 -757 -1315 -1130 -758 -869 -1386 -1138 -1626 -1452 -885 -629 -1045 -871 -714 -1871 -685 -970 -1059 -914 -924 -683 -1274 -991 -902 -781 -1689 -890 -1387 -1015 -647 -1032 -737 -1040 -750 -786 -717 -1252 -1334 -1332 -796 -861 -1058 -688 -1414 -1040 -835 -1396 -1410 -1153 -968 -773 -1368 -922 -1211 -1000 -901 -1123 -915 -1127 -832 -714 -942 -832 -1362 -1089 -952 -1125 -703 -622 -1117 -882 -1010 -1294 -1002 -940 -1224 -1219 -1032 -1489 -943 -699 -528 -782 -701 -1021 -777 -1041 -902 -1053 -1212 -471 -671 -1066 -753 -1061 -1005 -1134 -1232 -999 -946 -593 -879 -1009 -915 -992 -1240 -1335 -451 -1026 -903 -1114 -792 -1280 -1204 -1124 -1164 -1310 -1090 -976 -1326 -577 -741 -1315 -1118 -1121 -1032 -740 -883 -1400 -1576 -683 -1028 -1084 -1061 -1129 -1225 -975 -563 -1089 -1122 -1071 -708 -861 -1391 -1441 -1134 -881 -1188 -1449 -1061 -1176 -514 -1018 -1175 -1087 -887 -1867 -500 -520 -1321 -1004 -676 -792 -368 -1226 -915 -1056 -887 -855 -1119 -1088 -732 -1149 -1409 -1373 -979 -1055 -1042 -807 -772 -1085 -861 -816 -923 -1043 -576 -1868 -1072 -1438 -671 -836 -1269 -1039 -850 -1451 -1113 -1737 -1100 -882 -1134 -901 -815 -1425 -746 -953 -983 -810 -784 -646 -1201 -1207 -1497 -2044 -1165 -851 -969 -1083 -775 -844 -906 -749 -746 -1436 -799 -875 -696 -762 -1077 -1206 -1100 -1054 -765 -1208 -1181 -877 -1203 -487 -797 -946 -1491 -1331 -611 -1229 -997 -1271 -1231 -965 -1493 -1074 -971 -709 -807 -785 -835 -638 -660 -929 -811 -1360 -696 -1406 -1124 -733 -993 -511 -648 -566 -966 -818 -483 -1193 -986 -1078 -1146 -792 -921 -1772 -797 -639 -1372 -1003 -685 -664 -1071 -2037 -1007 -891 -1166 -1430 -1196 -1335 -1168 -1237 -1231 -1393 -969 -978 -904 -619 -1416 -1011 -862 -853 -988 -967 -943 -583 -666 -719 -1168 -1084 -970 -976 -1433 -774 -1157 -612 -836 -788 -1197 -946 -1359 -869 -874 -1100 -1307 -840 -1303 -817 -687 -1428 -776 -680 -1000 -938 -1080 -1123 -1146 -1381 -1284 -638 -1542 -869 -1105 -952 -856 -1146 -1412 -1209 -792 -780 -1215 -1599 -1095 -924 -1955 -1095 -918 -1138 -1350 -1385 -1311 -586 -783 -766 -757 -1065 -760 -1543 -905 -1028 -1142 -882 -1119 -786 -1040 -444 -912 -1025 -1454 -1361 -1223 -873 -961 -882 -670 -881 -995 -1147 -1184 -943 -648 -1313 -729 -587 -1099 -1782 -884 -1226 -816 -790 -495 -521 -1155 -1227 -905 -1021 -1113 -804 -1584 -485 -999 -1183 -1181 -1192 -1176 -1092 -926 -1393 -1085 -946 -686 -1137 -1221 -1223 -1061 -980 -607 -570 -689 -945 -679 -1185 -907 -966 -1255 -1011 -715 -926 -1376 -1139 -1336 -856 -1110 -882 -1173 -1611 -770 -966 -1248 -605 -617 -1057 -1498 -1044 -1212 -577 -743 -665 -561 -1151 -609 -378 -945 -870 -1523 -1236 -1526 -1148 -938 -647 -914 -733 -568 -906 -572 -774 -748 -1259 -1211 -1519 -738 -1153 -696 -660 -1402 -786 -735 -1145 -1012 -1233 -696 -901 -757 -757 -1131 -720 -1170 -833 -694 -898 -764 -925 -634 -1195 -1009 -1159 -1235 -849 -1352 -623 -1200 -985 -682 -895 -1173 -826 -666 -1088 -936 -1331 -893 -892 -714 -1078 -1238 -1176 -776 -1344 -1232 -980 -661 -1079 -1025 -1026 -772 -865 -969 -735 -807 -602 -792 -1960 -759 -956 -1339 -1048 -836 -796 -703 -753 -837 -916 -1026 -1098 -1082 -826 -1044 -892 -1218 -873 -1177 -924 -655 -799 -922 -993 -868 -755 -686 -1011 -846 -763 -928 -1462 -957 -1508 -1104 -771 -1261 -1218 -1017 -1012 -950 -841 -1179 -841 -1179 -860 -1016 -432 -795 -1047 -1174 -1387 -1154 -947 -1055 -919 -1291 -862 -872 -1471 -875 -1169 -1352 -714 -1167 -691 -787 -749 -787 -949 -795 -1023 -1058 -1167 -1361 -1180 -862 -593 -1163 -1177 -699 -872 -984 -679 -1152 -992 -1101 -779 -992 -1171 -795 -1150 -1085 -1181 -1059 -865 -810 -1253 -473 -1382 -837 -1037 -1023 -992 -1136 -943 -891 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/optimal.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/optimal.txt deleted file mode 100644 index 169de411c..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/optimal.txt +++ /dev/null @@ -1,2000 +0,0 @@ -1204 -984 -739 -1110 -815 -935 -1211 -679 -803 -1109 -1467 -1046 -904 -1083 -1503 -1077 -1196 -787 -1179 -1182 -1428 -1106 -1247 -1404 -1362 -1263 -852 -1565 -1185 -814 -757 -704 -622 -371 -990 -1132 -592 -935 -700 -712 -956 -1112 -969 -846 -707 -722 -1107 -1298 -1360 -951 -863 -1377 -973 -944 -690 -805 -704 -906 -931 -954 -964 -924 -1199 -1088 -1171 -1018 -1138 -993 -1207 -784 -1040 -841 -761 -1003 -943 -1128 -1102 -1652 -1160 -773 -1132 -1303 -1105 -898 -663 -880 -1306 -680 -1107 -1026 -1376 -615 -677 -1360 -1321 -633 -1109 -566 -894 -906 -937 -746 -839 -1309 -653 -1176 -664 -830 -1264 -728 -1302 -757 -750 -568 -921 -1062 -1002 -1102 -1179 -750 -1017 -631 -1306 -853 -957 -1251 -1235 -823 -678 -1065 -1417 -891 -1186 -1140 -1360 -955 -1498 -1048 -1127 -956 -1172 -690 -1274 -846 -1347 -1204 -684 -1129 -1103 -1044 -985 -1369 -811 -643 -912 -579 -1239 -714 -988 -1342 -1067 -1178 -723 -781 -1357 -1100 -1008 -749 -1189 -1022 -609 -1125 -818 -1323 -1339 -817 -665 -875 -704 -1015 -650 -928 -1135 -1026 -831 -1182 -942 -800 -1122 -1195 -1007 -1272 -942 -1121 -625 -1026 -928 -904 -622 -759 -547 -1468 -1455 -1073 -1453 -1370 -1478 -957 -1140 -767 -471 -730 -759 -1040 -855 -1025 -1242 -836 -1466 -1278 -817 -547 -848 -1098 -1795 -1153 -1057 -1038 -1239 -980 -708 -1217 -877 -908 -951 -969 -771 -848 -823 -692 -952 -1158 -1261 -1428 -727 -1208 -892 -993 -476 -1029 -616 -778 -566 -496 -783 -1259 -663 -710 -545 -1408 -965 -918 -472 -1175 -660 -1148 -667 -797 -1354 -977 -963 -494 -750 -1336 -823 -1475 -1142 -1741 -1203 -731 -796 -939 -929 -1173 -1318 -1052 -869 -912 -1145 -886 -1230 -977 -1570 -1129 -858 -876 -1297 -714 -1292 -833 -859 -916 -678 -1252 -790 -812 -958 -1021 -856 -1231 -1940 -859 -1021 -967 -696 -940 -767 -771 -970 -1007 -1078 -1486 -935 -1306 -903 -1305 -837 -802 -951 -995 -1008 -699 -868 -1184 -1229 -757 -615 -843 -814 -925 -1027 -748 -480 -917 -814 -1148 -1264 -751 -1363 -1107 -1300 -1222 -517 -1388 -796 -1007 -1108 -867 -620 -712 -927 -1128 -664 -1192 -639 -851 -674 -1137 -647 -747 -806 -825 -931 -929 -798 -625 -813 -862 -697 -1351 -885 -1179 -390 -1047 -1252 -1472 -1354 -721 -853 -598 -1207 -1344 -1339 -1184 -940 -1204 -643 -1085 -1299 -847 -704 -794 -1330 -1107 -810 -1317 -809 -866 -1375 -855 -952 -534 -1245 -529 -786 -738 -1176 -1343 -1304 -1159 -815 -1066 -755 -1122 -1155 -675 -1185 -721 -855 -1539 -794 -676 -924 -900 -931 -957 -838 -793 -1556 -1147 -1038 -1115 -919 -1025 -797 -1155 -963 -1045 -1063 -1138 -1113 -1038 -570 -1247 -985 -1045 -1197 -1001 -898 -572 -1321 -581 -1148 -1095 -988 -877 -995 -1087 -765 -833 -1146 -924 -912 -581 -848 -710 -1352 -812 -926 -908 -799 -760 -894 -1196 -1477 -906 -1237 -842 -659 -1064 -551 -1214 -1356 -1278 -1305 -673 -649 -945 -959 -1168 -795 -772 -858 -1006 -1185 -1188 -845 -1074 -853 -911 -703 -1171 -1140 -862 -1555 -538 -822 -709 -1185 -1261 -973 -1198 -823 -829 -697 -1589 -946 -953 -1268 -1288 -740 -805 -1066 -1133 -736 -1456 -1067 -979 -1189 -719 -943 -891 -1170 -896 -837 -764 -708 -1000 -745 -798 -903 -1107 -984 -996 -1085 -590 -1053 -818 -1000 -945 -1367 -1077 -1526 -981 -755 -1433 -979 -1114 -1278 -936 -771 -975 -1004 -582 -652 -923 -1389 -855 -1184 -926 -1221 -1303 -1418 -1059 -608 -1283 -1047 -798 -1318 -1018 -1465 -637 -677 -960 -1188 -902 -1251 -1642 -1105 -724 -1308 -1047 -944 -787 -1441 -1190 -903 -837 -1027 -925 -891 -930 -1137 -1053 -1803 -1045 -1107 -921 -1149 -929 -1064 -680 -1192 -801 -1024 -823 -828 -893 -1267 -992 -995 -821 -1180 -792 -996 -956 -932 -1177 -749 -808 -1166 -623 -1178 -529 -831 -1100 -1031 -1131 -1390 -722 -809 -820 -725 -1161 -944 -828 -942 -1222 -1077 -785 -892 -1313 -1294 -868 -864 -1326 -957 -613 -701 -922 -592 -1048 -728 -780 -590 -812 -1034 -1066 -513 -1189 -1205 -708 -1228 -1305 -1001 -741 -809 -1476 -706 -1394 -1298 -729 -876 -1031 -1042 -1022 -847 -1003 -1129 -1088 -1158 -942 -834 -877 -1149 -1003 -822 -678 -1246 -974 -631 -753 -803 -912 -917 -904 -854 -1365 -806 -1789 -1334 -911 -973 -925 -751 -957 -865 -1021 -1353 -876 -965 -1579 -710 -1132 -801 -1079 -1134 -1776 -1105 -1034 -831 -968 -754 -1448 -1174 -833 -904 -876 -1013 -1100 -1309 -1157 -1108 -733 -979 -1106 -900 -739 -1008 -1209 -643 -965 -1055 -782 -834 -1504 -1064 -709 -1065 -1269 -817 -1108 -724 -1070 -1493 -895 -818 -878 -1332 -815 -1105 -1112 -833 -976 -1200 -1201 -842 -1234 -832 -1021 -1434 -520 -911 -1625 -1035 -855 -702 -1144 -778 -1126 -979 -882 -958 -1027 -1777 -1121 -522 -1025 -1072 -1014 -1126 -974 -1609 -1112 -862 -798 -1088 -992 -573 -800 -1542 -1115 -668 -672 -943 -1056 -870 -1299 -650 -401 -706 -1060 -614 -1002 -987 -912 -776 -1034 -1059 -1868 -933 -538 -1076 -801 -1270 -1219 -972 -1149 -1203 -617 -1024 -1134 -980 -1510 -1110 -557 -722 -1063 -1453 -837 -872 -734 -779 -997 -897 -897 -644 -1207 -927 -630 -1277 -869 -1142 -653 -1292 -766 -1200 -773 -612 -1050 -848 -737 -876 -921 -824 -959 -953 -1229 -672 -921 -985 -1186 -997 -741 -939 -1332 -1237 -888 -1127 -1035 -940 -918 -969 -743 -970 -1046 -1080 -838 -1296 -607 -853 -694 -1361 -544 -1273 -790 -862 -860 -842 -1140 -1055 -1121 -929 -1010 -1052 -756 -837 -795 -627 -1131 -1157 -890 -1025 -939 -1018 -905 -638 -968 -1055 -778 -1609 -1239 -1490 -1318 -975 -1066 -379 -1146 -860 -894 -585 -945 -975 -519 -607 -702 -1016 -1593 -802 -883 -1167 -1102 -1351 -1291 -779 -1239 -850 -1245 -650 -1217 -1374 -821 -1051 -816 -925 -949 -665 -1110 -672 -896 -1437 -1280 -857 -664 -1191 -896 -492 -1202 -1153 -700 -873 -1079 -1183 -998 -841 -1038 -1341 -950 -978 -614 -1008 -708 -753 -682 -1209 -602 -629 -708 -1270 -1186 -1011 -893 -894 -1021 -1373 -638 -743 -558 -1174 -1118 -1008 -1043 -888 -1133 -879 -990 -1032 -809 -918 -872 -558 -865 -912 -634 -1004 -1252 -703 -1099 -698 -604 -928 -698 -1175 -992 -1363 -937 -1196 -792 -706 -607 -1042 -1030 -617 -1083 -967 -783 -1134 -807 -982 -760 -659 -851 -984 -1371 -1018 -803 -1125 -708 -770 -941 -649 -1129 -1482 -786 -1267 -883 -1318 -1103 -842 -1022 -1078 -988 -689 -664 -894 -777 -1365 -847 -825 -626 -1255 -767 -772 -885 -514 -1415 -1230 -1238 -1069 -546 -930 -1294 -1037 -1131 -1444 -796 -794 -957 -1200 -1005 -913 -808 -1182 -940 -1088 -973 -734 -688 -696 -534 -692 -1311 -912 -1284 -973 -731 -822 -870 -1260 -1009 -1060 -1122 -635 -1173 -635 -1004 -1118 -678 -554 -1172 -933 -1030 -1216 -1628 -1136 -914 -1056 -738 -993 -1054 -915 -590 -886 -1193 -466 -676 -954 -1574 -983 -922 -1311 -922 -1221 -1117 -1069 -1113 -1269 -704 -988 -1619 -1000 -1121 -1175 -822 -862 -1094 -908 -492 -1134 -667 -674 -1086 -915 -1191 -1061 -813 -1106 -800 -1137 -809 -640 -813 -1249 -763 -1200 -884 -481 -1017 -828 -623 -844 -888 -1256 -886 -799 -1119 -961 -1012 -1009 -1274 -792 -1058 -1130 -1329 -866 -1250 -1501 -845 -1369 -1085 -890 -737 -945 -1268 -959 -1349 -1252 -916 -1163 -1073 -1044 -933 -644 -1319 -1176 -1186 -869 -1243 -580 -730 -1326 -1284 -907 -794 -1066 -696 -1066 -794 -1332 -493 -944 -1188 -1802 -732 -474 -1046 -1422 -988 -1083 -1369 -1028 -792 -1074 -1052 -495 -982 -1085 -966 -1219 -1426 -1395 -1255 -1123 -878 -964 -1322 -1256 -842 -1104 -613 -522 -947 -1358 -1594 -566 -892 -1085 -1136 -772 -1173 -1146 -1185 -329 -578 -978 -1296 -1057 -853 -660 -780 -855 -977 -1013 -447 -763 -797 -787 -782 -621 -870 -978 -1121 -458 -716 -1155 -1168 -1237 -578 -593 -556 -542 -1222 -1063 -1310 -649 -971 -847 -931 -593 -865 -778 -1217 -778 -472 -839 -768 -1000 -1219 -565 -885 -739 -533 -1157 -1157 -647 -2118 -795 -1602 -1244 -475 -454 -611 -911 -1212 -1040 -1112 -1047 -780 -1124 -761 -898 -1270 -707 -972 -1420 -805 -1376 -1102 -681 -1646 -889 -1069 -747 -1115 -557 -1347 -754 -1055 -1096 -841 -870 -1014 -1464 -1110 -947 -692 -732 -1003 -1040 -1092 -1175 -1092 -962 -1128 -1239 -882 -797 -975 -587 -976 -979 -780 -560 -1113 -545 -1097 -825 -1139 -1075 -813 -1018 -1244 -841 -760 -1367 -926 -763 -820 -1146 -994 -507 -1155 -958 -906 -957 -997 -1539 -919 -866 -767 -1029 -944 -948 -921 -1037 -996 -1093 -1051 -1160 -1481 -1269 -941 -1131 -1716 -951 -1088 -1410 -1112 -1012 -923 -826 -911 -881 -1070 -889 -909 -933 -611 -804 -643 -766 -1112 -854 -1349 -939 -819 -1064 -549 -1460 -1178 -828 -841 -868 -973 -1659 -1013 -1122 -952 -815 -683 -1041 -842 -843 -907 -1168 -967 -805 -1455 -1355 -775 -1169 -1320 -733 -918 -831 -848 -764 -747 -1163 -741 -899 -838 -1029 -1246 -1592 -867 -1087 -652 -1091 -1275 -1193 -922 -1526 -1276 -821 -952 -1120 -775 -1239 -994 -877 -963 -989 -1304 -883 -825 -772 -974 -1071 -949 -990 -746 -1051 -1182 -873 -651 -772 -741 -1897 -1202 -961 -1463 -1061 -1262 -1299 -1011 -1008 -1341 -1210 -1001 -688 -1108 -989 -1083 -690 -1033 -739 -605 -1377 -1206 -984 -1048 -831 -1227 -923 -1282 -888 -587 -1002 -1466 -1442 -883 -895 -663 -1148 -851 -782 -1033 -1200 -986 -1012 -799 -1489 -430 -1102 -1055 -1032 -1157 -1120 -955 -836 -1139 -714 -858 -1157 -1014 -900 -1171 -1369 -982 -943 -1251 -1026 -1599 -1387 -919 -1190 -911 -902 -1035 -852 -889 -850 -814 -930 -1333 -1516 -1207 -993 -671 -846 -992 -907 -728 -1385 -1406 -1469 -1003 -1058 -1416 -832 -717 -1539 -986 -1287 -869 -762 -1093 -799 -802 -1497 -895 -1118 -1015 -1118 -1138 -1206 -1106 -927 -753 -1136 -576 -718 -1028 -1072 -961 -965 -938 -1060 -758 -600 -1034 -981 -705 -1994 -943 -1140 -1010 -969 -1127 -726 -803 -882 -752 -1055 -1160 -979 -889 -858 -1247 -1264 -1027 -1295 -1180 -1013 -947 -1187 -718 -1275 -1056 -1159 -903 -1052 -1300 -770 -1126 -1076 -1227 -1142 -1166 -1208 -1123 -676 -1430 -757 -1268 -894 -1450 -1496 -669 -1142 -585 -1376 -1339 -499 -1551 -1129 -1091 -878 -1047 -637 -1239 -923 -1266 -1478 -1037 -1005 -1055 -880 -625 -592 -918 -769 -1194 -672 -907 -779 -549 -1104 -894 -900 -1301 -740 -971 -1223 -829 -956 -924 -1148 -1506 -722 -587 -1214 -865 -674 -1242 -871 -1292 -578 -979 -1214 -1148 -828 -1911 -1099 -1874 -639 -747 -1222 -565 -1215 -916 -703 -776 -1324 -1053 -1075 -1022 -1345 -985 -1091 -978 -1053 -1253 -970 -1064 -601 -591 -1448 -734 -1024 -1184 -821 -717 -940 -676 -872 -930 -675 -1054 -1576 -845 -1247 -625 -801 -1219 -1193 -1045 -1096 -886 -1013 -1072 -1124 -884 -736 -1033 -1399 -926 -867 -870 -807 -871 -1148 -809 -925 -1138 -896 -1260 -744 -534 -943 -890 -1120 -1196 -1130 -922 -1219 -878 -1322 -1069 -1146 -1034 -688 -932 -951 -1231 -1027 -877 -798 -1123 -1378 -1006 -1177 -996 -1462 -1029 -1157 -961 -725 -955 -927 -1206 -934 -864 -1307 -678 -969 -865 -911 -734 -1639 -752 -1312 -1582 -1121 -692 -1495 -806 -790 -842 -863 -548 -1174 -1249 -914 -829 -647 -1135 -1189 -1081 -717 -830 -1059 -1223 -1086 -597 -773 -558 -978 -924 -1221 -803 -883 -759 -758 -919 -1146 -1020 -861 -1324 -766 -801 -917 -655 -1212 -914 -719 -673 -692 -1714 -781 -1091 -1219 -696 -1176 -1108 -766 -775 -1067 -1354 -1097 -1348 -965 -997 -1117 -1107 -946 -1122 -622 -1234 -1108 -850 -890 -721 -1038 -1242 -703 -810 -915 -636 -897 -743 -905 -899 -1110 -1219 -949 -639 -1060 -1012 -735 -972 -981 -1082 -1119 -1006 -781 -866 -805 -664 -922 -764 -1011 -869 -864 -1153 -1267 -817 -1410 -1049 -848 -929 -1374 -1315 -866 -739 -894 -943 -1004 -1404 -1424 -800 -2004 -1261 -741 -811 -1024 -756 -812 -939 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/random.txt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/random.txt deleted file mode 100644 index 56f648590..000000000 --- a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/random.txt +++ /dev/null @@ -1,2000 +0,0 @@ -2922 -1771 -1848 -3885 -2643 -2894 -2541 -1793 -2698 -3189 -4139 -3002 -1614 -2958 -2060 -2537 -5596 -2520 -2633 -3369 -3360 -1521 -3177 -2529 -3396 -1953 -2302 -2158 -3755 -2556 -2241 -2669 -3909 -3340 -3368 -2476 -3085 -3105 -2455 -2641 -2496 -4348 -2614 -4238 -2392 -2001 -2101 -2377 -3194 -2307 -1931 -1764 -1571 -1928 -3042 -2728 -2796 -2383 -3289 -1241 -4361 -2915 -1927 -2128 -2262 -2733 -4372 -2869 -3329 -3352 -1779 -3309 -2407 -1895 -4253 -2970 -2646 -2032 -2403 -1696 -1632 -2700 -2504 -1983 -4469 -3129 -2240 -2700 -2481 -2686 -2677 -2968 -4048 -3748 -3288 -2004 -2847 -2691 -1951 -2961 -1799 -3814 -2031 -2328 -3277 -2939 -1871 -3717 -1933 -2222 -3688 -1659 -2825 -2310 -2863 -3902 -1737 -3116 -2356 -2747 -3397 -1946 -2332 -1609 -2456 -3904 -2557 -3788 -1582 -2067 -1977 -3030 -4679 -3244 -1873 -2915 -2369 -1229 -4684 -2965 -2255 -3729 -1733 -2669 -2846 -3118 -2396 -3412 -1818 -3577 -2194 -1106 -2563 -2234 -1907 -2405 -4184 -2420 -3094 -3325 -1906 -3933 -2394 -1955 -3274 -1856 -2936 -3905 -2560 -3533 -2680 -2483 -1859 -1853 -1787 -3698 -1111 -2003 -2990 -2707 -3447 -4656 -4559 -3256 -2553 -3168 -1330 -3016 -2808 -3512 -3171 -3117 -2038 -1600 -1921 -2821 -2447 -2190 -2059 -2404 -3355 -2586 -2154 -2175 -1655 -3991 -2906 -2052 -2499 -1908 -1396 -2681 -1586 -1840 -3460 -2610 -3258 -3768 -3070 -1682 -1478 -2893 -2435 -2296 -2373 -3060 -3716 -2952 -2244 -1753 -2025 -3509 -2384 -2141 -1838 -2175 -4591 -2784 -2357 -2572 -5094 -2835 -1810 -2234 -2569 -1405 -2417 -1539 -1838 -3250 -2665 -3113 -1871 -3755 -3610 -1686 -2556 -1888 -2404 -3861 -3247 -2654 -4628 -2619 -1900 -3108 -2420 -2823 -1391 -2373 -3725 -2776 -4167 -3268 -3313 -3620 -1961 -3062 -2487 -3803 -2089 -2566 -3168 -4565 -2182 -1590 -3283 -4352 -2319 -3047 -1158 -2909 -1462 -2074 -3943 -2901 -3296 -2452 -2287 -4729 -2744 -4353 -1731 -2451 -3163 -2686 -2396 -2213 -2514 -2752 -4348 -2386 -1630 -3215 -3477 -3272 -3727 -3345 -3326 -2536 -2828 -2193 -2166 -2816 -2679 -2030 -3119 -3684 -1501 -5308 -2041 -3532 -2349 -2906 -2221 -4897 -4116 -5489 -2690 -2444 -3765 -4349 -4212 -2838 -3118 -3842 -3042 -3714 -2398 -2177 -2771 -2173 -2453 -3226 -1953 -3693 -2710 -2037 -2141 -2194 -3500 -1924 -4939 -3150 -1916 -3391 -2961 -2192 -2230 -3598 -3307 -3169 -2319 -2767 -1497 -3318 -1421 -3656 -2102 -3146 -1858 -3254 -2911 -2200 -2968 -2175 -2523 -2385 -1999 -3132 -2863 -2779 -1965 -1183 -1337 -2080 -1711 -3517 -1466 -2039 -2353 -2497 -3045 -2113 -2668 -4701 -3280 -2381 -1975 -3332 -2000 -2526 -2479 -2846 -2448 -3185 -2911 -2402 -2122 -3146 -1391 -2119 -1661 -2559 -2979 -2718 -3480 -4019 -2776 -3874 -2579 -2742 -1934 -2083 -3086 -855 -3273 -2805 -1944 -5703 -2454 -3160 -2347 -2126 -1882 -3353 -2446 -2411 -2040 -2775 -3226 -1690 -1170 -3946 -2011 -3442 -2332 -1977 -2540 -3176 -2593 -3423 -3278 -2354 -1703 -4290 -3028 -1251 -2794 -1822 -1976 -1179 -4106 -2648 -2273 -3882 -1517 -2307 -2461 -2573 -2959 -1629 -3706 -2526 -3409 -3325 -3289 -3207 -1462 -1719 -2883 -3260 -1940 -1890 -2292 -3001 -3324 -2346 -3421 -2454 -4951 -2317 -3918 -3113 -2660 -2499 -1615 -2927 -1544 -1621 -3199 -1763 -2664 -1956 -3440 -2592 -4493 -3379 -3533 -4062 -2615 -3190 -2656 -2407 -2444 -2283 -3042 -2161 -2436 -2246 -2648 -1858 -2120 -1880 -2146 -2710 -2386 -1109 -2150 -1846 -2167 -2345 -2559 -2040 -2516 -2328 -2660 -2472 -2705 -1057 -1660 -1418 -2621 -3384 -2654 -1691 -2736 -2809 -2065 -2157 -3603 -2385 -2136 -2211 -3680 -2627 -2868 -2092 -2941 -2888 -2138 -2338 -2738 -2168 -1487 -1271 -2428 -3900 -1796 -3198 -3260 -1336 -2062 -3080 -2602 -2069 -2590 -1297 -1792 -2775 -4560 -3917 -2585 -2631 -4738 -1135 -3109 -2659 -1792 -2058 -2530 -2546 -2386 -1031 -2029 -2490 -2613 -2435 -2793 -3370 -2917 -2988 -2340 -3042 -3061 -4805 -2085 -2987 -1713 -2562 -1836 -3116 -2063 -1655 -5586 -3108 -3498 -3271 -3270 -1570 -2721 -2248 -928 -2783 -2225 -3313 -4015 -1717 -2684 -2702 -1778 -2024 -2333 -2236 -2679 -2446 -1849 -1851 -2375 -2669 -1749 -2693 -3336 -2554 -2789 -3021 -1961 -2168 -4649 -1687 -1946 -1875 -3307 -2997 -2975 -3046 -2452 -2047 -2323 -3950 -2232 -2901 -2816 -3479 -1385 -3421 -2800 -2676 -2763 -3087 -1575 -2659 -4320 -2560 -938 -2573 -3091 -2135 -1529 -2124 -1581 -2657 -1266 -3168 -2221 -3662 -2415 -2318 -4485 -2188 -2894 -2551 -3224 -2308 -2074 -3489 -2789 -2248 -1908 -2637 -1528 -1887 -1274 -2128 -1584 -3204 -2385 -2090 -3724 -4684 -2758 -2530 -2438 -3472 -2861 -3006 -1093 -2622 -3946 -3678 -3595 -3202 -3106 -2005 -4332 -2220 -1281 -2457 -2767 -3015 -2592 -3067 -2833 -2417 -2392 -3320 -1697 -2232 -2585 -1416 -2496 -2821 -3823 -3100 -2570 -2447 -3556 -3193 -3738 -2990 -4722 -3534 -1820 -2400 -4037 -2879 -2856 -2271 -2194 -3846 -2579 -2572 -2694 -2363 -2553 -3336 -1487 -2785 -1084 -3052 -3132 -2803 -3007 -2445 -2143 -2231 -1904 -2686 -4002 -2505 -3227 -3135 -2438 -2473 -2424 -3464 -3015 -3138 -2209 -2699 -3152 -2781 -2475 -3528 -2898 -1600 -2180 -2192 -2773 -1407 -2484 -2730 -2691 -2961 -3993 -2498 -1853 -2755 -1966 -3730 -3127 -1688 -2824 -2604 -2602 -1818 -1755 -1554 -3991 -1630 -1627 -2654 -2787 -4615 -2923 -2100 -2618 -3676 -1980 -1180 -2090 -3325 -1972 -3439 -3249 -4107 -2464 -1662 -4116 -3281 -914 -1907 -2491 -5182 -3413 -2728 -3318 -3995 -1784 -3528 -4871 -1834 -1725 -3160 -2847 -2451 -2598 -2519 -4021 -3247 -1529 -2692 -2169 -3451 -2162 -3333 -2915 -4672 -3678 -3868 -3185 -2249 -2187 -2781 -3455 -1272 -2356 -3695 -3268 -3111 -3136 -2739 -2593 -2305 -3559 -2451 -2955 -2393 -2213 -2735 -2725 -2546 -2571 -1976 -3294 -2271 -2719 -1285 -2088 -2340 -3440 -1954 -2276 -2492 -2217 -3368 -2664 -3747 -3033 -1330 -3081 -2481 -2254 -2393 -2093 -4686 -4192 -3461 -3285 -2720 -3964 -3046 -2990 -2208 -1965 -3124 -2180 -2206 -2900 -4169 -3514 -2648 -3017 -2429 -2284 -1724 -2763 -2181 -1797 -4170 -3119 -2022 -2187 -3036 -2410 -2747 -2652 -2268 -2614 -2207 -2989 -3044 -3480 -3039 -4189 -2351 -2625 -2380 -1257 -1978 -2201 -2525 -2667 -3208 -3854 -2844 -2524 -2764 -2191 -1961 -5097 -3091 -3743 -1100 -3782 -2157 -2630 -2865 -2853 -2483 -2307 -2094 -2008 -1951 -4671 -3663 -2543 -3961 -1547 -1916 -2193 -4257 -3278 -1518 -2335 -2464 -3363 -1907 -2507 -3236 -1808 -3634 -2146 -2498 -2439 -2346 -2585 -3287 -3435 -2667 -3026 -4112 -2691 -2115 -3473 -1794 -1932 -3346 -2235 -3285 -1771 -2147 -2462 -3189 -2268 -2933 -3118 -2818 -2354 -2320 -2536 -2522 -1489 -3542 -3026 -3003 -2415 -2915 -2932 -4083 -2378 -3396 -2304 -1385 -2893 -2991 -3186 -2080 -2033 -2546 -3851 -3099 -4231 -2146 -3182 -2164 -1798 -2754 -2409 -2214 -2542 -2412 -2521 -2604 -1956 -2668 -2604 -1922 -2342 -1998 -2217 -2375 -3495 -4286 -2548 -2592 -2931 -3349 -2439 -1908 -1674 -2413 -2960 -1818 -4580 -3006 -2300 -2510 -4229 -3639 -2863 -2045 -2586 -2253 -4558 -2852 -2543 -1864 -4923 -2997 -2321 -2854 -2401 -2238 -4252 -2240 -2342 -2866 -1905 -2398 -3485 -3930 -3545 -4077 -3292 -3704 -4764 -2159 -3447 -2679 -3856 -2273 -2190 -1759 -2762 -3074 -2205 -2037 -2229 -3103 -5304 -3466 -3872 -1837 -1933 -2496 -2340 -2858 -2969 -2335 -2403 -2796 -3273 -2333 -1827 -1962 -4183 -4095 -3380 -2311 -2602 -1802 -3096 -2008 -2904 -3560 -2380 -2612 -2397 -4210 -2540 -1934 -2013 -2240 -2796 -3171 -1997 -1417 -3364 -1903 -2666 -4193 -2026 -2803 -4827 -2798 -1738 -2433 -3230 -4277 -2801 -3066 -3232 -2456 -2385 -3588 -1930 -1339 -4175 -2505 -2163 -1278 -2309 -2809 -2550 -2876 -2747 -3296 -2117 -2096 -4344 -3055 -4812 -2414 -941 -2953 -3471 -2688 -1978 -2396 -1545 -2886 -3995 -3033 -4049 -2043 -2519 -2779 -2828 -2679 -2924 -3388 -1986 -2536 -2496 -3533 -1529 -2122 -2512 -2655 -3393 -2519 -2954 -3889 -3341 -3023 -2702 -2580 -3078 -2228 -2452 -909 -3265 -2410 -3227 -3041 -1437 -2162 -2116 -2287 -3287 -3376 -2675 -2524 -2797 -4218 -2840 -2440 -5054 -2374 -3444 -3032 -1826 -2804 -4554 -2579 -2860 -1962 -3301 -2462 -2193 -1236 -3399 -2478 -2280 -1146 -1866 -3490 -2221 -2048 -3275 -3033 -3892 -2318 -1084 -2358 -2409 -1204 -3159 -4807 -2072 -2239 -2399 -1921 -2593 -2860 -2871 -2365 -2141 -4427 -1530 -2168 -3114 -2587 -2905 -3349 -4346 -2035 -2979 -2232 -3252 -2332 -2317 -3061 -4865 -1035 -2475 -3493 -2763 -2491 -2275 -3388 -3592 -5302 -3719 -3046 -3266 -1908 -2500 -3447 -2937 -1607 -2943 -3281 -2568 -2704 -2959 -3788 -3144 -4256 -3910 -4041 -1981 -1240 -2347 -1763 -1580 -1761 -2957 -2164 -4682 -2793 -2492 -3463 -2179 -2565 -1975 -2874 -1435 -2867 -4149 -1281 -2988 -2008 -2991 -2280 -1705 -1893 -2824 -2843 -3873 -2861 -1499 -3299 -2717 -3937 -2569 -1636 -1306 -2932 -2192 -1230 -2065 -3535 -3190 -3591 -3793 -3434 -2621 -1872 -1766 -1720 -3545 -2753 -3191 -3693 -2588 -3568 -3649 -4122 -4325 -1673 -3888 -2691 -2617 -1740 -1907 -1829 -3271 -3552 -2303 -3271 -2349 -2662 -2392 -2447 -1312 -2888 -1594 -2633 -2565 -3237 -2313 -1406 -3231 -2871 -2813 -2250 -3916 -2517 -3435 -3313 -3574 -2786 -1903 -4184 -3230 -2761 -3583 -1863 -3151 -5072 -2389 -1908 -1827 -4080 -3315 -4280 -2741 -4011 -2906 -2293 -2677 -2880 -1797 -2007 -2138 -2432 -1616 -3117 -3266 -2209 -2626 -3262 -1654 -1859 -2137 -2663 -1286 -2794 -2687 -4775 -3657 -2847 -3738 -2904 -3182 -3094 -2702 -3727 -3055 -3689 -2072 -2551 -1398 -2571 -4301 -1943 -3332 -4473 -2622 -2005 -3458 -1764 -3039 -2171 -3154 -1956 -2867 -2185 -2944 -2498 -2717 -4742 -3218 -1604 -1923 -3043 -2318 -2586 -2249 -2088 -2372 -3071 -3238 -2968 -1639 -1749 -4055 -3125 -1638 -2086 -3283 -3382 -2906 -3400 -2631 -3050 -2163 -2819 -3902 -2588 -2039 -3220 -4082 -3752 -2514 -2798 -3483 -1620 -3075 -2250 -2005 -2114 -1907 -2521 -1575 -1627 -3814 -3137 -3563 -2706 -2641 -2277 -4149 -2971 -2307 -3582 -2287 -1603 -3604 -2961 -2907 -2489 -1612 -2761 -1430 -2886 -3069 -2997 -3438 -2436 -2427 -3752 -1748 -2034 -1990 -1853 -3480 -2428 -2656 -4022 -2845 -1784 -2710 -2755 -2549 -1397 -4171 -2732 -4816 -2545 -3114 -2315 -2302 -2093 -2134 -2791 -2763 -2142 -2552 -2987 -2130 -1535 -4669 -1691 -3736 -3238 -2043 -4021 -2143 -2561 -3666 -4382 -1825 -2692 -2173 -3862 -2248 -2177 -3534 -1418 -3433 -2346 -3267 -2088 -2382 -3310 -3371 -4389 -2947 -2208 -2976 -1978 -1887 -1784 -1868 -1423 -3221 -3275 -1572 -1735 -4070 -4020 -1737 -4614 -2027 -3007 -2842 -2563 -1367 -2170 -2819 -2620 -1774 -1116 -3054 -3798 -1373 -3861 -3272 -2142 -1663 -3029 -2408 -3379 -4802 -1760 -2904 -1306 -3860 -3479 -3744 -3544 -3776 -2617 -2460 -2004 -1993 -2053 -2089 -1985 -2224 -4008 -2276 -2909 -2336 -2804 -1924 -1828 -4022 -2372 -2083 -1444 -3129 -2800 -2773 -2163 -1585 -2500 -2973 -4360 -2957 -2600 -2701 -2362 -3513 -2423 -1368 -2384 -2238 -3097 -2320 -1842 -2028 -2153 -2202 -2629 -3446 -1434 -3861 -1932 -2839 -2684 -1935 -2510 -3613 -2444 -2031 -3178 -2716 -2459 -3038 -4481 -3219 -2566 -2037 -3321 -1834 -2901 -1582 -2774 -2877 -2497 -2447 -3509 -2811 -3838 -2844 -2999 -2596 -2747 -2072 -3123 -1275 -2070 -2309 -2320 -2400 -3190 -1563 -1657 -2947 -3856 -2856 -2861 -4053 -2551 -2867 -1519 -2336 -2019 -2053 -2179 -3071 -2479 -1139 -2391 -3494 -1749 -2261 -1916 -1672 -4583 -4045 -3496 -1976 -1212 -2543 -3813 -2724 -4491 -3029 -1860 -2575 -3899 -3316 -2148 -2077 -2551 -2574 -2582 -1889 -2170 -4150 -2501 -3216 -1898 -2640 -3195 -1994 -2759 -2825 -2594 -2358 -2753 -2464 -1594 -2321 -1133 -4613 -2312 -3747 -3818 -3044 -2282 -2936 -2539 -3413 -2793 -3875 -3906 -2737 -2577 -2580 -3753 -3411 -2247 -3265 -1906 -1458 -3943 -2533 -1567 -3663 -3816 -1635 -3515 -1931 -3943 -2249 -3326 -2388 -3867 -3812 -2301 -2126 -5356 -3030 -3751 -2589 -3806 -3315 -3039 -1682 -2953 -3160 -3026 -3853 -3628 -2807 -3290 -1892 -3929 -3303 -3144 -4671 -3334 -2402 -2778 -2725 -2383 -3559 -2446 -2133 -3372 -3261 -3266 -3425 -2275 -3160 -3098 -1894 -1553 -1958 -3839 -3012 -2817 -4603 -2765 -2481 -2618 -3082 -2838 -2294 -2253 -2134 -2134 -2187 -3468 -3227 -3753 -2682 -3308 -3685 -3018 -3211 -3286 -4077 -1381 -1462 -1998 -4009 -2720 -1964 -3830 -2351 -3682 -1626 -2335 -4719 -2260 -2775 -2147 -2514 -2840 -1542 -3986 -5170 -1988 -2914 -2816 -2394 -1748 -1568 -1939 -2103 -3825 -3527 -2787 -3941 -2149 -3000 -1904 -1912 -2272 -1613 -2356 -2901 -1356 -2200 -2256 -2565 -5051 -3448 -2044 -2660 -3112 -1903 -3207 -4253 -3204 -2115 -2262 -3400 -3258 -2667 -3714 -3004 -2668 -3905 -4264 -4030 -1319 -1689 -1807 -2132 -2596 -2111 -2979 diff --git a/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/trained_ddqn/best.pt b/examples/benchmarks/theory/experiments/results/n50_power_of_2/k5/trained_ddqn/best.pt deleted file mode 100644 index 92ba40ccf3c08df12c7f0a59c5b4b948d9c48cd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13847 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 diff --git a/examples/benchmarks/theory/experiments/test_conf.yml b/examples/benchmarks/theory/experiments/test_conf.yml deleted file mode 100644 index 91be4ac98..000000000 --- a/examples/benchmarks/theory/experiments/test_conf.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: "Theory" -discrete_action: True -action_choices: [1, 17, 33] -problem: "LeadingOne" -instance_set_path: "lo_rls_50_random.csv" diff --git a/examples/benchmarks/theory/experiments/test_conf_non_discrete.yml b/examples/benchmarks/theory/experiments/test_conf_non_discrete.yml deleted file mode 100644 index c09650ed6..000000000 --- a/examples/benchmarks/theory/experiments/test_conf_non_discrete.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: "Theory" -discrete_action: False -min_action: 1 -max_action: 49 -problem: "LeadingOne" -instance_set_path: "lo_rls_50_random.csv" - diff --git a/examples/benchmarks/theory/experiments/train_conf.yml b/examples/benchmarks/theory/experiments/train_conf.yml deleted file mode 100755 index a8bdfb526..000000000 --- a/examples/benchmarks/theory/experiments/train_conf.yml +++ /dev/null @@ -1,29 +0,0 @@ -experiment: - n_cores: 1 - log_level: 1 - n_episodes: 100000 - n_steps: 2000000 - save_interval: 2000 - eval_interval: 2000 - eval_n_episodes: 50 - -bench: - name: "Theory" - discrete_action: True - action_choices: [1, 17, 33] - problem: "LeadingOne" - instance_set_path: "lo_rls_50_random.csv" - observation_description: "n,f(x)" - reward_choice: "imp_minus_evals" - seed: 0 - -eval_env: - reward_choice: "minus_evals" - -agent: - name: "ddqn_local" - epsilon: 0.2 - begin_learning_after: 10000 - batch_size: 2048 - gamma: 0.9998 - diff --git a/examples/benchmarks/theory/scripts/calculate_optimal_policy/calculatePolicy.d b/examples/benchmarks/theory/scripts/calculate_optimal_policy/calculatePolicy.d deleted file mode 100644 index 046e2126b..000000000 --- a/examples/benchmarks/theory/scripts/calculate_optimal_policy/calculatePolicy.d +++ /dev/null @@ -1,13 +0,0 @@ -module app; - -public import data_management; - -import std.conv; - -void main(string[] args) -{ - const int n = args[1].to!(int); - const int[] portfolio = args[2 .. $].to!(int[]); - - writeln(portfolio.determineOptimalBreakingPoints(n)[1 .. $]); -} \ No newline at end of file diff --git a/examples/benchmarks/theory/scripts/calculate_optimal_policy/compile.sh b/examples/benchmarks/theory/scripts/calculate_optimal_policy/compile.sh deleted file mode 100755 index 7631d0337..000000000 --- a/examples/benchmarks/theory/scripts/calculate_optimal_policy/compile.sh +++ /dev/null @@ -1,5 +0,0 @@ -dComplier="dmd.2.100.0.linux" -wget https://s3.us-west-2.amazonaws.com/downloads.dlang.org/releases/2022/$dComplier.tar.xz -tar -xf $dComplier.tar.xz -dmd2/linux/bin64/dmd -O -release ./calculatePolicy.d ./data_management.d ./eas.d - diff --git a/examples/benchmarks/theory/scripts/calculate_optimal_policy/data_management.d b/examples/benchmarks/theory/scripts/calculate_optimal_policy/data_management.d deleted file mode 100644 index 27b4474b3..000000000 --- a/examples/benchmarks/theory/scripts/calculate_optimal_policy/data_management.d +++ /dev/null @@ -1,526 +0,0 @@ -module data_management; - -public import eas; - -/** - * The different options for functions that return policies. - */ -enum PickerName -{ - RANDOM = "random", - OPTIMAL = "optimal", -} - -/** - * The different options for policies to choose from. - */ -enum PortfolioName -{ - POWERS_OF_TWO = "powers_of_2", - INITIAL_SEGMENT = "initial_segment", - EVENLY_SPREAD = "evenly_spread", - OPTIMAL = "optimal_portfolio", -} - -/** - * The different options for where data can lie. Each option denotes a top-level - * directory that is then followed by the ›path‹ provided in ›FileData‹. - */ -enum DirectoryType -{ - EXPERIMENTS = "experiments", - EVALUATION = "evaluation", - INFORMATION = "information", - VISUALIZATION = "visualization", -} - -/** - * The different options for what compound data to use. - */ -enum CompoundType -{ - POLICIES = "policies", -} - -/** - * The different options for what data is used for the visualization. - */ -enum VisualizationDataSource -{ - EMPIRICAL = "empirical", - OPTIMAL = "optimal", -} - -/** - * The different options for what visualization is chosen. - */ -enum VisualizationType -{ - VARY_K = "vary_k", - VARY_N = "vary_n", -} - - -// ****************** -// ** Helper Stuff ** -// ****************** - -/** - * Used for communicating different cases to run or evaluate. - */ -struct TestCase -{ - int n; - int portfolioSize; - PortfolioName portfolioName; - PickerName pickerName; -} - -/** - * Used for communicating different cases to visualize. - */ -struct PlotCase -{ - int[] nValues; - int[] kValues; - PortfolioName portfolioName; - PickerName pickerName; - VisualizationType visualizationType; - VisualizationDataSource visualizationDataSource; -} - -/** - * Used for storing information about file locations. - */ -struct FileData -{ - string path; - string fileName; - string filePath; -} - -/** - * Returns file data for a specific setting, not requiring a PickerName. - * Creates the directory if it is not already present. - */ -FileData getShortFileData(in DirectoryType directoryType, in int n, in int portfolioSize, - in PortfolioName portfolioName) -{ - auto path = directoryType ~ dirSeparator ~ "k=" ~ portfolioSize.text() ~ dirSeparator; - mkdirRecurse(path); - auto fileName = "n=" ~ n.text() ~ "_" ~ portfolioName; - auto filePath = path ~ fileName; - return FileData(path, fileName, filePath); -} - -/** - * Returns file data for a specific setting, requiring a PickerName. - * Creates the directory if it is not already present. - */ -FileData getFileData(in DirectoryType directoryType, in int n, in int portfolioSize, in PortfolioName portfolioName, - in PickerName pickerName) -{ - auto fileData = getShortFileData(directoryType, n, portfolioSize, portfolioName); - auto path = fileData.path; - auto fileName = fileData.fileName ~ "_" ~ pickerName; - auto filePath = path ~ fileName; - return FileData(path, fileName, filePath); -} - -/** - * Returns file data for compound information. - * Creates the directory if it is not already present. - */ -FileData getCompoundInformationFileData(in int n, in PortfolioName portfolioName, in CompoundType compoundType) -{ - auto path = DirectoryType.INFORMATION ~ dirSeparator ~ compoundType ~ dirSeparator; - mkdirRecurse(path); - auto fileName = "n=" ~ n.text() ~ "_" ~ portfolioName; - auto filePath = path ~ fileName; - return FileData(path, fileName, filePath); -} - -/** - * Returns file data for visualization purposes. Requires to determine the type of visualization and the data source. - * Creates the directory if it is not already present. - */ -FileData getVisualizationFileData(in int fixedValue, in PortfolioName portfolioName, in PickerName pickerName, - in VisualizationType visualizationType, in VisualizationDataSource visualizationDataSource) -{ - auto path = DirectoryType.VISUALIZATION ~ dirSeparator ~ "plot_data" ~ dirSeparator; - auto fileName = ""; - final switch(visualizationType) - { - with(VisualizationType) - { - case VARY_K: - case VARY_N: - path ~= visualizationType ~ dirSeparator ~ visualizationDataSource ~ dirSeparator; - fileName ~= ((visualizationType == VARY_K) ? "n" : "k"); - fileName ~= "=" ~ fixedValue.text() ~ "_" ~ portfolioName; - if(visualizationDataSource == VisualizationDataSource.EMPIRICAL) - { - fileName ~= "_" ~ pickerName; - } - break; - } - } - mkdirRecurse(path); - auto filePath = path ~ fileName; - return FileData(path, fileName, filePath); -} - -/** - * Determines the portfolio, given the portfolio name. Returns it in descending order. - */ -int[] calculatePortfolio(in int n, in int portfolioSize, in PortfolioName portfolioName) -{ - int[] portfolio = () - { - with(PortfolioName) - { - final switch(portfolioName) - { - case POWERS_OF_TWO: - return iota(0, portfolioSize).map!(e => 2 ^^ e)().array(); - case INITIAL_SEGMENT: - return iota(1, portfolioSize + 1).array(); - case EVENLY_SPREAD: - return iota(0, portfolioSize).map!(e => e * (n / portfolioSize) + 1)().array(); - case OPTIMAL: - return bruteForceOptimalPortfolio(n, portfolioSize); - } - } - }(); - portfolio.sort!("a > b")(); - return portfolio; -} - - -// ******************* -// ** Visualization ** -// ******************* - -/** - * Produces visualization data for multiple tests at once, given as an array of test cases. - * Requires results from runs to be present. If not, no evaluation is generated. - */ -void generateMultiplePlotData(in PlotCase[] plotCases) -{ - foreach(plotCase; plotCases) - { - generatePlotData(plotCase); - } -} - -/** - * Generates visualization data used for a plot. If one value is varied, for the other value, the first element - * of the array is chosen. - */ -void generatePlotData(in PlotCase plotCase) -{ - final switch(plotCase.visualizationType) - { - with(VisualizationType) - { - case VARY_K: - const n = plotCase.nValues[0]; - const visualizationFileData = getVisualizationFileData(n, plotCase.portfolioName, - plotCase.pickerName, plotCase.visualizationType, plotCase.visualizationDataSource); - auto visualizationFile = File(visualizationFileData.filePath, "w"); - final switch(plotCase.visualizationDataSource) - { - case VisualizationDataSource.EMPIRICAL: - visualizationFile.writeln("k avg lq med uq"); - foreach(k; plotCase.kValues) - { - const evaluationFileData = getFileData(DirectoryType.EVALUATION, n, k, - plotCase.portfolioName, plotCase.pickerName); - if(!exists(evaluationFileData.filePath)) - { - continue; - } - const evaluationContent = readText(evaluationFileData.filePath).split("\n")[1]; - visualizationFile.write(k, " ", evaluationContent); - } - return; - case VisualizationDataSource.OPTIMAL: - visualizationFile.writeln("k rel-rt"); - foreach(k; plotCase.kValues) - { - const informationFileData = getShortFileData(DirectoryType.INFORMATION, n, k, - plotCase.portfolioName); - if(!exists(informationFileData.filePath)) - { - continue; - } - const optimalRunTime = readText(informationFileData.filePath).split("\n")[3] - .split(" ")[$ - 1].strip().to!(double); - visualizationFile.writeln(k, " ", optimalRunTime / (n ^^ 2)); - } - return; - } - assert(false); - case VARY_N: - const portfolioSize = plotCase.kValues[0]; - const visualizationFileData = getVisualizationFileData(portfolioSize, plotCase.portfolioName, - plotCase.pickerName, plotCase.visualizationType, plotCase.visualizationDataSource); - auto visualizationFile = File(visualizationFileData.filePath, "w"); - final switch(plotCase.visualizationDataSource) - { - case VisualizationDataSource.EMPIRICAL: - visualizationFile.writeln("n avg lq med uq"); - foreach(n; plotCase.nValues) - { - const evaluationFileData = getFileData(DirectoryType.EVALUATION, n, portfolioSize, - plotCase.portfolioName, plotCase.pickerName); - if(!exists(evaluationFileData.filePath)) - { - continue; - } - const evaluationContent = readText(evaluationFileData.filePath).split("\n")[1]; - visualizationFile.write(n, " ", evaluationContent); - } - return; - case VisualizationDataSource.OPTIMAL: - visualizationFile.writeln("n rel-rt"); - foreach(n; plotCase.nValues) - { - const informationFileData = getShortFileData(DirectoryType.INFORMATION, n, portfolioSize, - plotCase.portfolioName); - if(!exists(informationFileData.filePath)) - { - continue; - } - const optimalRunTime = readText(informationFileData.filePath).split("\n")[3] - .split(" ")[$ - 1].strip().to!(double); - visualizationFile.writeln(n, " ", optimalRunTime / (n ^^ 2)); - } - return; - } - assert(false); - } - } - assert(false); -} - - -// ***************** -// ** Information ** -// ***************** - -/** - * Generates information for all the provided test cases. - */ -void generateInformation(in TestCase[] testCases) -{ - foreach(testCase; testCases) - { - calculateInformation(testCase.n, testCase.portfolioSize, testCase.portfolioName); - } -} - -/** - * Generates compound information for all the provided values of n. For each, it does so for - * all values of k. - */ -void generateCompoundInformation(in int[] nValues, in int[] kValues, in PortfolioName[] portfolioNames, - in CompoundType compoundType) -{ - foreach(n; nValues) - { - foreach(portfolioName; portfolioNames) - { - gatherCompoundInformation(n, kValues, portfolioName, compoundType); - } - } -} - -/** - * Calculates for the specified setting what its portfolio, optimal policy, and optimal expected run time are. Writes them into a file. - */ -void calculateInformation(in int n, in int portfolioSize, in PortfolioName portfolioName) -{ - auto portfolio = calculatePortfolio(n, portfolioSize, portfolioName); - // Abort if the portfolio is invalid. - if(portfolio[0] > n) - { - return; - } - auto informationFileData = getShortFileData(DirectoryType.INFORMATION, n, portfolioSize, portfolioName); - auto informationFile = File(informationFileData.filePath, "w"); - auto optimalBreakingPoints = determineOptimalBreakingPoints(portfolio, n)[1 .. $]; - auto optimalRunTime = determineOptimalRunTime(portfolio, n); - informationFile.writeln("portfolio: ", portfolio); - informationFile.writeln("optimal policy: ", optimalBreakingPoints); - informationFile.writeln("optimal policy relative: ", optimalBreakingPoints.map!(point => point / (n + 0.0))()); - informationFile.writeln("optimal expected run time: ", optimalRunTime); - informationFile.writeln("relative optimal expected run time: ", optimalRunTime / (n ^^ 2)); - informationFile.writef("%(%d,%); ", portfolio.dup.reverse()); - informationFile.writefln("%(%d,%)", optimalBreakingPoints.reverse()); -} - -/** - * Gather for the specified compound type the respective information. - */ -void gatherCompoundInformation(in int n, in int[] kValues, in PortfolioName portfolioName, in CompoundType compoundType) -{ - auto compoundInformationFileData = getCompoundInformationFileData(n, portfolioName, compoundType); - auto compoundInformationFile = File(compoundInformationFileData.filePath, "w"); - final switch(compoundType) - { - with(CompoundType) - { - case POLICIES: - foreach(portfolioSize; kValues) - { - auto informationFileData = getShortFileData(DirectoryType.INFORMATION, n, portfolioSize, - portfolioName); - if(!exists(informationFileData.filePath)) - { - continue; - } - auto policyData = readText(informationFileData.filePath).split("\n")[5]; - compoundInformationFile.write(policyData); - } - return; - } - } - assert(false); -} - -/** - * Calculates the data required for a cumulative plot of the data for all optimal policies. - */ -void calculateCumulativeOptimalPolicyData(in int n, in int portfolioSize) -{ - const path = DirectoryType.INFORMATION ~ dirSeparator ~ "all_optimal_policies" ~ dirSeparator; - const fileName = "n=" ~ n.text() ~ "_" ~ "k=" ~ portfolioSize.text(); - const filePath = path ~ fileName; - if(!exists(filePath)) - { - return; - } - auto policyData = readText(filePath).split("\n")[1 .. $ - 1] - .map!(line => line.split(" "))().array(); - policyData.sort!((a, b) => a[0].to!(double) < b[0].to!(double))(); - - const outputPath = DirectoryType.INFORMATION ~ dirSeparator ~ "cumulative_optimal_policies" ~ dirSeparator; - mkdirRecurse(outputPath); - auto outputFile = File(outputPath ~ fileName, "w"); - outputFile.writeln("relative_run_time relative_amount portfolio"); - foreach(index, policyEntry; policyData) - { - outputFile.write(policyEntry[0].to!(double) / (n ^^ 2), " ", (index + 1.0) / policyData.length, " ", - policyEntry[1 .. $].join()); - } -} - - -// **************** -// ** Evaluation ** -// **************** - -/** - * Evaluate multiple tests at once, given as an array of test cases. - * Requires results from runs to be present. If not, no evaluation is generated. - */ -void evaluateDifferentRLSTests(in TestCase[] testCases) -{ - foreach(testCase; testCases) - { - evaluateRuns(testCase.n, testCase.portfolioSize, testCase.portfolioName, testCase.pickerName); - } -} - -/** - * Evaluates the data produced by runs. Just returns if no such data is present. Calculates the average of this data. - */ -void evaluateRuns(in int n, in int portfolioSize, in PortfolioName portfolioName, in PickerName pickerName) -{ - auto experimentsFileData = getFileData(DirectoryType.EXPERIMENTS, n, portfolioSize, portfolioName, pickerName); - auto evaluationsFileData = getFileData(DirectoryType.EVALUATION, n, portfolioSize, portfolioName, pickerName); - if(!exists(experimentsFileData.filePath)) - { - return; - } - auto experimentsFile = File(experimentsFileData.filePath); - - auto lines = experimentsFile.byLineCopy() - .array() - .map!(l => l.strip.to!(int))() - .array() - .sort() - .array(); - auto evaluationFile = File(evaluationsFileData.filePath, "w"); - evaluationFile.writeln("avg lq med uq"); - evaluationFile.writeln - ( - lines.sum() / lines.length, " ", - lines[cast(int) (0.25 * n)], " ", - lines[cast(int) (0.50 * n)], " ", - lines[cast(int) (0.75 * n)], - ); -} - - -// *********** -// ** Tests ** -// *********** - -/** - * Run multiple tests at once, given as an array of test cases. - */ -void runDifferentRLSTests(in TestCase[] testCases, in int numberOfRuns) -{ - foreach(testCase; testCases) - { - runRLSTests(testCase.n, testCase.portfolioSize, testCase.portfolioName, testCase.pickerName, numberOfRuns); - } -} - -/** - * Runs the provided RLS variant with the given portfolio and policy for the given number of times. - */ -void runRLSTests(in int n, in int portfolioSize, in PortfolioName portfolioName, in PickerName pickerName, - in int numberOfRuns) -{ - // Choose the correct portfolio and mutation picker. - const portfolio = calculatePortfolio(n, portfolioSize, portfolioName); - // Abort if the portfolio contains invalid (i.e., too large) mutation rates. - if(portfolio[0] > n) - { - return; - } - - MutationPicker mutationPicker = () - { - with(PickerName) - { - final switch(pickerName) - { - case RANDOM: - return getUniformPicker(portfolio); - case OPTIMAL: - return getOptimalPicker(portfolio, n); - } - } - }(); - - // Set up the file. - auto experimentsFileData = getFileData(DirectoryType.EXPERIMENTS, n, portfolioSize, portfolioName, pickerName); - auto file = File(experimentsFileData.filePath, "w"); - file.close(); - - // Run tests in parallel. - foreach(_; iota(numberOfRuns).parallel()) - { - auto numberOfIterations = rlsWithSchedule(n, mutationPicker); - synchronized - { - file.open(experimentsFileData.filePath, "a"); - file.writeln(numberOfIterations); - file.close(); - } - } -} \ No newline at end of file diff --git a/examples/benchmarks/theory/scripts/calculate_optimal_policy/eas.d b/examples/benchmarks/theory/scripts/calculate_optimal_policy/eas.d deleted file mode 100644 index ec8ec29fd..000000000 --- a/examples/benchmarks/theory/scripts/calculate_optimal_policy/eas.d +++ /dev/null @@ -1,316 +0,0 @@ -module eas; - -public import std.algorithm.iteration; -public import std.algorithm.mutation; -public import std.algorithm.sorting; -public import std.bitmanip; -public import std.conv; -public import std.file; -public import std.parallelism; -public import std.path; -public import std.random; -public import std.range; -public import std.stdio; -public import std.string; - -alias Individual = BitArray; -alias MutationPicker = int delegate(in int); - -// ********************* -// ** Portfolio Stuff ** -// ********************* - -/** - * Determines an optimal portfolio via brute force. Note that 1 is always included in the portfolio. - * Saves the data collected in a file. - */ -int[] bruteForceOptimalPortfolio(in int n, in int portfolioSize) -in -{ - assert(portfolioSize >= 1 && portfolioSize <= n, "The portfolio size is incorrect."); -} -body -{ - import data_management; - const path = DirectoryType.INFORMATION ~ dirSeparator ~ "all_optimal_policies" ~ dirSeparator; - mkdirRecurse(path); - const fileName = "n=" ~ n.text() ~ "_" ~ "k=" ~ portfolioSize.text(); - auto file = File(path ~ fileName, "w"); - file.writeln("run_time portfolio"); - - int[] bestPortfolio = []; - auto bestRunTime = double.infinity; - - // Call with a portfolio of [1]. - void stackedForLoops(in int layers, int[] portfolio) - { - auto newPortfolio = portfolio; - if(layers > 1) - { - foreach(mutationRate; portfolio[$ - 1] + 1 .. n + 1) - { - stackedForLoops(layers - 1, newPortfolio ~ [mutationRate]); - } - } - else - { - const currentRunTime = determineOptimalRunTime(newPortfolio, n); - file.writeln(currentRunTime, " ", newPortfolio); - if(currentRunTime < bestRunTime) - { - bestRunTime = currentRunTime; - bestPortfolio = newPortfolio; - } - } - } - - stackedForLoops(portfolioSize, [1]); - - return bestPortfolio; -} - -/** - * Determines the optimal run time for a given portfolio in a setting of size n. - */ -double determineOptimalRunTime(in int[] portfolioIn, in int n) -{ - // Sort the portfolio descendingly; - auto portfolio = portfolioIn.dup; - portfolio.sort!("a > b")(); - auto breakingPoints = portfolio.determineOptimalBreakingPoints(n); - - // Concatenate the portfolio with the breaking points. - auto zippedArrays = zip([-1] ~ portfolio, breakingPoints) - .uniq!((a, b) => a[1] == b[1])() - .array; - - // Calculate the optimal run time. - double optimalRunTime = 0.0; - foreach(i; 0 .. zippedArrays.length - 1) // @suppress(dscanner.suspicious.length_subtraction) - { - auto currentNumberOfBitsToFlip = zippedArrays[i + 1][0]; - auto startingIndexExclusive = zippedArrays[i][1]; - auto endingIndexInclusive = zippedArrays[i + 1][1]; - foreach(fitness; startingIndexExclusive + 1 .. endingIndexInclusive + 1) - { - auto probabilityOfImprovement = improvementProbability(n, currentNumberOfBitsToFlip, fitness); - optimalRunTime += 1.0 / probabilityOfImprovement; - } - } - return 0.5 * optimalRunTime; -} - -/** - * Given a portfolio of decreasing mutation strengths, this function determines the breaking points - * that result in the lowest possible expected run time. - */ -int[] determineOptimalBreakingPoints(in int[] portfolio, in int n) -in -{ - assert(portfolio.isSorted!("a > b"), "The portfolio is not sorted."); - assert(portfolio.length >= 1 && portfolio.length <= n, "The portfolio size is incorrect."); -} -body -{ - auto portfolioCardinality = cast(int) portfolio.length; - - // Note that the first and the last breaking points are set. There is one more breaking point that - // the size of the portfolio. - auto breakingPoints = new int[](portfolioCardinality + 1); - breakingPoints[0] = -1; - breakingPoints[portfolioCardinality] = n - 1; - foreach(i; 1 .. portfolioCardinality) - { - breakingPoints[i] = determineBreakingPoint(portfolio[i - 1], portfolio[i], n); - } - return breakingPoints; -} - -/** - * Determine the breaking point of two values. This is the largest index [0 .. n - 1] such that the larger input has - * an improvement quality of at least the smaller input. - */ -int determineBreakingPoint(in int larger, in int smaller, in int n) -{ - int breakingPoint = 0; - foreach(i; 1 .. n) - { - if(improvementProbability(n, larger, i) < improvementProbability(n, smaller, i)) - { - break; - } - breakingPoint = i; - } - return breakingPoint; -} - -/** - * The probability of an improvement on LO with n bits when exactly k bits are flipped and the current fitness is i. - */ -double improvementProbability(in int n, in int k, in int i) -{ - double improvementProbability = (k + 0.0) / n; - foreach(j; 1 .. k) - { - improvementProbability *= (n - j - i + 0.0) / (n - j); - } - return improvementProbability; -} - - -// ******************** -// ** Schedule Stuff ** -// ******************** - -/** - * Returns a delegate that chosses one of the mutation strengths of the portfolio uniformly at random. - */ -MutationPicker getUniformPicker(in int[] portfolio) -{ - int chooseUniformMutationStrength(in int) - { - auto indexOfChosenPosition = uniform(0, portfolio.length); - return portfolio[indexOfChosenPosition]; - } - return &chooseUniformMutationStrength; -} - -/** - * Returns a delegate that chooses for a given fitness the best mutation strength out of the given portfolio. - */ -MutationPicker getOptimalPicker(in int[] portfolio, in int n) -{ - // Remove the first entry of the optimal breaking points, which is always -1. - auto optimalBreakingPoints = determineOptimalBreakingPoints(portfolio, n)[1 .. $]; - int chooseOptimalMutationStrength(in int fitness) - { - foreach(index, breakingPoint; optimalBreakingPoints) - { - if(fitness <= breakingPoint) - { - return portfolio[index]; - } - } - // Since the last entry of the breaking points is always n - 1, the loop - // cannot be exited without the return statement. - assert(false); - } - return &chooseOptimalMutationStrength; -} - - -// *************** -// ** RLS Stuff ** -// *************** - -/** - * A variant of RLS that chooses each iteration how many bits to flip based on the provided delegate. - * The delegate receives a fitness value as input and returns a number of bits to flip as output. - */ -int rlsWithSchedule(in int n, MutationPicker chooseMutationRate) -{ - auto individual = generateUniformIndividual(n); - auto numberOfIterations = 0; - while(!isOptimal(individual)) - { - auto fitness = individual.leadingOnesFitness(); - auto numberOfBitsToFlip = chooseMutationRate(fitness); - auto offspring = individual.generateOffspring(numberOfBitsToFlip); - if(offspring.leadingOnesFitness() >= fitness) - { - individual = offspring; - } - numberOfIterations++; - } - return numberOfIterations; -} - -/** - * Generates an offspring of an individual by flipping exactly the specified number of bits. - */ -Individual generateOffspring(in Individual parent, in int numberOfBitsToFlip) -{ - // Generate a copy of the parent and flip the respective bits. - auto offspring = parent.dup; - kFlipMutation(offspring, numberOfBitsToFlip); - return offspring; -} - -/** - * Flips exactly k bits in the provided individual. - */ -void kFlipMutation(ref Individual individual, size_t k) -{ - const n = individual.length; - assert(k <= n, "Too many bits need to be flipped."); - - /* - This function is optimized for performance. - We use rejection sampling and try to check quickyl for duplicates - without allocating too much memory. - */ - auto indicesAlreadyChosen = new size_t[k]; - bool alreadyChosen; - size_t indexToCheck; - foreach(index; iota(k)) - { - auto flipPosition = uniform(0, individual.length); - if(index > 0) - { - do - { - alreadyChosen = false; - for(indexToCheck = 0; indexToCheck < index; indexToCheck++) - { - if(flipPosition == indicesAlreadyChosen[indexToCheck]) - { - alreadyChosen = true; - flipPosition = uniform(0, individual.length); - break; - } - } - } - while(alreadyChosen); - } - indicesAlreadyChosen[index] = flipPosition; - individual[flipPosition] = 1 - individual[flipPosition]; - } -} - -/** - * Generates an individual whose bits are chosen uniformly at random. - */ -Individual generateUniformIndividual(in int n) -{ - auto individual = Individual(new bool[n]); - foreach(ref bit; individual) - { - bit = ((uniform01() < 0.5) ? 0 : 1); - } - return individual; -} - -/** - * Returns the number of leading 1s of the given individual. - */ -int leadingOnesFitness(in Individual individual) -{ - auto fitness = 0; - foreach(bit; individual) - { - if(bit == 0) - { - break; - } - fitness++; - } - return fitness; -} - -/** - * Returns whether the given individual is optimal for LeadingOnes. - */ -bool isOptimal(in Individual individual) -{ - return (individual.leadingOnesFitness == individual.length); -} \ No newline at end of file diff --git a/examples/benchmarks/theory/scripts/calculate_optimal_policy/run.py b/examples/benchmarks/theory/scripts/calculate_optimal_policy/run.py deleted file mode 100644 index 4b94c0fa2..000000000 --- a/examples/benchmarks/theory/scripts/calculate_optimal_policy/run.py +++ /dev/null @@ -1,66 +0,0 @@ -import sys -import os -import subprocess - -scriptDir = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(scriptDir) - - -def run_cmd(cmd): - p = subprocess.run( - cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True - ) - output = p.stdout.decode("utf-8") - return output, p.returncode - - -def calculate_optimal_policy(n: int, portfolio: [int]): - # call Martin's D code to get the optimal policy - portfolio = sorted(portfolio, reverse=True) - cmd = f"{scriptDir}/calculatePolicy {n} {' '.join([str(x) for x in portfolio])}" - output, rc = run_cmd(cmd) - assert rc == 0, f"ERROR: fail to run command: {cmd}" - assert n > 0, f"ERROR: problem size must be a positive integer" - breakPoints = [ - int(s.strip()) for s in output.replace("[", "").replace("]", "").split(",") - ] - assert len(breakPoints) == len(portfolio) - - # remove radius that are not used (due to duplicated breaking points) - newPort = [] - newBreakPoints = [] - for i in range(len(breakPoints)): - skip = False - if i > 0: - if breakPoints[i] == breakPoints[i - 1]: - skip = True - else: - assert breakPoints[i] > breakPoints[i - 1] - if skip: - continue - newPort.append(portfolio[i]) - newBreakPoints.append(breakPoints[i]) - - # parse the optimal policy to an array of radiuses ([0..n-1]) - policy = [] - previousBP = -1 - for i in range(len(newPort)): - policy.extend([newPort[i]] * (newBreakPoints[i] - previousBP)) - previousBP = newBreakPoints[i] - - assert len(policy) == n - return policy - - -def main(): - assert ( - len(sys.argv) == 3 - ), "Usage: python calculate_optimal_policy.py . \nExample: python calculate_optimal_policy.py 50 1,17,33" - n = int(sys.argv[1]) - portfolio = [int(s.strip()) for s in sys.argv[2].split(",")] - p = calculate_optimal_policy(n, portfolio) - print(" ".join([str(x) for x in p])) - - -if __name__ == "__main__": - main() diff --git a/examples/benchmarks/theory/scripts/ddqn_local/ddqn.py b/examples/benchmarks/theory/scripts/ddqn_local/ddqn.py deleted file mode 100755 index 907e0cb40..000000000 --- a/examples/benchmarks/theory/scripts/ddqn_local/ddqn.py +++ /dev/null @@ -1,604 +0,0 @@ -import pickle -import gzip - -import scipy.signal -import numpy as np -import gym -import torch -import torch.nn as nn -import torch.optim as optim -import torch.nn.functional as F -from torch.autograd import Variable -from itertools import count -from collections import namedtuple -import time -import sys -import os -import json - -sys.path.append(os.path.dirname(__file__)) - -device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - - -def tt(ndarray): - """ - Helper Function to cast observation to correct type/device - """ - if device == "cuda": - return Variable(torch.from_numpy(ndarray).float().cuda(), requires_grad=False) - else: - return Variable(torch.from_numpy(ndarray).float(), requires_grad=False) - - -def soft_update(target, source, tau): - """ - Simple Helper for updating target-network parameters - :param target: target network - :param source: policy network - :param tau: weight to regulate how strongly to update (1 -> copy over weights) - """ - for target_param, param in zip(target.parameters(), source.parameters()): - target_param.data.copy_(target_param.data * (1.0 - tau) + param.data * tau) - - -def hard_update(target, source): - """ - See soft_update - """ - soft_update(target, source, 1.0) - - -class Q(nn.Module): - """ - Simple fully connected Q function. Also used for skip-Q when concatenating behaviour action and state together. - Used for simpler environments such as mountain-car or lunar-lander. - """ - - def __init__(self, state_dim, action_dim, non_linearity=F.relu, hidden_dim=50): - super(Q, self).__init__() - self.fc1 = nn.Linear(state_dim, hidden_dim) - self.fc2 = nn.Linear(hidden_dim, hidden_dim) - self.fc3 = nn.Linear(hidden_dim, action_dim) - self._non_linearity = non_linearity - - def forward(self, x): - x = self._non_linearity(self.fc1(x)) - x = self._non_linearity(self.fc2(x)) - return self.fc3(x) - - -class ReplayBuffer: - """ - Simple Replay Buffer. Used for standard DQN learning. - """ - - def __init__(self, max_size): - self._data = namedtuple( - "ReplayBuffer", - ["states", "actions", "next_states", "rewards", "terminal_flags"], - ) - self._data = self._data( - states=[], actions=[], next_states=[], rewards=[], terminal_flags=[] - ) - self._size = 0 - self._max_size = max_size - - def add_transition(self, state, action, next_state, reward, done): - self._data.states.append(state) - self._data.actions.append(action) - self._data.next_states.append(next_state) - self._data.rewards.append(reward) - self._data.terminal_flags.append(done) - self._size += 1 - - if self._size > self._max_size: - self._data.states.pop(0) - self._data.actions.pop(0) - self._data.next_states.pop(0) - self._data.rewards.pop(0) - self._data.terminal_flags.pop(0) - - def random_next_batch(self, batch_size): - batch_indices = np.random.choice(len(self._data.states), batch_size) - batch_states = np.array([self._data.states[i] for i in batch_indices]) - batch_actions = np.array([self._data.actions[i] for i in batch_indices]) - batch_next_states = np.array([self._data.next_states[i] for i in batch_indices]) - batch_rewards = np.array([self._data.rewards[i] for i in batch_indices]) - batch_terminal_flags = np.array( - [self._data.terminal_flags[i] for i in batch_indices] - ) - return ( - tt(batch_states), - tt(batch_actions), - tt(batch_next_states), - tt(batch_rewards), - tt(batch_terminal_flags), - ) - - def save(self, path): - with open(os.path.join(path, "rpb.pkl"), "wb") as fh: - pickle.dump(list(self._data), fh) - - def load(self, path): - with open(os.path.join(path, "rpb.pkl"), "rb") as fh: - data = pickle.load(fh) - self._data = namedtuple( - "ReplayBuffer", - ["states", "actions", "next_states", "rewards", "terminal_flags"], - ) - self._data.states = data[0] - self._data.actions = data[1] - self._data.next_states = data[2] - self._data.rewards = data[3] - self._data.terminal_flags = data[4] - self._size = len(data[0]) - - -class DQN: - """ - Simple double DQN Agent - """ - - def __init__( - self, - state_dim: int, - action_dim: int, - gamma: float, - env: gym.Env, - eval_env: gym.Env, - train_eval_env: gym.Env = None, - vision: bool = False, - out_dir: str = "./output/", - ): - - """ - Initialize the DQN Agent - :param state_dim: dimensionality of the input states - :param action_dim: dimensionality of the output actions - :param gamma: discount factor - :param env: environment to train on - :param eval_env: environment to evaluate on - :param eval_env: environment to evaluate on with training data - :param vision: boolean flag to indicate if the input state is an image or not - """ - if not vision: # For featurized states - self._q = Q(state_dim, action_dim).to(device) - self._q_target = Q(state_dim, action_dim).to(device) - else: # For image states, i.e. Atari - raise NotImplementedError - - self._eval_r_best = None - - self._gamma = gamma - self._loss_function = nn.MSELoss() - self._q_optimizer = optim.Adam(self._q.parameters(), lr=0.001) - self._action_dim = action_dim - - self._replay_buffer = ReplayBuffer(1e6) - self._env = env - self._eval_env = eval_env - self._train_eval_env = train_eval_env - self.out_dir = out_dir - - def save_rpb(self, path): - self._replay_buffer.save(path) - - def load_rpb(self, path): - self._replay_buffer.load(path) - - def get_action(self, x: np.ndarray, epsilon: float) -> int: - """ - Simple helper to get action epsilon-greedy based on observation x - """ - u = np.argmax(self._q(tt(x)).detach().numpy()) - r = np.random.uniform() - if r < epsilon: - return np.random.randint(self._action_dim) - return u - - def train( - self, - episodes: int, - max_env_time_steps: int = 1_000_000, - epsilon: float = 0.2, - eval_eps: int = 10, - eval_every_n_steps: int = 1000, - max_train_time_steps: int = 1_000_000, - begin_learning_after: int = 10_000, - batch_size: int = 2_048, - log_level=1, - save_best=True, - save_model_interval=1000, - ): - """ - Training loop - :param episodes: maximum number of episodes to train for - :param max_env_time_steps: maximum number of steps in the environment to perform per episode - :param epsilon: constant epsilon for exploration when selecting actions - :param eval_eps: numper of episodes to run for evaluation - :param eval_every_n_steps: interval of steps after which to evaluate the trained agent - :param max_train_time_steps: maximum number of steps to train - :param log_level: - (1) basic log: evaluation scores and evaluation episodes' infos - (2) extensive log: (1) and discounted rewards per episode (evaluation), average value-action estimate per episode (evaluation), average discounted rewards per episode (evaluation), average loss per batch - :return: - """ - total_steps = 0 - start_time = time.time() - - def write_info(obj, mode="a+"): - with gzip.open(os.path.join(self.out_dir, "eval_infos.gzip"), mode) as f: - pickle.dump(obj, f) - - def write_extra_log(obj, mode="a+"): - with gzip.open( - os.path.join(self.out_dir, "eval_extra_log.gzip"), mode - ) as f: - pickle.dump(obj, f) - - def write_train_log(obj, mode="a+"): - with gzip.open(os.path.join(self.out_dir, "train_log.gzip"), mode) as f: - pickle.dump(obj, f) - - for e in range(episodes): - # print('\033c') - # print('\x1bc') - # if e % 100 == 0: - # print("%s/%s" % (e + 1, episodes)) - s = self._env.reset() - ep_loss = [] - for t in range(max_env_time_steps): - a = self.get_action( - s, epsilon if total_steps > begin_learning_after else 1.0 - ) - ns, r, d, _ = self._env.step(a) - total_steps += 1 - print("#episodes=%d, #steps=%d" % (e + 1, total_steps), end="\r") - - ########### Begin Evaluation - if (total_steps % eval_every_n_steps) == 0: - # print('Begin Evaluation') - eval_s, eval_r, eval_d, infos, eval_extra_log = self.eval( - episodes=eval_eps, - max_env_time_steps=max_env_time_steps, - train_set=False, - log_level=log_level, - ) - eval_stats = dict( - elapsed_time=time.time() - start_time, - training_steps=total_steps, - training_eps=e, - avg_num_steps_per_eval_ep=float(np.mean(eval_s)), - avg_num_decs_per_eval_ep=float(np.mean(eval_d)), - avg_rew_per_eval_ep=float(np.mean(eval_r)), - std_rew_per_eval_ep=float(np.std(eval_r)), - eval_eps=eval_eps, - ) - per_inst_stats = dict( - # eval_insts=self._train_eval_env.instances, - reward_per_isnts=eval_r, - steps_per_insts=eval_s, - ) - with open( - os.path.join(self.out_dir, "eval_scores.json"), "a+" - ) as out_fh: - json.dump(eval_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "eval_scores_per_inst.json"), "a+" - ) as out_fh: - json.dump(per_inst_stats, out_fh) - out_fh.write("\n") - # with open(os.path.join(self.out_dir, 'eval_infos_per_episode.json'), 'a+') as out_fh: - # json.dump(infos, out_fh) - # out_fh.write('\n') - write_info(infos) - # pickle.dump(infos, eval_infos_file) - if log_level > 1: - # pickle.dump(eval_extra_log, eval_extra_log_file) - write_extra_log(eval_extra_log) - - # save best model - if (self._eval_r_best is None) or ( - self._eval_r_best < eval_stats["avg_rew_per_eval_ep"] - ): - self._eval_r_best = eval_stats["avg_rew_per_eval_ep"] - self.save_model("best") - - if self._train_eval_env is not None: - eval_s, eval_r, eval_d, pols, infos = self.eval( - eval_eps, max_env_time_steps, train_set=True - ) - eval_stats = dict( - elapsed_time=time.time() - start_time, - training_steps=total_steps, - training_eps=e, - avg_num_steps_per_eval_ep=float(np.mean(eval_s)), - avg_num_decs_per_eval_ep=float(np.mean(eval_d)), - avg_rew_per_eval_ep=float(np.mean(eval_r)), - std_rew_per_eval_ep=float(np.std(eval_r)), - eval_eps=eval_eps, - ) - per_inst_stats = dict( - # eval_insts=self._train_eval_env.instances, - reward_per_isnts=eval_r, - steps_per_insts=eval_s, - ) - - with open( - os.path.join(self.out_dir, "train_scores.json"), "a+" - ) as out_fh: - json.dump(eval_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "train_scores_per_inst.json"), - "a+", - ) as out_fh: - json.dump(per_inst_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "train_infos_per_episode.json"), - "a+", - ) as out_fh: - json.dump(infos, out_fh) - out_fh.write("\n") - # print('End Evaluation') - print("\n(eval) R=%.2f" % (float(np.mean(eval_r)))) - ########### End Evaluation - - # save checkpoint models - if (total_steps % save_model_interval) == 0: - self.save_model("checkpoint_" + str(total_steps)) - - # Update replay buffer - self._replay_buffer.add_transition(s, a, ns, r, d) - if begin_learning_after < total_steps: - ( - batch_states, - batch_actions, - batch_next_states, - batch_rewards, - batch_terminal_flags, - ) = self._replay_buffer.random_next_batch(batch_size) - - ########### Begin double Q-learning update - target = ( - batch_rewards - + (1 - batch_terminal_flags) - * self._gamma - * self._q_target(batch_next_states)[ - torch.arange(batch_size).long(), - torch.argmax(self._q(batch_next_states), dim=1), - ] - ) - current_prediction = self._q(batch_states)[ - torch.arange(batch_size).long(), batch_actions.long() - ] - - loss = self._loss_function(current_prediction, target.detach()) - if log_level > 1: - ep_loss.append(loss.detach().numpy()) - - self._q_optimizer.zero_grad() - loss.backward() - self._q_optimizer.step() - - soft_update(self._q_target, self._q, 0.01) - ########### End double Q-learning update - - if d: - break - s = ns - if total_steps >= max_train_time_steps: - break - - if log_level > 1: - if len(ep_loss) > 0: - # pickle.dump({'ep_loss':ep_loss, 'total_steps': total_steps}, train_log_file) - write_train_log({"ep_loss": ep_loss, "total_steps": total_steps}) - ep_loss = [] - - if total_steps >= max_train_time_steps: - break - - # Final evaluation - eval_s, eval_r, eval_d, infos, eval_extra_log = self.eval( - episodes=eval_eps, - max_env_time_steps=max_env_time_steps, - train_set=False, - log_level=log_level, - ) - eval_stats = dict( - elapsed_time=time.time() - start_time, - training_steps=total_steps, - training_eps=e, - avg_num_steps_per_eval_ep=float(np.mean(eval_s)), - avg_num_decs_per_eval_ep=float(np.mean(eval_d)), - avg_rew_per_eval_ep=float(np.mean(eval_r)), - std_rew_per_eval_ep=float(np.std(eval_r)), - eval_eps=eval_eps, - ) - per_inst_stats = dict( - # eval_insts=self._train_eval_env.instances, - reward_per_isnts=eval_r, - steps_per_insts=eval_s, - ) - - with open(os.path.join(self.out_dir, "eval_scores.json"), "a+") as out_fh: - json.dump(eval_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "eval_scores_per_inst.json"), "a+" - ) as out_fh: - json.dump(per_inst_stats, out_fh) - out_fh.write("\n") - # with open(os.path.join(self.out_dir, 'eval_infos_per_episode.json'), 'a+') as out_fh: - # json.dump(infos, out_fh) - # out_fh.write('\n') - # pickle.dump(infos, eval_infos_file) - write_info(infos) - if log_level > 1: - # pickle.dump(eval_extra_log, eval_extra_log_file) - write_extra_log(eval_extra_log) - # eval_infos_file.close() - # eval_extra_log_file.close() - # train_log_file.close() - - if self._train_eval_env is not None: - eval_s, eval_r, eval_d, pols, infos = self.eval( - eval_eps, max_env_time_steps, train_set=True - ) - eval_stats = dict( - elapsed_time=time.time() - start_time, - training_steps=total_steps, - training_eps=e, - avg_num_steps_per_eval_ep=float(np.mean(eval_s)), - avg_num_decs_per_eval_ep=float(np.mean(eval_d)), - avg_rew_per_eval_ep=float(np.mean(eval_r)), - std_rew_per_eval_ep=float(np.std(eval_r)), - eval_eps=eval_eps, - ) - per_inst_stats = dict( - # eval_insts=self._train_eval_env.instances, - reward_per_isnts=eval_r, - steps_per_insts=eval_s, - ) - - with open(os.path.join(self.out_dir, "train_scores.json"), "a+") as out_fh: - json.dump(eval_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "train_scores_per_inst.json"), "a+" - ) as out_fh: - json.dump(per_inst_stats, out_fh) - out_fh.write("\n") - with open( - os.path.join(self.out_dir, "train_infos_per_episode.json"), "a+" - ) as out_fh: - json.dump(infos, out_fh) - out_fh.write("\n") - - def __repr__(self): - return "DDQN" - - def eval( - self, - episodes: int, - max_env_time_steps: int, - train_set: bool = False, - log_level: int = 1, - ): - """ - Simple method that evaluates the agent with fixed epsilon = 0 - :param episodes: max number of episodes to play - :param max_env_time_steps: max number of max_env_time_steps to play - - :returns (steps per episode), (reward per episode), (decisions per episode) - """ - steps, rewards, decisions = [], [], [] - infos = [] - this_env = self._eval_env if not train_set else self._train_eval_env - extra_log = { - "dis_r": [], - "est_q": [], - "avg_dis_r_per_state": [], - "avg_est_qs_per_state": [], - } # extra log info when log_level>1 - for e in range(episodes): - # this_env.instance_index = this_env.instance_index % 10 # for faster debugging on only 10 insts - # print(f'Eval Episode {e} of {episodes}', end='\r') - ed, es, er = 0, 0, 0 - - ep_s, ep_r = ( - [], - [], - ) # list of states visited during current episode and the rewards - - s = this_env.reset() - info_this_episode = [] - for _ in count(): - with torch.no_grad(): - a = self.get_action(s, 0) - ns, r, d, info = this_env.step(a) - if log_level > 1: - ep_s.append(ns) - ep_r.append(r) - if d: - info_this_episode.append(info) - ed += 1 - er += r - es += 1 - if es >= max_env_time_steps or d: - break - s = ns - steps.append(es) - rewards.append(float(er)) - decisions.append(ed) - infos.append(info_this_episode) - - if log_level > 1: - # discounted cumulative reward for each visited state - dis_r_per_state = scipy.signal.lfilter( - [1], [1, float(-self._gamma)], ep_r[::-1], axis=0 - )[ - ::-1 - ] # copy from https://github.com/openai/spinningup/blob/038665d62d569055401d91856abb287263096178/spinup/algos/pytorch/ppo/core.py#L29 - # estimated value for each visited state - with torch.no_grad(): - est_qs_per_state = np.amax( - self._q(tt(np.array(ep_s))).detach().numpy(), axis=1 - ) - extra_log["avg_dis_r_per_state"].append(np.mean(dis_r_per_state)) - extra_log["avg_est_qs_per_state"].append(np.mean(est_qs_per_state)) - extra_log["dis_r"].append(dis_r_per_state[0]) - extra_log["est_q"].append(est_qs_per_state[0]) - - return steps, rewards, decisions, infos, extra_log - - def save_model(self, model_name): - torch.save(self._q.state_dict(), os.path.join(self.out_dir, model_name + ".pt")) - - def load(self, path): - self._q.load_state_dict(torch.load(path)) - - -def train_ddqn_local( - train_env, - eval_env, - state_dim, - action_dim, - train_episodes=1000, - train_max_steps=100000, - eval_episodes=10, - eval_interval=1000, - begin_learning_after=10000, - batch_size=2048, - epsilon=0.2, - gamma=0.99, - out_dir="./output", - save_model_interval=1000, - save_best=True, - save_final=True, - log_level=1, -): - - agent = DQN( - state_dim, action_dim, gamma, env=train_env, eval_env=eval_env, out_dir=out_dir - ) - - agent.train( - episodes=train_episodes, - max_env_time_steps=int(1e9), - epsilon=epsilon, - eval_eps=eval_episodes, - eval_every_n_steps=eval_interval, - max_train_time_steps=train_max_steps, - begin_learning_after=begin_learning_after, - batch_size=batch_size, - log_level=log_level, - save_best=save_best, - save_model_interval=save_model_interval, - ) - - agent.save_model("final") diff --git a/examples/benchmarks/theory/scripts/ddqn_local/ddqn_utils.py b/examples/benchmarks/theory/scripts/ddqn_local/ddqn_utils.py deleted file mode 100755 index 1b600f134..000000000 --- a/examples/benchmarks/theory/scripts/ddqn_local/ddqn_utils.py +++ /dev/null @@ -1,101 +0,0 @@ -import argparse -import datetime -import json -import os -import sys -import tempfile - -import subprocess - - -def prepare_output_dir( - args, user_specified_dir=None, argv=None, subfolder_naming_scheme=None -): - """ - Largely inspired by chainerRLs prepare output dir (also copied parts of it). - Differences: We also allow to index experiment subfolders by experiment seeds and we do not check if the repo - is under git control but always asume this to be true. Lastly we also print to stdout where data will be stored. - - For the original code see: - (https://github.com/chainer/chainerrl/blob/018a29132d77e5af0f92161250c72aba10c6ce29/chainerrl/experiments/prepare_output_dir.py) - Prepare a directory for outputting training results. - - An output directory, which ends with the current datetime string, - is created. Then the following infomation is saved into the directory: - - args.txt: command line arguments - command.txt: command itself - environ.txt: environmental variables - - Args: - args (dict or argparse.Namespace): Arguments to save - user_specified_dir (str or None): If str is specified, the output - directory is created under that path. If not specified, it is - created as a new temporary directory instead. - argv (list or None): The list of command line arguments passed to a - script. If not specified, sys.argv is used instead. - subfolder_naming_scheme (str): Format used to represent the current datetime. The - default format is the basic format of ISO 8601. - Returns: - Path of the output directory created by this function (str). - """ - - if subfolder_naming_scheme == "time": - subfolder_str = datetime.datetime.now().strftime("%Y%m%dT%H%M%S.%f") - else: - subfolder_str = "{:>05d}".format(args.seed) - if user_specified_dir is not None: - if os.path.exists(user_specified_dir): - if not os.path.isdir(user_specified_dir): - raise RuntimeError("{} is not a directory".format(user_specified_dir)) - outdir = os.path.join(user_specified_dir, subfolder_str) - if os.path.exists(outdir): - raise RuntimeError("{} exists".format(outdir)) - else: - os.makedirs(outdir) - else: - outdir = tempfile.mkdtemp( - prefix=datetime.datetime.now().strftime("%Y%m%dT%H%M%S.%f") - ) - - # Save all the arguments - with open(os.path.join(outdir, "args.txt"), "w") as f: - if isinstance(args, argparse.Namespace): - args = vars(args) - f.write(json.dumps(args)) - - # Save all the environment variables - with open(os.path.join(outdir, "environ.txt"), "w") as f: - f.write(json.dumps(dict(os.environ))) - - # Save the command - with open(os.path.join(outdir, "command.txt"), "w") as f: - if argv is None: - argv = sys.argv - f.write(" ".join(argv)) - - try: - cwd = os.getcwd() - dir_path = os.path.dirname(os.path.realpath(__file__)) - os.chdir(dir_path) - # Save `git rev-parse HEAD` (SHA of the current commit) - # with open(os.path.join(outdir, 'git-head.txt'), 'wb') as f: - # f.write(subprocess.check_output('git rev-parse HEAD'.split())) - - # Save `git status` - # with open(os.path.join(outdir, 'git-status.txt'), 'wb') as f: - # f.write(subprocess.check_output('git status'.split())) - - # Save `git log` - # with open(os.path.join(outdir, 'git-log.txt'), 'wb') as f: - # f.write(subprocess.check_output('git log'.split())) - - # Save `git diff` - # with open(os.path.join(outdir, 'git-diff.txt'), 'wb') as f: - # f.write(subprocess.check_output('git diff'.split())) - os.chdir(cwd) - except subprocess.CalledProcessError: - print("Not in a git environment") - - print("Results stored in {:s}".format(os.path.abspath(outdir))) - return outdir diff --git a/examples/benchmarks/theory/scripts/optimal_policies.txt b/examples/benchmarks/theory/scripts/optimal_policies.txt deleted file mode 100644 index 1f9773dda..000000000 --- a/examples/benchmarks/theory/scripts/optimal_policies.txt +++ /dev/null @@ -1,63 +0,0 @@ -50; 1,17,33; 49,6,0 -50; 1,13,25,37; 49,8,1,0 -50; 1,11,21,31,41; 49,9,2,0,0 -50; 1,9,17,25,33,41; 49,10,2,1,0,0 -50; 1,8,15,22,29,36,43; 49,11,3,1,0,0,0 -50; 1,7,13,19,25,31,37,43; 49,12,3,2,1,0,0,0 -50; 1,6,11,16,21,26,31,36,41,46; 49,14,4,2,1,1,0,0,0,0 -50; 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43; 49,17,7,4,3,2,1,1,1,0,0,0,0,0,0 -50; 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39; 49,20,10,6,5,3,3,2,2,1,1,1,1,0,0,0,0,0,0,0 - -60; 1,21,41; 59,6,0 -60; 1,16,31,46; 59,8,1,0 -60; 1,13,25,37,49; 59,10,2,0,0 -60; 1,11,21,31,41,51; 59,11,2,1,0,0 -60; 1,9,17,25,33,41,49; 59,13,3,1,1,0,0 -60; 1,8,15,22,29,36,43,50; 59,14,4,2,1,0,0,0 -60; 1,7,13,19,25,31,37,43,49,55; 59,15,4,2,1,1,0,0,0,0 -60; 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57; 59,19,7,4,2,2,1,1,0,0,0,0,0,0,0 -60; 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58; 59,21,9,5,4,3,2,1,1,1,1,0,0,0,0,0,0,0,0,0 - -80; 1,27,53; 79,7,1 -80; 1,21,41,61; 79,9,1,0 -80; 1,17,33,49,65; 79,11,2,0,0 -80; 1,14,27,40,53,66; 79,13,2,1,0,0 -80; 1,12,23,34,45,56,67; 79,14,3,1,1,0,0 -80; 1,11,21,31,41,51,61,71; 79,15,4,2,1,0,0,0 -80; 1,9,17,25,33,41,49,57,65,73; 79,18,5,2,1,1,0,0,0,0 -80; 1,6,11,16,21,26,31,36,41,46,51,56,61,66,71; 79,23,8,4,3,2,1,1,1,0,0,0,0,0,0 -80; 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77; 79,25,10,6,4,3,2,1,1,1,1,0,0,0,0,0,0,0,0,0 - -100;1,34,67; 99,8,0 -100;1,26,51,76; 99,10,1,0 -100;1,21,41,61,81; 99,12,2,0,0 -100;1,17,33,49,65,81; 99,14,3,1,0,0 -100;1,15,29,43,57,71,85; 99,16,3,1,0,0,0 -100;1,13,25,37,49,61,73,85; 99,17,4,2,1,0,0,0 -100;1,11,21,31,41,51,61,71,81,91; 99,20,5,2,1,1,0,0,0,0 -100;1,7,13,19,25,31,37,43,49,55,61,67,73,79,85; 99,26,8,5,3,2,1,1,1,0,0,0,0,0,0 -100;1,6,11,16,21,26,31,36,41,46,51,56,61,66,71,76,81,86,91,96; 99,29,10,6,4,3,2,1,1,1,1,0,0,0,0,0,0,0,0,0 - -50; 1,2,3; 49,24,15 -50; 1,2,3,4; 49,24,15,11 -50; 1,2,3,4,5; 49,24,15,11,9 -50; 1,2,3,4,5,6; 49,24,15,11,9,7 -50; 1,2,3,4,5,6,7; 49,24,15,11,9,7,6 -50; 1,2,3,4,5,6,7,8; 49,24,15,11,9,7,6,5 - -50; 1,2,4; 49,24,13 -50; 1,2,4,8; 49,24,13,7 -50; 1,2,4,8,16; 49,24,13,7,3 -50; 1,2,4,8,16,32; 49,24,13,7,3,1 - -150;1,51,101; 149,9,0 -150;1,38,75,112; 149,12,1,0 -150;1,31,61,91,121; 149,14,2,0,0 -150;1,26,51,76,101,126; 149,16,2,1,0,0 -150;1,22,43,64,85,106,127; 149,18,3,1,1,0,0 - -200;1,67,133; 199,10,1 -200;1,51,101,151; 199,13,1,0 -200;1,41,81,121,161; 199,15,2,0,0 -200;1,34,67,100,133,166; 199,18,3,1,0,0 -200;1,29,57,85,113,141,169; 199,20,3,1,1,0,0 diff --git a/examples/benchmarks/theory/scripts/rls_policies.py b/examples/benchmarks/theory/scripts/rls_policies.py deleted file mode 100644 index 0e63da559..000000000 --- a/examples/benchmarks/theory/scripts/rls_policies.py +++ /dev/null @@ -1,132 +0,0 @@ -import numpy as np -from dacbench.envs import RLSEnv, RLSEnvDiscrete -import os -import sys - -sys.path.append(os.path.dirname(__file__)) -from ddqn_local.ddqn import DQN -import pprint - - -class RandomPolicy: - def __init__(self, env, name="random"): - self.name = name - self.env = env - - def get_next_action(self, obs): - action = self.env.action_space.sample() - return action - - -class RLSOptimalPolicy: - def __init__(self, env, name="RLSOptimal"): - self.name = name - self.env = env - - def get_next_action(self, obs): - k = int(self.env.n / (self.env.x.fitness + 1)) - return k - - def get_predictions(self): - return [int(self.env.n / (fx + 1)) for fx in range(0, self.env.n)] - - -class RLSFixedOnePolicy: - def __init__(self, env, name="RLSFixedOne"): - self.name = name - self.env = env - - def get_next_action(self, obs): - return 1 - - def get_predictions(self): - return [1 for fx in range(0, self.env.n)] - - -class DQNPolicy: - def __init__(self, env, model, name="RLSDQNPolicy"): - """ - model: trained model - """ - self.name = name - self.env = env - state_dim = env.observation_space.shape[0] - action_dim = env.action_space.n - self.agent = DQN(state_dim, action_dim, 1, env=env, eval_env=env, out_dir="./") - self.agent.load(model) - - def get_next_action(self, obs): - return self.agent.get_action(obs, 0) - - def get_predictions(self): - acts = [ - self.get_next_action(np.array([self.env.n, fx])) - for fx in range(0, self.env.n) - ] - return [self.env.action_choices[act] for act in acts] - - -class RLSOptimalDiscretePolicy: - def __init__(self, env, name="RLSOptimalDiscrete"): - self.name = name - self.env = env - assert "action_choices" in env.unwrapped.__dict__ - env.reset() - self.acts = env.action_choices - # string of all actions - self.acts_str = str(self.acts) - script_dir = os.path.dirname(__file__) - self.positions_dict = self.parse_rls_optimal_policies( - fn=script_dir + "/optimal_policies.txt" - ) - sn = str(env.n) - assert sn in self.positions_dict - assert self.acts_str in self.positions_dict[sn] - self.positions = self.positions_dict[sn][self.acts_str] - - def get_next_action(self, obs): - fx = self.env.x.fitness - act = None - for i in range(len(self.positions) - 1, -1, -1): - if self.positions[i] >= fx: - act = i - break - # print(f"{fx:3d}: {self.acts[act]:3d}") - assert act is not None, f"ERROR: {fx}" - return act - - def parse_rls_optimal_policies(self, fn="./optimal_policies.txt"): - with open(fn, "rt") as f: - ls = [s.replace("\n", "") for s in f.readlines()] - ls = [s for s in ls if s != ""] - positions_dict = {} - for s in ls: - ls1 = s.split(";") - n = int(ls1[0]) - ks = [x.strip() for x in ls1[1].split(",") if x.strip() != ""] - pos = [x.strip() for x in ls1[2].split(",") if x.strip() != ""] - assert len(ks) == len(pos), f"ERROR with {s} ({len(ks)} {len(pos)})" - ks = "[" + ", ".join([str(x) for x in ks]) + "]" - pos = [int(x) for x in pos] - # sn = str(self.env.n) - sn = str(n) - if sn not in positions_dict: - positions_dict[sn] = {} - positions_dict[sn][ks] = pos - - # pprint.pprint(positions_dict) - return positions_dict - - def get_predictions(self): - def get_optimal_act(fx): - act = None - for i in range(len(self.positions) - 1, -1, -1): - if self.positions[i] >= fx: - act = i - break - assert act is not None, f"ERROR: invalid f(x) ({fx})" - return act - - return [ - self.env.action_choices[get_optimal_act(fx)] for fx in range(0, self.env.n) - ] diff --git a/examples/benchmarks/theory/scripts/run_experiment.py b/examples/benchmarks/theory/scripts/run_experiment.py deleted file mode 100644 index 6bcda5c29..000000000 --- a/examples/benchmarks/theory/scripts/run_experiment.py +++ /dev/null @@ -1,92 +0,0 @@ -import argparse -import os - -import gym -import sys - -sys.path.append(os.path.dirname(__file__)) -import shutil - -from ddqn_local.ddqn import DQN -from utils import make_env, read_config - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--out-dir", "-o", type=str, default="output", help="output folder" - ) - parser.add_argument( - "--setting-file", "-s", type=str, help="yml file with all settings" - ) - args = parser.parse_args() - - config_yml_fn = args.setting_file - ( - exp_params, - bench_params, - agent_params, - train_env_params, - eval_env_params, - ) = read_config(config_yml_fn) - - if exp_params["n_cores"] > 1: - print("WARNING: n_cores>1 is not yet supported") - - # create output folder - out_dir = args.out_dir - if os.path.isdir(out_dir) is False: - os.mkdir(out_dir) - shutil.copyfile(args.setting_file, out_dir + "/config.yml") - - # get state_dim and action_dim - temp_env = make_env(bench_params, train_env_params) - s = temp_env.reset() - print(temp_env.observation_space) # DEBUG - print(s) # DEBUG - state_dim = len(s) - if isinstance(temp_env.action_space, gym.spaces.Discrete): - action_dim = temp_env.action_space.n - else: - action_dim = temp_env.action_space.shape[0] - - # start the training for ddqn_local agent - if agent_params["name"] == "ddqn_local": - # create train_env and eval_env - train_env = make_env(bench_params, train_env_params) - eval_env = make_env(bench_params, eval_env_params) - - assert agent_params["name"] in ["ddqn_local", "ppo"], ( - "ERROR: agent " + agent_params["name"] + " is not supported" - ) - - # start ddqn training - if agent_params["name"] == "ddqn_local": - agent = DQN( - state_dim, - action_dim, - agent_params["gamma"], - env=train_env, - eval_env=eval_env, - out_dir=out_dir, - ) - agent.train( - episodes=exp_params["n_episodes"], - max_env_time_steps=int(1e9), - epsilon=agent_params["epsilon"], - eval_eps=exp_params["eval_n_episodes"], - eval_every_n_steps=exp_params["eval_interval"], - max_train_time_steps=exp_params["n_steps"], - begin_learning_after=agent_params["begin_learning_after"], - batch_size=agent_params["batch_size"], - log_level=exp_params["log_level"], - save_best=True, - save_model_interval=exp_params["save_interval"], - ) - agent.save_model("final") - - else: - print(f"Sorry, agent {agent_params['name']} is not yet supported") - - -main() diff --git a/examples/benchmarks/theory/scripts/run_policy.py b/examples/benchmarks/theory/scripts/run_policy.py deleted file mode 100644 index ebac2b716..000000000 --- a/examples/benchmarks/theory/scripts/run_policy.py +++ /dev/null @@ -1,97 +0,0 @@ -import os -import sys - -sys.path.append(os.path.dirname(__file__)) -import argparse -import yaml -import pickle - -from rls_policies import ( - RandomPolicy, - RLSOptimalPolicy, - RLSFixedOnePolicy, - DQNPolicy, - RLSOptimalDiscretePolicy, -) -from utils import make_env, read_config - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--n-runs", "-n", type=int, default=10, help="number of episodes" - ) - parser.add_argument( - "--bench", - "-b", - type=str, - required=True, - help="yml file of benchmark configuration", - ) - parser.add_argument("--policy", "-p", type=str, required=True, help="policy name") - parser.add_argument( - "--policy-params", "-pr", type=str, default=None, help="policy params" - ) - parser.add_argument("--out", "-o", type=str) - args = parser.parse_args() - - # create enviroment - with open(args.bench, "r") as f: - bench_params = yaml.safe_load(f) - - env = None - # load policy - if args.policy in [ - "RandomPolicy", - "RLSOptimalPolicy", - "RLSFixedOnePolicy", - "RLSOptimalDiscretePolicy", - ]: - env = make_env(bench_params, test_env=True) - policy = globals()[args.policy](env) - elif args.policy == "DQNPolicy": - # get path to the trained agent model - agent_model_file = args.policy_params - assert ( - agent_model_file - and os.path.isfile(agent_model_file) - and agent_model_file.endswith(".pt") - ) - # get observation space of the trained model - train_bench_file = os.path.dirname(agent_model_file) + "/config.yml" - _, train_bench_params, _, _, _ = read_config(train_bench_file) - assert "observation_description" in train_bench_params - bench_params["observation_description"] = train_bench_params[ - "observation_description" - ] - # create env - env = make_env(bench_params, test_env=True) - # create policy - policy = DQNPolicy(env, agent_model_file) - else: - print(f"ERROR: policy {args.policy} not supported") - sys.exit(1) - - assert env - - n = args.n_runs - assert n >= 1 - - infos = [] - for i in range(n): - env.seed(i) - s = env.reset() - while True: - act = policy.get_next_action(s) - s, r, done, info = env.step(act) - if done: - infos.append(info) - break - # print(f"Run {i}: n_evals={env.total_evals}") - print(env.total_evals) - - with open(args.out, "wb") as f: - pickle.dump(infos, f) - - -main() diff --git a/examples/benchmarks/theory/scripts/runtime_calculation.py b/examples/benchmarks/theory/scripts/runtime_calculation.py deleted file mode 100644 index c9c43bc7a..000000000 --- a/examples/benchmarks/theory/scripts/runtime_calculation.py +++ /dev/null @@ -1,77 +0,0 @@ -import numpy as np - - -def improvement_probability(r: int, i: int, n: int) -> float: - """Returns the probability to improve the LeadingOnes value. - - Assumes that the bits to be flipped are chosen uniformly at random. - - Parameters: - r (int): The number of bits flipped by the mutation operator. - - i (int): The fitness before flipping bits. - - n (int): The number of bits in the bit string. - - Watch out: - It is assumed that r ≤ n and i ≤ n. Further, all arguments are supposed - to be non-negative. - """ - assert i <= n - assert r <= n - - return (r / n) * np.prod([(n - i - j) / (n - j) for j in range(1, r)]) - - -def expected_run_time(p, n: int) -> float: - """Returns the expected run time of an algorithm using policy p when run on - LeadingOnes. - - Parameters: - p (array of size n): The policy that returns for a given fitness - value how many bits to flip, p[i] is the number of bits flipped for fitness value i - - n (int): The length of the bit strings of the LeadingOnes function. - - Watch out: - It is assumed that the domain of p is [0..n-1] and that p returns values in - [0..n]. - """ - - for i in range(0, n): - v = p[i] - assert (v >= 0) and (v <= n) - if v > (n - i): - return np.inf - - return 0.5 * np.sum([1 / improvement_probability(p[i], i, n) for i in range(0, n)]) - - -def variance_in_run_time(p, n: int) -> float: - """Returns the variance of the run time of an algorithm using policy p - when run on LeadingOnes. - - Parameters: - p (array of size n): The policy that returns for a given fitness - value how many bits to flip, p[i] is the number of bits flipped for fitness value i - - n (int): The length of the bit strings of the LeadingOnes function. - - Watch out: - It is assumed that the domain of p is [0..n-1] and that p returns values in - [0..n]. - """ - - def variance_for_fitness(i: int) -> float: - """A helper function that calculates the variance if the fitness is - i.""" - q = improvement_probability(p[i], i, n) - return (3 - 2 * q) / (q ** 2) - - for i in range(0, n): - v = p[i] - assert (v >= 0) and (v <= n) - if v > (n - i): - return np.inf - - return 0.25 * np.sum([variance_for_fitness(i) for i in range(0, n)]) diff --git a/examples/benchmarks/theory/scripts/utils.py b/examples/benchmarks/theory/scripts/utils.py deleted file mode 100644 index ced5c18a4..000000000 --- a/examples/benchmarks/theory/scripts/utils.py +++ /dev/null @@ -1,44 +0,0 @@ -import sys -import yaml -import os -from gym import wrappers - -sys.path.append(os.path.dirname(__file__)) -# import shutil -# from pprint import pprint - - -def read_config(config_yml_fn: str = "output/config.yml"): - with open(config_yml_fn, "r") as f: - params = yaml.safe_load(f) - train_env_params = eval_env_params = None - if "train_env" in params: - train_env_params = params["train_env"] - if "eval_env" in params: - eval_env_params = params["eval_env"] - return ( - params["experiment"], - params["bench"], - params["agent"], - train_env_params, - eval_env_params, - ) - - -def make_env(bench_params, env_config=None, test_env=False): - """ - env_config will override bench_params - """ - bench_class = globals()[bench_params["name"] + "Benchmark"] - - params = bench_params.copy() - del params["name"] - if env_config: - for name, val in env_config.items(): - params[name] = val - - # pprint(params) - bench = bench_class(config=params) - env = bench.get_environment(test_env) - env = wrappers.FlattenObservation(env) - return env diff --git a/examples/example_utils.py b/examples/example_utils.py index fcef1248e..efcf7960d 100644 --- a/examples/example_utils.py +++ b/examples/example_utils.py @@ -22,11 +22,11 @@ def __init__(self): def step(self, action): self.c_step += 1 - return np.array([0]), 0, self.c_step > 9, {} + return np.array([0]), 0, False, self.c_step > 9, {} def reset(self): self.c_step = 0 - return np.array([1]) + return np.array([1]), {} class QTable(dict): @@ -142,7 +142,7 @@ def greedy_eval_Q(Q: QTable, this_environment, nevaluations: int = 1): """ cumuls = [] for _ in range(nevaluations): - evaluation_state = this_environment.reset() + evaluation_state, _ = this_environment.reset() episode_length, cummulative_reward = 0, 0 expected_reward = np.max(Q[evaluation_state]) greedy = make_tabular_policy(Q, 0, this_environment.action_space.n) @@ -150,12 +150,12 @@ def greedy_eval_Q(Q: QTable, this_environment, nevaluations: int = 1): evaluation_action = np.random.choice( list(range(this_environment.action_space.n)), p=greedy(evaluation_state) ) - s_, evaluation_reward, evaluation_done, _ = this_environment.step( + s_, evaluation_reward, eval_done, evaluation_done, _ = this_environment.step( evaluation_action ) cummulative_reward += evaluation_reward episode_length += 1 - if evaluation_done: + if evaluation_done or eval_done: break evaluation_state = s_ @@ -175,15 +175,15 @@ def update( :param discount_factor: discounting factor """ # Need to parse to string to easily handle list as state with defdict - policy_state = environment.reset() + policy_state, _ = environment.reset() episode_length, cummulative_reward = 0, 0 expected_reward = np.max(Q[policy_state]) - done = False - while not done: # roll out episode + terminated, truncated = False, False + while not (terminated or truncated): # roll out episode policy_action = np.random.choice( list(range(environment.action_space.n)), p=policy(policy_state) ) - s_, policy_reward, done, _ = environment.step(policy_action) + s_, policy_reward, terminated, truncated, _ = environment.step(policy_action) cummulative_reward += policy_reward episode_length += 1 Q[[policy_state, policy_action]] = Q[[policy_state, policy_action]] + alpha * ( @@ -287,16 +287,16 @@ def train_chainer( agent, env, num_episodes=10, flatten_state=False, logger: Logger = None ): for i in range(num_episodes): - state = env.reset() + state, _ = env.reset() if flatten_state: state = np.array(flatten([state[k] for k in state.keys()])) state = state.astype(np.float32) - done = False + terminated, truncated = False, False r = 0 reward = 0 - while not done: + while not (terminated or truncated): action = agent.act_and_train(state, reward) - next_state, reward, done, _ = env.step(action) + next_state, reward, terminated, truncated, _ = env.step(action) r += reward if flatten_state: state = np.array(flatten([next_state[k] for k in next_state.keys()])) @@ -305,7 +305,7 @@ def train_chainer( state = next_state if logger is not None: logger.next_step() - agent.stop_episode_and_train(state, reward, done=done) + agent.stop_episode_and_train(state, reward, done=terminated or truncated) if logger is not None: logger.next_episode() print( diff --git a/examples/plotting/data/CMAESBenchmark/benchmark.json b/examples/plotting/data/CMAESBenchmark/benchmark.json deleted file mode 100644 index 3419e0899..000000000 --- a/examples/plotting/data/CMAESBenchmark/benchmark.json +++ /dev/null @@ -1 +0,0 @@ -{"action_space_class": "Box", "action_space_args": [[0], [10]], "observation_space_class": "Dict", "observation_space_type": "None", "observation_space_args": [["current_loc", "past_deltas", "current_ps", "current_sigma", "history_deltas", "past_sigma_deltas"], [[[-Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity], [Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]], [[-Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity], [Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]], [[-Infinity], [Infinity]], [[-Infinity], [Infinity]], [[-Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity], [Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]], [[-Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity, -Infinity], [Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]]]], "reward_range": [-1000000000, 0], "cutoff": 1000000.0, "hist_length": 40, "popsize": 10, "seed": 0, "instance_set_path": "../instance_sets/cma/cma_train.csv", "benchmark_info": {"identifier": "CMA-ES", "name": "Step-size adaption in CMA-ES", "reward": "Negative best function value", "state_description": ["Loc", "Past Deltas", "Population Size", "Sigma", "History Deltas", "Past Sigma Deltas"]}, "instance_set": {"0": [ \ No newline at end of file diff --git a/examples/wrappers/action_tracking_modea.py b/examples/wrappers/action_tracking_modcma.py similarity index 90% rename from examples/wrappers/action_tracking_modea.py rename to examples/wrappers/action_tracking_modcma.py index 4cd2366cf..4e5b7f814 100644 --- a/examples/wrappers/action_tracking_modea.py +++ b/examples/wrappers/action_tracking_modcma.py @@ -3,12 +3,12 @@ from dacbench.agents import RandomAgent from dacbench.logger import Logger from dacbench.runner import run_benchmark -from dacbench.benchmarks import ModeaBenchmark +from dacbench.benchmarks import ModCMABenchmark from dacbench.wrappers import ActionFrequencyWrapper # Make ModeaBenchmark environment -bench = ModeaBenchmark() +bench = ModCMABenchmark() env = bench.get_environment() # Make logger object diff --git a/setup.cfg b/setup.cfg index d9e2d5e8c..3d2d91722 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,10 +32,10 @@ python_requires= >=3.10 install_requires = gymnasium==0.27.1 numpy==1.24.2 - scipy=~1.10.1 - pandas=~1.5.3 - matplotlib=~3.7.1 - seaborn=~0.12.2 + scipy==1.10.1 + pandas==1.5.3 + matplotlib==3.7.1 + seaborn==0.12.2 configspace==0.6.1 Pyro4==4.82 @@ -44,14 +44,14 @@ install_requires = [options.extras_require] dev = - black=~23.1.0 - scikit-learn=~1.2.2 - flake8=~6.0.0 + black==23.1.0 + scikit-learn==1.2.2 + flake8==6.0.0 pytest==7.1.0 pytest-html==3.2.0 pytest-cov==4.0.0 - coverage[toml]=~7.2.1 - pre-commit=~3.1.1 + coverage[toml]==7.2.1 + pre-commit==3.1.1 example = chainerrl ray @@ -68,20 +68,20 @@ docs = cma==3.3.0 modcma==0.0.2.8.4 IOHexperimenter==0.2.9.2 - scikit-learn=~1.2.2 + scikit-learn==1.2.2 torchvision==0.14.1 torch==1.13.1 backpack-for-pytorch==1.5.2 all= gymnasium==0.27.1 numpy==1.24.2 - scipy=~1.10.1 + scipy==1.10.1 cma==3.3.0 - pandas=~1.5.3 - matplotlib=~3.7.1 - seaborn=~0.12.2 + pandas==1.5.3 + matplotlib==3.7.1 + seaborn==0.12.2 configspace==0.6.1 - scikit-learn=~1.2.2 + scikit-learn==1.2.2 torchvision==0.14.1 torch==1.13.1 backpack-for-pytorch==1.5.2 @@ -96,7 +96,7 @@ modcma= modcma==0.0.2.8.4 IOHexperimenter==0.2.9.2 sgd= - scikit-learn=~1.2.2 + scikit-learn==1.2.2 torchvision==0.14.1 torch==1.13.1 backpack-for-pytorch==1.5.2 diff --git a/tests/agents/test_generic_agent.py b/tests/agents/test_generic_agent.py deleted file mode 100644 index cd2a13de4..000000000 --- a/tests/agents/test_generic_agent.py +++ /dev/null @@ -1,13 +0,0 @@ -import unittest - -from dacbench.agents import GenericAgent - - -class TestGenericAgent(unittest.TestCase): - def test_dummy_policy(self): - agent = GenericAgent(None, lambda env, state: 0) - - self.assertIsNone(agent.env) - self.assertEqual(agent.act(None, None), 0) - self.assertIsNone(agent.train(None, None)) - self.assertIsNone(agent.end_episode(None, None)) diff --git a/tests/benchmarks/test_geometric_benchmark.py b/tests/benchmarks/test_geometric_benchmark.py deleted file mode 100644 index ffb8a1dea..000000000 --- a/tests/benchmarks/test_geometric_benchmark.py +++ /dev/null @@ -1,204 +0,0 @@ -import unittest -import json -import os - -from dacbench.abstract_benchmark import objdict -from dacbench.benchmarks import GeometricBenchmark -from dacbench.envs import GeometricEnv - - -INFO = { - "identifier": "Geometric", - "name": "High Dimensional Geometric Curve Approximation. Curves are geometrical orthogonal.", - "reward": "Overall Euclidean Distance between Point on Curve and Action Vector for all Dimensions", - "state_description": ["Remaining Budget", "Dimensions",], -} - - -DEFAULTS_DYNAMIC = objdict( - { - "action_space_class": "Discrete", - "action_space_args": [1], - "observation_space_class": "Box", - "observation_space_type": None, - "observation_space_args": [1, 1], - "reward_range": (0, 1), - "cutoff": 10, - "action_values": [1], - "action_value_default": 4, - "action_values_variable": True, # if True action value mapping will be used - "action_value_mapping": { # defines number of action values for differnet functions - "sigmoid": 3, - "linear": 3, - "polynomial2D": 5, - "polynomial3D": 7, - "polynomial7D": 11, - "exponential": 4, - "logarithmic": 4, - "constant": 1, - }, - "action_interval_mapping": {}, # maps actions to equally sized intervalls in [-1, 1] - "seed": 0, - "derivative_interval": 3, - "max_function_value": 10000, # clip function value if it is higher than this number - "realistic_trajectory": True, - "instance_set_path": "../instance_sets/geometric/geometric_test.csv", - "benchmark_info": INFO, - } -) - - -DEFAULTS_STATIC = objdict( - { - "action_space_class": "Discrete", - "action_space_args": [1], - "observation_space_class": "Box", - "observation_space_type": None, - "observation_space_args": [1, 1], - "reward_range": (0, 1), - "cutoff": 10, - "action_values": [1], - "action_value_default": 4, - "action_values_variable": False, # if True action value mapping will be used - "action_interval_mapping": {}, # maps actions to equally sized intervalls in [-1, 1] - "max_function_value": 10000, # clip function value if it is higher than this number - "derivative_interval": 3, - "realistic_trajectory": True, - "instance_set_path": "../instance_sets/geometric/geometric_test.csv", - "benchmark_info": INFO, - } -) - -DEFAULTS_CORRELATION = objdict( - { - "action_space_class": "Discrete", - "action_space_args": [1], - "observation_space_class": "Box", - "observation_space_type": None, - "observation_space_args": [1, 1], - "reward_range": (0, 1), - "seed": 0, - "cutoff": 10, - "action_values": [1], - "action_value_default": 4, - "action_values_variable": False, - "action_interval_mapping": {}, # maps actions to equally sized intervalls in interval [-1, 1] - "derivative_interval": 3, # defines how many values are used for derivative calculation - "max_function_value": 1000000, # clip function value if it is higher than this number - "realistic_trajectory": True, # True: coordiantes are used as trajectory, False: Actions are used as trajectories - "instance_set_path": "../instance_sets/geometric/geometric_test.csv", - # correlation table to chain dimensions -> if dim x changes dim y changes as well - # either assign numpy array to correlation table or use create_correlation_table() - "correlation_table": None, - "correlation_info": { - "high": [(1, 2, "+"), (2, 3, "-"), (1, 5, "+")], - "middle": [(4, 5, "-")], - "low": [(4, 7, "+"), (2, 3, "+"), (0, 2, "-")], - }, - "correlation_mapping": { - "high": (0.5, 1), - "middle": (0.1, 0.5), - "low": (0, 0.1), - }, - "create_correlation": False, - "benchmark_info": INFO, - } -) - - -class TestGeometricBenchmark(unittest.TestCase): - def load_bench(self, config): - with open("data.json", "w") as fp: - json.dump(config, fp) - - absolute_path = os.path.abspath("data.json") - bench = GeometricBenchmark(config_path=absolute_path) - os.remove("data.json") - return bench - - def test_get_env(self): - bench = GeometricBenchmark() - env = bench.get_environment() - self.assertTrue(issubclass(type(env), GeometricEnv)) - - def test_setup(self): - bench = GeometricBenchmark() - self.assertTrue(bench.config is not None) - config = {"dummy": 0} - with open("test_conf.json", "w+") as fp: - json.dump(config, fp) - bench = GeometricBenchmark("test_conf.json") - self.assertTrue(bench.config.dummy == 0) - os.remove("test_conf.json") - - def test_save_conf(self): - bench = self.load_bench(DEFAULTS_STATIC) - bench.read_instance_set() - bench.set_action_values() - - absolute_path = os.path.abspath("data.json") - bench.save_config(absolute_path) - with open(absolute_path, "r") as fp: - recovered = json.load(fp) - - del bench.config["instance_set"] - for k in bench.config.keys(): - self.assertTrue(k in recovered.keys()) - os.remove("data.json") - - def test_read_instance_set(self): - bench = self.load_bench(DEFAULTS_STATIC) - bench.read_instance_set() - self.assertTrue(len(bench.config.instance_set.keys()) == 100) - self.assertTrue(len(bench.config.instance_set[0]) == 7) - self.assertTrue(bench.config.instance_set[0][0][1] == "sigmoid") - first_inst = bench.config.instance_set[0][0][3] - - bench2 = self.load_bench(DEFAULTS_STATIC) - env = bench2.get_environment() - self.assertTrue(env.instance_set[0][0][3] == first_inst) - self.assertTrue(len(env.instance_set.keys()) == 100) - self.assertTrue(bench.config.instance_set[0][1][1] == "linear") - - def test_benchmark_env(self): - bench = GeometricBenchmark() - env = bench.get_benchmark() - self.assertTrue(issubclass(type(env), GeometricEnv)) - - def test_set_action_values_static(self): - bench = self.load_bench(DEFAULTS_STATIC) - bench.read_instance_set() - bench.set_action_values() - self.assertTrue(bench.config.action_value_default == 4) - self.assertTrue(bench.config.action_values[0] == 4) - self.assertTrue(len(bench.config.observation_space_args[0]) == 16) - self.assertTrue( - len(bench.config.action_interval_mapping) - == len(bench.config.action_value_mapping) - ) - - def test_set_action_values_dynamic(self): - bench = self.load_bench(DEFAULTS_DYNAMIC) - bench.read_instance_set() - bench.set_action_values() - self.assertTrue(bench.config.action_values_variable) - self.assertTrue(bench.config.action_values[4] == 4) - self.assertTrue(len(bench.config.observation_space_args[0]) == 16) - - def test_set_action_description(self): - bench = self.load_bench(DEFAULTS_DYNAMIC) - bench.read_instance_set() - bench.set_action_values() - bench.set_action_description() - self.assertTrue( - "Derivative1" in bench.config.benchmark_info["state_description"] - ) - - def test_create_correlation_table(self): - bench = self.load_bench(DEFAULTS_CORRELATION) - bench.read_instance_set() - bench.read_instance_set() - bench.set_action_values() - bench.create_correlation_table() - n_actions = len(bench.config.action_values) - self.assertTrue(bench.config.correlation_table.shape == (n_actions, n_actions)) diff --git a/tests/benchmarks/test_theory_benchmark.py b/tests/benchmarks/test_theory_benchmark.py deleted file mode 100644 index 9cd7f06fc..000000000 --- a/tests/benchmarks/test_theory_benchmark.py +++ /dev/null @@ -1,45 +0,0 @@ -from dacbench.benchmarks import TheoryBenchmark -from dacbench.envs import RLSEnv, RLSEnvDiscrete -import unittest -import json -import os - - -class TestTheoryBenchmark(unittest.TestCase): - def test_get_env(self): - # environment with non-discrete action space - bench = TheoryBenchmark( - config={"discrete_action": False, "min_action": 1, "max_action": 49} - ) - env = bench.get_environment() - self.assertTrue(issubclass(type(env), RLSEnv)) - - # environment with discrete action space - bench = TheoryBenchmark( - config={"discrete_action": True, "action_choices": [1, 2, 4, 8]} - ) - env = bench.get_environment() - self.assertTrue(issubclass(type(env), RLSEnvDiscrete)) - - def test_save_conf(self): - # save a benchmark config - bench = TheoryBenchmark() - bench.save_config("test_conf.json") - - # reload it - with open("test_conf.json", "r") as f: - recovered = json.load(f) - os.remove("test_conf.json") - - # create a new benchmark with the loaded config - rbench = TheoryBenchmark(config=recovered) - - # check if the two benchmarks are identical - assert isinstance(rbench.get_environment(), RLSEnvDiscrete) - for i in range(len(bench.config.action_choices)): - assert bench.config.action_choices[i] == rbench.config.action_choices[i] - - -if __name__ == "__main__": - TestTheoryBenchmark().test_get_env() - TestTheoryBenchmark().test_save_conf() diff --git a/tests/envs/data/sgd_config.hash b/tests/envs/data/sgd_config.hash deleted file mode 100644 index 2e306a218..000000000 --- a/tests/envs/data/sgd_config.hash +++ /dev/null @@ -1 +0,0 @@ -97a430190499eb5111d11d2b8ff1b8e65c2693c2 \ No newline at end of file diff --git a/tests/envs/data/sgd_dynamic_test.npy b/tests/envs/data/sgd_dynamic_test.npy deleted file mode 100644 index 766a13b77b8430fa21c97a2fc1d15c3ff38a3fe7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4928 zcmbW4dt6T08pl^IN8w=H%1p){B8@0Cl~GwW73DgU+#2kLk_?s3D3dzdB_kO_g=yTj zs9YP2OHOD>Lgm(&T#n0DsYY|8L(DM4SK27S0ZXxPR!Ev0*$O8xa~E#{K>u zIXfzYhd4MYiOT;u+7d#vhPvMixz(qQ??=I(`{_;edmQ_71jPF^B%!tPuzLF3Y0ivW9GhRKH1`%d*0-QFB3be+Av9KxRqMWr2FtEb zE&-kXG$suDUU_`3?B53R#=M1sKjz&AGk;lJUa{1vXK(j{II|oww~_mM&9y@A<9J}_H$m!X_q88T9#lJz3IR*=<_-p{ zjEfZgPu(~h^mC0-Sfh7$M zL%`AxZ{z%HLtRrqr>!S~e`6!A~XNHXg?E`Npcn z(Zd_Yc``H;nQkt(R>$Shl}?FwT$D6XdGXz5OMB5ag8&X%{i?Jh}iakCCqF z&4;CqT2&*Tz1bfO_39}Eheot*t{-?lG`Z^+?EO){6s#`lh1|56hRRwvbj=Tw$58Q|9wHFo0ZTS@6 z^O$L4eJazWJJ}K6H+uY%36v+*fPdrjWmYq%qd)%e@5q1MWPnefSl$N9$56^IG_5uZ z`MUA;{2CcpF-hu-D_J-{WKF?%s8{QfkWaD?i~YPTX*=lY%gS4jCuN@HXbHi6uCz;z zDunpW^lH2hd~Vz~`A4bK3g5?dtnEmdNO_9wvl8pGCUy$=T7C;Wzm(LlYv3CTGRwg7 zf%{zVziAtC>6%Suez)bDS4y4Qo8WmuZ0F+o)Y|TKqgvh0R{PK`Nw9ejFc zkN6&h;67Jo5*@iKZ&w%cJPyB0Jzne(Iwi#y-*3v3jmT3TPC~vu)*rtQ^-POJe%4Fm z>jyGS^N)4vlJ#4WPhRaX^Pg>);wE(@$r|}&_Y~wQ)vbkYQ0!-vH$(gNIS+c8-CO~_ zR#$cjEFUvSOzkz(E>a@guc#dkHUB&+OCLiQ0|2;Yy^lDvx zf8gsZp%i>&{)`J?`4~?5g&m0a0q4ik_W@eST<|y(C3R}mWE-ectEMBLjP8Ma@}^w? z#5JD+H_#dLl5qa1>TTkCKwdw+RLl=~AJ+j75wfu3J8@E{+5Tuvd5Eb__(wo<2cKhlHpkajK)*9!|x z5d6hm{2*@B-hYn$YwdpmpT^xg2$l~o3Rm0M&3OO6`Qz_Y2$AShF?Xd-b*$)0d5GS< zj_*(UWFYdDE0aEfIGge>FXTtGJ^{WlKJGYJK1NV}(U;VvBmd7{zZ60gMtJMHCr!Gd z;x3ejSjWHc{i(a2a{*uR=;i}f-Bf)5^vWZ)4}2r=;$g6SP|7bxgF{iJ>V4)XPj6u-YRrKk8^*5Q5*)Uj{(vR9`5 zasBFft;PK0TU{vxHjER$6bzI)@_3o}{rFU#@7L3ZP+p>y7UMpk_fzqF=g0bbh_liy z^7(4WSI%q~=S$7w+vfhy4)FDsI=y?-uMpQmU*h@8awj35KKeVZBjeY_KcOzSb0+eW zYEAw7f^VobV*UJ5$h7 zqw~P>Psmr}g7N$(^+m5AVD&LnmgU<>&3UiP^=!}x(_*|I>m3)HlZ)1GAct7apGR^#|Jgd=Cr|+`B`B%QbkNvQ-DafbwF(1PH z*xHLHQ8%X5YVb9`*fg;G6Y|xjJh8v(UEcnFdpyXwMC!D5ArA_9wbC~P``1nmN4`E} zoCD=?`b89;U&=QXtH9Sr#GCpb2|jyNBKm&PywBYKszl9G>eQmrM&Og|)7X!0`x>9C zaqyTu==Ge-(V)|AJx>MSxS`{Hcm(;nqbu%Day3-E2YC%~SoSPi>R7_cXTVn-uZZ=0 z{vh(T_7(joj~l5IR|DS&Ub_N(WpnFfuzcY6)pO2^_37gKc70|h#od!S?Uq{$#)}y% z!2Xr$DCCpijJ}k|Xx}D1pOn26d?k5nHdsEy?+YztBix^OENLhN3!`yPV>Rgh E2mZ*zeEqA#jB!CpM#W4?#yN3~`;sWO zW8C*;G#XDR6(LH-xG$ilH43ss1yodArtZJHIj_%opQb*%+jZ;Tzq)SIZg3W9^dd$?Qn8qEn#+}B#*EmFLJa$sdw3x_=BPYd-9z*`_krSqlQU0lai<~@0 z^@H2A2+>-GHVM&YY5!*{&lr<+-u97X2W@D{$(|i|KT%n|{=O2_H+zrj7p5!^=;lLx z5%mkKx_m_b;&!)nLUI4)w!91WeImC+S*b*#`t>$kSsuJNm-upHHaHHS`OdYt&pSDM zMtc3;_AB77y}sTnzr~75l6ZHt_M{hCERXnl04u?jb@*bT4|rV8fK@|fXG-VjuhFP8l3uptInbCS9r|!yZHLm z`ZcA}v5hgvkL-Ea;>T|S$Ki_srwi$RdA#IvoAVY|eK92OGWEsSK}WsuS$wR&RO6=a z*>+r6Z9;$W&F)X1k>266Cm%kgzIJH*W1CZl^sN1F{AIDyQet=az&-yVJcdsSMmo%pZSH{rxV1Jpr;*bZ2 z&)S?q-{>$dkLFRW5m!IP)21iEybS!vxbFPdYG|S>wm=BJ_7ruS7 z>3*@{n3JDi(#zC#m%)Ej`#h}jdB)EswyPt_7k4p)De9tG)4m5^ObCG9j9!vSdUMp^hhb#xb4oAY1RO~C;!YhHIq1E;YRABRv+BL3j0f&AB(zD(oUq;-~H-maAosV-uSFj4EW~X zMOD(9dHyEpc#|EM!>I3kM~=uq-HTEUaPFz0&YZ@hS6k;>-yVodx!n0#Gyr^UxU9_8 zkoL05E#ezZsv+MFpZRP+-OFy%ktZeTLVEq$a`4T0Z}5D|<>HI*1n@=ZYd@}rWW?6r ziEj=Yh4aMWYY%tdpy$zi?q`x!EsU!lIlUeDvScIF1r2!CzgD_E*4L;Ii|s_w;l&1#c z{VLZr!#t`|!DrQq66krEIb}X9U3=6IuQ=I?zgGW>Tn%x*GdO>wU#z=+?srArwT#Ek z`P>!y$#ENr%l*fBU0=P@6!2MiTshKssq!K15w9NjO(OB6v8~mraZO-5Z}p zYyqD~1o@KQC@Ml7Xb+aU_}YuvxZgZ@`@F>w;m|MXxR2st4_YL7Ja(PvsJv#!_x(kzU*# zV#Vw1-v_BUfAzQ|I}ZYU@n__D(raCoq9+m>wQXLUH^O2@jH;OpbtVm~?cuV+Q$ z{FSr6!#XHs1nEs}&s^fmRwteJraOK<#ESo?P1gU;$&ne*|9hD$e!g;$iTK7Wwa+&J zKKrWk7V>L3-(cUUOE>>XL+~}&xX?W6Q-(|fpDh{zzIc>vt?$mJuKbAorL6Z$e3G4K0lt~k7Vk%GbLJy^UU&SL zmVs|vc=C$IjgL=Q`)l}rP%lpY`P=ubx}3S)IVZbwrI)9M?V`Bl-gKPn>e9uRul8H< zADdD{eDlx<Mt&{hAerH1(R&%UtF2LZlbyTHm%y70Pxjh!jr>%Ft^e^f5{0eoJq ztgHUnC#BKX`sO+H(}Sycv}K#E?}v91ocE3^els!?eDi$vQ{>NY0{B`{f$RKdMJ4e( z+M>*4=$HUs#_!)p`C*5vIPV=7U*FujfmFlh`PAohpRxHM&L7_IF7oZ Date: Thu, 23 Mar 2023 16:35:51 +0100 Subject: [PATCH 05/44] ignore builds --- .gitignore | 19 +- build/lib/dacbench/__init__.py | 8 - build/lib/dacbench/abstract_agent.py | 57 -- build/lib/dacbench/abstract_benchmark.py | 567 ----------- build/lib/dacbench/abstract_env.py | 374 ------- build/lib/dacbench/agents/__init__.py | 5 - .../dacbench/agents/dynamic_random_agent.py | 30 - build/lib/dacbench/agents/generic_agent.py | 16 - build/lib/dacbench/agents/simple_agents.py | 36 - build/lib/dacbench/argument_parsing.py | 69 -- build/lib/dacbench/benchmarks/__init__.py | 73 -- .../lib/dacbench/benchmarks/cma_benchmark.py | 162 ---- .../benchmarks/fast_downward_benchmark.py | 192 ---- .../benchmarks/geometric_benchmark.py | 304 ------ .../lib/dacbench/benchmarks/luby_benchmark.py | 189 ---- .../dacbench/benchmarks/modcma_benchmark.py | 134 --- .../dacbench/benchmarks/modea_benchmark.py | 114 --- .../lib/dacbench/benchmarks/sgd_benchmark.py | 219 ----- .../dacbench/benchmarks/sigmoid_benchmark.py | 254 ----- .../dacbench/benchmarks/theory_benchmark.py | 169 ---- .../dacbench/benchmarks/toysgd_benchmark.py | 122 --- build/lib/dacbench/container/__init__.py | 0 .../lib/dacbench/container/container_utils.py | 191 ---- build/lib/dacbench/container/remote_env.py | 81 -- build/lib/dacbench/container/remote_runner.py | 278 ------ build/lib/dacbench/envs/__init__.py | 81 -- build/lib/dacbench/envs/cma_es.py | 255 ----- build/lib/dacbench/envs/cma_step_size.py | 54 -- build/lib/dacbench/envs/fast_downward.py | 452 --------- build/lib/dacbench/envs/geometric.py | 665 ------------- build/lib/dacbench/envs/luby.py | 180 ---- build/lib/dacbench/envs/modcma.py | 60 -- build/lib/dacbench/envs/modea.py | 289 ------ build/lib/dacbench/envs/policies/__init__.py | 14 - build/lib/dacbench/envs/policies/csa_cma.py | 7 - .../lib/dacbench/envs/policies/optimal_fd.py | 8 - .../dacbench/envs/policies/optimal_luby.py | 14 - .../dacbench/envs/policies/optimal_sigmoid.py | 25 - build/lib/dacbench/envs/policies/sgd_ca.py | 33 - build/lib/dacbench/envs/sgd.py | 891 ----------------- build/lib/dacbench/envs/sigmoid.py | 325 ------- build/lib/dacbench/envs/theory.py | 574 ----------- build/lib/dacbench/envs/toysgd.py | 234 ----- build/lib/dacbench/logger.py | 915 ------------------ build/lib/dacbench/plotting.py | 557 ----------- build/lib/dacbench/run_baselines.py | 248 ----- build/lib/dacbench/runner.py | 94 -- build/lib/dacbench/wrappers/__init__.py | 20 - .../wrappers/action_tracking_wrapper.py | 259 ----- .../dacbench/wrappers/episode_time_tracker.py | 243 ----- .../wrappers/instance_sampling_wrapper.py | 112 --- .../dacbench/wrappers/observation_wrapper.py | 106 -- .../wrappers/performance_tracking_wrapper.py | 204 ---- .../wrappers/policy_progress_wrapper.py | 107 -- .../dacbench/wrappers/reward_noise_wrapper.py | 119 --- .../wrappers/state_tracking_wrapper.py | 289 ------ 56 files changed, 2 insertions(+), 11095 deletions(-) delete mode 100644 build/lib/dacbench/__init__.py delete mode 100644 build/lib/dacbench/abstract_agent.py delete mode 100644 build/lib/dacbench/abstract_benchmark.py delete mode 100644 build/lib/dacbench/abstract_env.py delete mode 100644 build/lib/dacbench/agents/__init__.py delete mode 100644 build/lib/dacbench/agents/dynamic_random_agent.py delete mode 100644 build/lib/dacbench/agents/generic_agent.py delete mode 100644 build/lib/dacbench/agents/simple_agents.py delete mode 100644 build/lib/dacbench/argument_parsing.py delete mode 100644 build/lib/dacbench/benchmarks/__init__.py delete mode 100644 build/lib/dacbench/benchmarks/cma_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/fast_downward_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/geometric_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/luby_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/modcma_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/modea_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/sgd_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/sigmoid_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/theory_benchmark.py delete mode 100644 build/lib/dacbench/benchmarks/toysgd_benchmark.py delete mode 100644 build/lib/dacbench/container/__init__.py delete mode 100644 build/lib/dacbench/container/container_utils.py delete mode 100644 build/lib/dacbench/container/remote_env.py delete mode 100644 build/lib/dacbench/container/remote_runner.py delete mode 100644 build/lib/dacbench/envs/__init__.py delete mode 100644 build/lib/dacbench/envs/cma_es.py delete mode 100644 build/lib/dacbench/envs/cma_step_size.py delete mode 100644 build/lib/dacbench/envs/fast_downward.py delete mode 100644 build/lib/dacbench/envs/geometric.py delete mode 100644 build/lib/dacbench/envs/luby.py delete mode 100644 build/lib/dacbench/envs/modcma.py delete mode 100644 build/lib/dacbench/envs/modea.py delete mode 100644 build/lib/dacbench/envs/policies/__init__.py delete mode 100644 build/lib/dacbench/envs/policies/csa_cma.py delete mode 100644 build/lib/dacbench/envs/policies/optimal_fd.py delete mode 100644 build/lib/dacbench/envs/policies/optimal_luby.py delete mode 100644 build/lib/dacbench/envs/policies/optimal_sigmoid.py delete mode 100644 build/lib/dacbench/envs/policies/sgd_ca.py delete mode 100644 build/lib/dacbench/envs/sgd.py delete mode 100644 build/lib/dacbench/envs/sigmoid.py delete mode 100644 build/lib/dacbench/envs/theory.py delete mode 100644 build/lib/dacbench/envs/toysgd.py delete mode 100644 build/lib/dacbench/logger.py delete mode 100644 build/lib/dacbench/plotting.py delete mode 100644 build/lib/dacbench/run_baselines.py delete mode 100644 build/lib/dacbench/runner.py delete mode 100644 build/lib/dacbench/wrappers/__init__.py delete mode 100644 build/lib/dacbench/wrappers/action_tracking_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/episode_time_tracker.py delete mode 100644 build/lib/dacbench/wrappers/instance_sampling_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/observation_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/performance_tracking_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/policy_progress_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/reward_noise_wrapper.py delete mode 100644 build/lib/dacbench/wrappers/state_tracking_wrapper.py diff --git a/.gitignore b/.gitignore index 359c1a4af..c0ddda1c3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,34 +2,19 @@ __pycache__/ *.py[cod] .ipynb_checkpoints -.flake8 +tox.ini *.egg-info/ -# docs -docs/_build/* # project spcecific stuff TODOS.md builds/ - -# coverage -coverage_report/* -.coverage +build/ ## results, data or temp files written during runs output/ port_*.txt tests/data/ test/*.json -test_run -/data/ # pycharm specific stuff .idea - - -venv -settings.json -*egg - - -.vscode/launch.json diff --git a/build/lib/dacbench/__init__.py b/build/lib/dacbench/__init__.py deleted file mode 100644 index 08e6071b6..000000000 --- a/build/lib/dacbench/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""DACBench: a benchmark library for Dynamic Algorithm Configuration""" -__version__ = "0.0.1" -__contact__ = "automl.org" - -from dacbench.abstract_env import AbstractEnv -from dacbench.abstract_benchmark import AbstractBenchmark - -__all__ = ["AbstractEnv", "AbstractBenchmark"] diff --git a/build/lib/dacbench/abstract_agent.py b/build/lib/dacbench/abstract_agent.py deleted file mode 100644 index 58016ca13..000000000 --- a/build/lib/dacbench/abstract_agent.py +++ /dev/null @@ -1,57 +0,0 @@ -class AbstractDACBenchAgent: - """ Abstract class to implement for use with the runner function """ - - def __init__(self, env): - """ - Initialize agent - - Parameters - ------- - env : gym.Env - Environment to train on - """ - pass - - def act(self, state, reward): - """ - Compute and return environment action - - Parameters - ------- - state - Environment state - reward - Environment reward - - Returns - ------- - action - Action to take - """ - raise NotImplementedError - - def train(self, next_state, reward): - """ - Train during episode if needed (pass if not) - - Parameters - ------- - next_state - Environment state after step - reward - Environment reward - """ - raise NotImplementedError - - def end_episode(self, state, reward): - """ - End of episode training if needed (pass if not) - - Parameters - ------- - state - Environment state - reward - Environment reward - """ - raise NotImplementedError diff --git a/build/lib/dacbench/abstract_benchmark.py b/build/lib/dacbench/abstract_benchmark.py deleted file mode 100644 index 679b37be8..000000000 --- a/build/lib/dacbench/abstract_benchmark.py +++ /dev/null @@ -1,567 +0,0 @@ -import json -from types import FunctionType - -import numpy as np -from gymnasium import spaces -from functools import partial -from dacbench import wrappers - -# from dacbench import ModuleLogger - - -class AbstractBenchmark: - """ - Abstract template for benchmark classes - """ - - def __init__(self, config_path=None, config: "objdict" = None): - """ - Initialize benchmark class - - Parameters - ------- - config_path : str - Path to load configuration from (if read from file) - config : objdict - Object dict containing the config - """ - if config is not None and config_path is not None: - raise ValueError("Both path to config and config where provided") - self.wrap_funcs = [] - if config_path: - self.config_path = config_path - self.read_config_file(self.config_path) - elif config: - self.load_config(config) - else: - self.config = None - - def get_config(self): - """ - Return current configuration - - Returns - ------- - dict - Current config - """ - return self.config - - def serialize_config(self): - """ - Save configuration to json - - Parameters - ---------- - path : str - File to save config to - """ - conf = self.config.copy() - if "observation_space_type" in self.config: - conf["observation_space_type"] = f"{self.config['observation_space_type']}" - if isinstance(conf["observation_space_args"][0], dict): - conf["observation_space_args"] = self.jsonify_dict_space( - conf["observation_space_args"][0] - ) - elif "observation_space" in self.config: - conf["observation_space"] = self.space_to_list(conf["observation_space"]) - - if "action_space" in self.config: - conf["action_space"] = self.space_to_list(conf["action_space"]) - - # TODO: how can we use the built in serialization of configspace here? - if "config_space" in self.config: - conf["config_space"] = self.process_configspace(self.config.config_space) - - conf = AbstractBenchmark.__stringify_functions(conf) - - for k in self.config.keys(): - if isinstance(self.config[k], np.ndarray) or isinstance( - self.config[k], list - ): - if type(self.config[k][0]) == np.ndarray: - conf[k] = list(map(list, conf[k])) - for i in range(len(conf[k])): - if ( - not type(conf[k][i][0]) == float - and np.inf not in conf[k][i] - and -np.inf not in conf[k][i] - ): - conf[k][i] = list(map(int, conf[k][i])) - elif isinstance(conf[k], np.ndarray): - conf[k] = conf[k].tolist() - - conf["wrappers"] = self.jsonify_wrappers() - - # can be recovered from instance_set_path, and could contain function that are not serializable - if "instance_set" in conf: - del conf["instance_set"] - - return conf - - def process_configspace(self, configuration_space): - """ - This is largely the builting cs.json.write method, but doesn't save the result directly - If this is ever implemented in cs, we can replace this method - """ - from ConfigSpace.configuration_space import ConfigurationSpace - from ConfigSpace.hyperparameters import ( - CategoricalHyperparameter, - UniformIntegerHyperparameter, - UniformFloatHyperparameter, - NormalIntegerHyperparameter, - NormalFloatHyperparameter, - OrdinalHyperparameter, - Constant, - UnParametrizedHyperparameter, - ) - from ConfigSpace.read_and_write.json import ( - _build_constant, - _build_condition, - _build_ordinal, - _build_forbidden, - _build_categorical, - _build_normal_int, - _build_normal_float, - _build_uniform_float, - _build_uniform_int, - _build_unparametrized_hyperparameter, - ) - - if not isinstance(configuration_space, ConfigurationSpace): - raise TypeError( - "pcs_parser.write expects an instance of %s, " - "you provided '%s'" % (ConfigurationSpace, type(configuration_space)) - ) - - hyperparameters = [] - conditions = [] - forbiddens = [] - - for hyperparameter in configuration_space.get_hyperparameters(): - - if isinstance(hyperparameter, Constant): - hyperparameters.append(_build_constant(hyperparameter)) - elif isinstance(hyperparameter, UnParametrizedHyperparameter): - hyperparameters.append( - _build_unparametrized_hyperparameter(hyperparameter) - ) - elif isinstance(hyperparameter, UniformFloatHyperparameter): - hyperparameters.append(_build_uniform_float(hyperparameter)) - elif isinstance(hyperparameter, NormalFloatHyperparameter): - hyperparameters.append(_build_normal_float(hyperparameter)) - elif isinstance(hyperparameter, UniformIntegerHyperparameter): - hyperparameters.append(_build_uniform_int(hyperparameter)) - elif isinstance(hyperparameter, NormalIntegerHyperparameter): - hyperparameters.append(_build_normal_int(hyperparameter)) - elif isinstance(hyperparameter, CategoricalHyperparameter): - hyperparameters.append(_build_categorical(hyperparameter)) - elif isinstance(hyperparameter, OrdinalHyperparameter): - hyperparameters.append(_build_ordinal(hyperparameter)) - else: - raise TypeError( - "Unknown type: %s (%s)" % (type(hyperparameter), hyperparameter,) - ) - - for condition in configuration_space.get_conditions(): - conditions.append(_build_condition(condition)) - - for forbidden_clause in configuration_space.get_forbiddens(): - forbiddens.append(_build_forbidden(forbidden_clause)) - - rval = {} - if configuration_space.name is not None: - rval["name"] = configuration_space.name - rval["hyperparameters"] = hyperparameters - rval["conditions"] = conditions - rval["forbiddens"] = forbiddens - - return rval - - @classmethod - def from_json(cls, json_config): - config = objdict(json.loads(json_config)) - if "config_space" in config.keys(): - from ConfigSpace import ConfigurationSpace - from ConfigSpace.read_and_write.json import ( - _construct_hyperparameter, - _construct_forbidden, - _construct_condition, - ) - - if "name" in config.config_space: - configuration_space = ConfigurationSpace( - name=config.config_space["name"] - ) - else: - configuration_space = ConfigurationSpace() - - for hyperparameter in config.config_space["hyperparameters"]: - configuration_space.add_hyperparameter( - _construct_hyperparameter(hyperparameter,) - ) - - for condition in config.config_space["conditions"]: - configuration_space.add_condition( - _construct_condition(condition, configuration_space,) - ) - - for forbidden in config.config_space["forbiddens"]: - configuration_space.add_forbidden_clause( - _construct_forbidden(forbidden, configuration_space,) - ) - config.config_space = configuration_space - - return cls(config=config) - - def to_json(self): - conf = self.serialize_config() - return json.dumps(conf) - - def save_config(self, path): - conf = self.serialize_config() - with open(path, "w") as fp: - json.dump(conf, fp, default=lambda o: "not serializable") - - def jsonify_wrappers(self): - wrappers = [] - for func in self.wrap_funcs: - args = func.args - arg_descriptions = [] - contains_func = False - func_dict = {} - for i in range(len(args)): - if callable(args[i]): - contains_func = True - func_dict[f"{args[i]}"] = [args[i].__module__, args[i].__name__] - arg_descriptions.append(["function", f"{args[i]}"]) - # elif isinstance(args[i], ModuleLogger): - # pass - else: - arg_descriptions.append({args[i]}) - function = func.func.__name__ - if contains_func: - wrappers.append([function, arg_descriptions, func_dict]) - else: - wrappers.append([function, arg_descriptions]) - return wrappers - - def dejson_wrappers(self, wrapper_list): - for i in range(len(wrapper_list)): - import importlib - - func = getattr(wrappers, wrapper_list[i][0]) - arg_descriptions = wrapper_list[i][1] - args = [] - for a in arg_descriptions: - if a[0] == "function": - module = importlib.import_module(wrapper_list[i][2][a[1]][0]) - name = wrapper_list[i][2][a[1]][0] - func = getattr(module, name) - args.append(func) - # elif a[0] == "logger": - # pass - else: - args.append(a) - - self.wrap_funcs.append(partial(func, *args)) - - @staticmethod - def __import_from(module: str, name: str): - """ - Imports the class / function / ... with name from module - Parameters - ---------- - module - name - - Returns - ------- - the imported object - """ - module = __import__(module, fromlist=[name]) - return getattr(module, name) - - @classmethod - def class_to_str(cls): - return cls.__module__, cls.__name__ - - @staticmethod - def __decorate_config_with_functions(conf: dict): - """ - Replaced the stringified functions with the callable objects - Parameters - ---------- - config - - Returns - ------- - - """ - for key, value in { - k: v - for k, v in conf.items() - if isinstance(v, list) and len(v) == 3 and v[0] == "function" - }.items(): - _, module_name, function_name = value - conf[key] = AbstractBenchmark.__import_from(module_name, function_name) - return conf - - @staticmethod - def __stringify_functions(conf: dict) -> dict: - """ - Replaced all callables in the config with a - triple ('function', module_name, function_name) - - Parameters - ---------- - config - - Returns - ------- - modified dict - """ - for key, value in { - k: v for k, v in conf.items() if isinstance(v, FunctionType) - }.items(): - conf[key] = ["function", conf[key].__module__, conf[key].__name__] - return conf - - def space_to_list(self, space): - res = [] - if isinstance(space, spaces.Box): - res.append("Box") - res.append([space.low.tolist(), space.high.tolist()]) - res.append("numpy.float32") - elif isinstance(space, spaces.Discrete): - res.append("Discrete") - res.append([space.n]) - elif isinstance(space, spaces.Dict): - res.append("Dict") - res.append(self.jsonify_dict_space(space.spaces)) - elif isinstance(space, spaces.MultiDiscrete): - res.append("MultiDiscrete") - res.append([space.nvec]) - elif isinstance(space, spaces.MultiBinary): - res.append("MultiBinary") - res.append([space.n]) - return res - - def list_to_space(self, space_list): - if space_list[0] == "Dict": - args = self.dictify_json(space_list[1]) - space = getattr(spaces, space_list[0])(args) - elif len(space_list) == 2: - space = getattr(spaces, space_list[0])(*space_list[1]) - else: - typestring = space_list[2].split(".")[1] - dt = getattr(np, typestring) - args = [np.array(arg) for arg in space_list[1]] - space = getattr(spaces, space_list[0])(*args, dtype=dt) - return space - - def jsonify_dict_space(self, dict_space): - keys = [] - types = [] - arguments = [] - for k in dict_space.keys(): - keys.append(k) - value = dict_space[k] - if not isinstance(value, (spaces.Box, spaces.Discrete)): - raise ValueError( - f"Only Dict spaces made up of Box spaces or discrete spaces are supported but got {type(value)}" - ) - - if isinstance(value, spaces.Box): - types.append("box") - low = value.low.tolist() - high = value.high.tolist() - arguments.append([low, high]) - - if isinstance(value, spaces.Discrete): - types.append("discrete") - n = value.n - arguments.append([n]) - return [keys, types, arguments] - - def dictify_json(self, dict_list): - dict_space = {} - keys, types, args = dict_list - for k, type, args_ in zip(keys, types, args): - prepared_args = map(np.array, args_) - if type == "box": - dict_space[k] = spaces.Box(*prepared_args, dtype=np.float32) - elif type == "discrete": - dict_space[k] = spaces.Discrete(*prepared_args) - else: - raise TypeError( - f"Currently only Discrete and Box spaces are allowed in Dict spaces, got {type}" - ) - return dict_space - - def load_config(self, config: "objdict"): - self.config = config - if "observation_space_type" in self.config: - # Types have to be numpy dtype (for gym spaces)s - if type(self.config["observation_space_type"]) == str: - if self.config["observation_space_type"] == "None": - self.config["observation_space_type"] = None - else: - typestring = self.config["observation_space_type"].split(" ")[1][ - :-2 - ] - typestring = typestring.split(".")[1] - self.config["observation_space_type"] = getattr(np, typestring) - - if "observation_space" in self.config: - self.config["observation_space"] = self.list_to_space( - self.config["observation_space"] - ) - - elif "observation_space_class" in config.keys(): - if config.observation_space_class == "Dict": - self.config["observation_space_args"] = [ - self.dictify_json(self.config["observation_space_args"]) - ] - - if "action_space" in self.config: - self.config["action_space"] = self.list_to_space( - self.config["action_space"] - ) - - if "wrappers" in self.config: - self.dejson_wrappers(self.config["wrappers"]) - del self.config["wrappers"] - - self.config = AbstractBenchmark.__decorate_config_with_functions(self.config) - - for k in self.config.keys(): - if type(self.config[k]) == list: - if type(self.config[k][0]) == list: - map(np.array, self.config[k]) - self.config[k] = np.array(self.config[k]) - - def read_config_file(self, path): - """ - Read configuration from file - - Parameters - ---------- - path : str - Path to config file - """ - with open(path, "r") as fp: - config = objdict(json.load(fp)) - - self.load_config(config) - - def get_environment(self): - """ - Make benchmark environment - - Returns - ------- - env : gym.Env - Benchmark environment - """ - raise NotImplementedError - - def set_seed(self, seed): - """ - Set environment seed - - Parameters - ---------- - seed : int - New seed - """ - self.config["seed"] = seed - - def set_action_space(self, kind, args): - """ - Change action space - - Parameters - ---------- - kind : str - Name of action space class - args: list - List of arguments to pass to action space class - """ - self.config["action_space"] = kind - self.config["action_space_args"] = args - - def set_observation_space(self, kind, args, data_type): - """ - Change observation_space - - Parameters - ---------- - kind : str - Name of observation space class - args : list - List of arguments to pass to observation space class - data_type : type - Data type of observation space - """ - self.config["observation_space"] = kind - self.config["observation_space_args"] = args - self.config["observation_space_type"] = data_type - - def register_wrapper(self, wrap_func): - if isinstance(wrap_func, list): - self.wrap_funcs.append(*wrap_func) - else: - self.wrap_funcs.append(wrap_func) - - def __eq__(self, other): - return type(self) == type(other) and self.config == other.config - - -# This code is taken from https://goodcode.io/articles/python-dict-object/ -class objdict(dict): - """ - Modified dict to make config changes more flexible - """ - - def __getattr__(self, name): - if name in self: - return self[name] - else: - raise AttributeError("No such attribute: " + name) - - def __setattr__(self, name, value): - self[name] = value - - def __delattr__(self, name): - if name in self: - del self[name] - else: - raise AttributeError("No such attribute: " + name) - - def copy(self): - return objdict(**super().copy()) - - def __eq__(self, other): - """return isinstance(other, dict) \ - and set(other.keys()) == set(self.keys()) \ - and all( - np.array_equal(self[key], other[key]) - if any(isinstance(obj[key], np.ndarray) for obj in (self, other)) - else other[key] == self[key] - for key in self.keys() - )""" - if not isinstance(other, dict): - return False - if not set(other.keys()) == set(self.keys()): - return False - truth = [] - for key in self.keys(): - if any(isinstance(obj[key], np.ndarray) for obj in (self, other)): - truth.append(np.array_equal(self[key], other[key])) - else: - truth.append(other[key] == self[key]) - return all(truth) - - def __ne__(self, other): - return not self == other diff --git a/build/lib/dacbench/abstract_env.py b/build/lib/dacbench/abstract_env.py deleted file mode 100644 index 373259a14..000000000 --- a/build/lib/dacbench/abstract_env.py +++ /dev/null @@ -1,374 +0,0 @@ -import random - -import gymnasium as gym -from gymnasium.utils import seeding -import numpy as np - - -class AbstractEnv(gym.Env): - """ - Abstract template for environments - """ - - def __init__(self, config): - """ - Initialize environment - - Parameters - ------- - config : dict - Environment configuration - If to seed the action space as well - """ - super(AbstractEnv, self).__init__() - self.config = config - if "instance_update_func" in self.config.keys(): - self.instance_updates = self.config["instance_update_func"] - else: - self.instance_updates = "round_robin" - self.instance_set = config["instance_set"] - self.instance_id_list = sorted(list(self.instance_set.keys())) - self.instance_index = 0 - self.inst_id = self.instance_id_list[self.instance_index] - self.instance = self.instance_set[self.inst_id] - - self.test = False - if "test_set" in self.config.keys(): - self.test_set = config["test_set"] - self.test_instance_id_list = sorted(list(self.test_set.keys())) - self.test_instance_index = 0 - self.test_inst_id = self.test_instance_id_list[self.test_instance_index] - self.test_instance = self.test_set[self.test_inst_id] - - self.training_set = self.instance_set - self.training_id_list = self.instance_id_list - self.training_inst_id = self.inst_id - self.training_instance = self.instance - else: - self.test_set = None - - self.benchmark_info = config["benchmark_info"] - self.initial_seed = None - self.np_random = None - - self.n_steps = config["cutoff"] - self.c_step = 0 - - self.reward_range = config["reward_range"] - - if "observation_space" in config.keys(): - self.observation_space = config["observation_space"] - else: - if not config["observation_space_class"] == "Dict": - try: - self.observation_space = getattr( - gym.spaces, config["observation_space_class"] - )( - *config["observation_space_args"], - dtype=config["observation_space_type"], - ) - except KeyError: - print( - "Either submit a predefined gym.space 'observation_space' or an 'observation_space_class' as well as a list of 'observation_space_args' and the 'observation_space_type' in the configuration." - ) - print("Tuple observation_spaces are currently not supported.") - raise KeyError - - else: - try: - self.observation_space = getattr( - gym.spaces, config["observation_space_class"] - )(*config["observation_space_args"]) - except TypeError: - print( - "To use a Dict observation space, the 'observation_space_args' in the configuration should be a list containing a Dict of gym.Spaces" - ) - raise TypeError - - # TODO: use dicts by default for actions and observations - # The config could change this for RL purposes - if "config_space" in config.keys(): - actions = config["config_space"].get_hyperparameters() - action_types = [type(a).__name__ for a in actions] - - # Uniform action space - if all(t == action_types[0] for t in action_types): - if "Float" in action_types[0]: - low = np.array([a.lower for a in actions]) - high = np.array([a.upper for a in actions]) - self.action_space = gym.spaces.Box(low=low, high=high) - elif "Integer" in action_types[0] or "Categorical" in action_types[0]: - if len(action_types) == 1: - try: - n = actions[0].upper - actions[0].lower - except: - n = len(actions[0].choices) - self.action_space = gym.spaces.Discrete(n) - else: - ns = [] - for a in actions: - try: - ns.append(a.upper - a.lower) - except: - ns.append(len(a.choices)) - self.action_space = gym.spaces.MultiDiscrete(np.array(ns)) - else: - raise ValueError( - "Only float, integer and categorical hyperparameters are supported as of now" - ) - # Mixed action space - # TODO: implement this - else: - raise ValueError("Mixed type config spaces are currently not supported") - elif "action_space" in config.keys(): - self.action_space = config["action_space"] - else: - try: - self.action_space = getattr(gym.spaces, config["action_space_class"])( - *config["action_space_args"] - ) - except KeyError: - print( - "Either submit a predefined gym.space 'action_space' or an 'action_space_class' as well as a list of 'action_space_args' in the configuration" - ) - raise KeyError - - except TypeError: - print("Tuple and Dict action spaces are currently not supported") - raise TypeError - - # seeding the environment after initialising action space - self.seed(config.get("seed", None), config.get("seed_action_space", False)) - - def step_(self): - """ - Pre-step function for step count and cutoff - - Returns - ------- - bool - End of episode - """ - trucated = False - self.c_step += 1 - if self.c_step >= self.n_steps: - truncated = True - return truncated - - def reset_(self, instance=None, instance_id=None, scheme=None): - """ - Pre-reset function for progressing through the instance set - Will either use round robin, random or no progression scheme - """ - self.c_step = 0 - if scheme is None: - scheme = self.instance_updates - self.use_next_instance(instance, instance_id, scheme=scheme) - - def use_next_instance(self, instance=None, instance_id=None, scheme=None): - """ - Changes instance according to chosen instance progession - - Parameters - ------- - instance - Instance specification for potentional new instances - instance_id - ID of the instance to switch to - scheme - Update scheme for this progression step (either round robin, random or no progression) - """ - if instance is not None: - self.instance = instance - elif instance_id is not None: - self.inst_id = instance_id - self.instance = self.instance_set[self.inst_id] - elif scheme == "round_robin": - self.instance_index = (self.instance_index + 1) % len(self.instance_id_list) - self.inst_id = self.instance_id_list[self.instance_index] - self.instance = self.instance_set[self.inst_id] - elif scheme == "random": - self.inst_id = np.random.choice(self.instance_id_list) - self.instance = self.instance_set[self.inst_id] - - def step(self, action): - """ - Execute environment step - - Parameters - ------- - action - Action to take - - Returns - ------- - state - Environment state - reward - Environment reward - terminated: bool - Run finished flag - truncated: bool - Run timed out flag - info : dict - Additional metainfo - """ - raise NotImplementedError - - def reset(self): - """ - Reset environment - - Returns - ------- - state - Environment state - info: dict - Additional metainfo - """ - raise NotImplementedError - - def get_inst_id(self): - """ - Return instance ID - - Returns - ------- - int - ID of current instance - """ - return self.inst_id - - def get_instance_set(self): - """ - Return instance set - - Returns - ------- - list - List of instances - - """ - return self.instance_set - - def get_instance(self): - """ - Return current instance - - Returns - ------- - type flexible - Currently used instance - """ - return self.instance - - def set_inst_id(self, inst_id): - """ - Change current instance ID - - Parameters - ---------- - inst_id : int - New instance index - """ - self.inst_id = inst_id - self.instance_index = self.instance_id_list.index(self.inst_id) - - def set_instance_set(self, inst_set): - """ - Change instance set - - Parameters - ---------- - inst_set: list - New instance set - """ - self.instance_set = inst_set - self.instance_id_list = sorted(list(self.instance_set.keys())) - - def set_instance(self, instance): - """ - Change currently used instance - - Parameters - ---------- - instance: - New instance - """ - self.instance = instance - - def seed_action_space(self, seed=None): - """ - Seeds the action space. - Parameters - ---------- - seed : int, default None - if None self.initial_seed is be used - - Returns - ------- - - """ - if seed is None: - seed = self.initial_seed - - self.action_space.seed(seed) - - def seed(self, seed=None, seed_action_space=False): - """ - Set rng seed - - Parameters - ---------- - seed: - seed for rng - seed_action_space: bool, default False - if to seed the action space as well - """ - - self.initial_seed = seed - # maybe one should use the seed generated by seeding.np_random(seed) but it can be to large see issue https://github.com/openai/gym/issues/2210 - random.seed(seed) - np.random.seed(seed) - self.np_random, seed = seeding.np_random(seed) - # uses the uncorrelated seed from seeding but makes sure that no randomness is introduces. - - if seed_action_space: - self.seed_action_space() - - return [seed] - - def use_test_set(self): - """ - Change to test instance set - """ - if self.test_set is None: - raise ValueError( - "No test set was provided, please check your benchmark config." - ) - - self.test = True - self.training_set = self.instance_set - self.training_id_list = self.instance_id_list - self.training_inst_id = self.inst_id - self.training_instance = self.instance - - self.instance_set = self.test_set - self.instance_id_list = self.test_instance_id_list - self.inst_id = self.test_inst_id - self.instance = self.test_instance - - def use_training_set(self): - """ - Change to training instance set - """ - self.test = False - self.test_set = self.instance_set - self.test_instance_id_list = self.instance_id_list - self.test_inst_id = self.inst_id - self.test_instance = self.instance - - self.instance_set = self.training_set - self.instance_id_list = self.training_id_list - self.inst_id = self.training_inst_id - self.instance = self.training_instance diff --git a/build/lib/dacbench/agents/__init__.py b/build/lib/dacbench/agents/__init__.py deleted file mode 100644 index caabeed61..000000000 --- a/build/lib/dacbench/agents/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from dacbench.agents.generic_agent import GenericAgent -from dacbench.agents.simple_agents import RandomAgent, StaticAgent -from dacbench.agents.dynamic_random_agent import DynamicRandomAgent - -__all__ = ["StaticAgent", "RandomAgent", "GenericAgent", "DynamicRandomAgent"] diff --git a/build/lib/dacbench/agents/dynamic_random_agent.py b/build/lib/dacbench/agents/dynamic_random_agent.py deleted file mode 100644 index 2f312834b..000000000 --- a/build/lib/dacbench/agents/dynamic_random_agent.py +++ /dev/null @@ -1,30 +0,0 @@ -from dacbench.abstract_agent import AbstractDACBenchAgent -from gymnasium import spaces - - -class DynamicRandomAgent(AbstractDACBenchAgent): - def __init__(self, env, switching_interval): - self.sample_action = env.action_space.sample - self.switching_interval = switching_interval - self.count = 0 - self.action = self.sample_action() - self.shortbox = ( - isinstance(env.action_space, spaces.Box) and len(env.action_space.low) == 1 - ) - - def act(self, state, reward): - if self.count >= self.switching_interval: - self.action = self.sample_action() - self.count = 0 - self.count += 1 - - if self.shortbox: - return self.action[0] - else: - return self.action - - def train(self, next_state, reward): - pass - - def end_episode(self, state, reward): - pass diff --git a/build/lib/dacbench/agents/generic_agent.py b/build/lib/dacbench/agents/generic_agent.py deleted file mode 100644 index bc16b0b06..000000000 --- a/build/lib/dacbench/agents/generic_agent.py +++ /dev/null @@ -1,16 +0,0 @@ -from dacbench.abstract_agent import AbstractDACBenchAgent - - -class GenericAgent(AbstractDACBenchAgent): - def __init__(self, env, policy): - self.policy = policy - self.env = env - - def act(self, state, reward): - return self.policy(self.env, state) - - def train(self, next_state, reward): - pass - - def end_episode(self, state, reward): - pass diff --git a/build/lib/dacbench/agents/simple_agents.py b/build/lib/dacbench/agents/simple_agents.py deleted file mode 100644 index 3fc6a7f0c..000000000 --- a/build/lib/dacbench/agents/simple_agents.py +++ /dev/null @@ -1,36 +0,0 @@ -from dacbench.abstract_agent import AbstractDACBenchAgent -from gymnasium import spaces - - -class RandomAgent(AbstractDACBenchAgent): - def __init__(self, env): - self.sample_action = env.action_space.sample - self.shortbox = isinstance(env.action_space, spaces.Box) - if self.shortbox: - self.shortbox = self.shortbox and len(env.action_space.low) == 1 - - def act(self, state, reward): - if self.shortbox: - return self.sample_action()[0] - else: - return self.sample_action() - - def train(self, next_state, reward): - pass - - def end_episode(self, state, reward): - pass - - -class StaticAgent(AbstractDACBenchAgent): - def __init__(self, env, action): - self.action = action - - def act(self, state, reward): - return self.action - - def train(self, next_state, reward): - pass - - def end_episode(self, state, reward): - pass diff --git a/build/lib/dacbench/argument_parsing.py b/build/lib/dacbench/argument_parsing.py deleted file mode 100644 index c1a1e7c9c..000000000 --- a/build/lib/dacbench/argument_parsing.py +++ /dev/null @@ -1,69 +0,0 @@ -from argparse import ArgumentTypeError as err -from pathlib import Path - - -class PathType(object): - """ - Custom argument type for path validation. - - Adapted from: https://stackoverflow.com/questions/11415570/directory-path-types-with-argparse - """ - - def __init__(self, exists=True, type='file', dash_ok=True): - ''' - - Parameters - ---------- - - exists : bool - True: a path that does exist - False: a path that does not exist, in a valid parent directory - None: don't care - type : str - file, dir, symlink, socket, None, or a function returning True for valid paths - None: don't care - dash_ok: whether to allow "-" as stdin/stdout - - ''' - - assert exists in (True, False, None) - assert type in ('file', 'dir', 'symlink', 'socket', None) or hasattr(type, '__call__') - - self._exists = exists - self._type = type - self._dash_ok = dash_ok - - def __call__(self, string: str): - if string == '-': - # the special argument "-" means sys.std{in,out} - if self._type == 'dir': - raise err('standard input/output (-) not allowed as directory path') - elif self._type == 'symlink': - raise err('standard input/output (-) not allowed as symlink path') - elif not self._dash_ok: - raise err('standard input/output (-) not allowed') - - path = Path(string) - - # existence - if self._exists is None: - pass - elif not self._exists == path.exists(): - negate = '' if self._exists else 'not' - positive = '' if not self._exists else 'not' - raise err(f"{self._type.capitalize()} should {negate} exist but does {positive}") - - # type - if self._type is None: - pass - elif isinstance(self._type, str): - check = getattr(path, f'is_{self._type}') - if not check(): - raise err(f"Path is not {self._type}") - elif isinstance(self._type, callable): - if not self._type(path): - raise err("Callable type check failed") - else: - raise err("invalid type to check for") - - return path diff --git a/build/lib/dacbench/benchmarks/__init__.py b/build/lib/dacbench/benchmarks/__init__.py deleted file mode 100644 index 50d412a0f..000000000 --- a/build/lib/dacbench/benchmarks/__init__.py +++ /dev/null @@ -1,73 +0,0 @@ -# flake8: noqa: F401 -from dacbench.benchmarks.luby_benchmark import LubyBenchmark -from dacbench.benchmarks.sigmoid_benchmark import SigmoidBenchmark -from dacbench.benchmarks.toysgd_benchmark import ToySGDBenchmark -from dacbench.benchmarks.geometric_benchmark import GeometricBenchmark - -from dacbench.benchmarks.fast_downward_benchmark import FastDownwardBenchmark - -__all__ = [ - "LubyBenchmark", - "SigmoidBenchmark", - "ToySGDBenchmark", - "GeometricBenchmark", - "FastDownwardBenchmark", -] - -import importlib -import warnings - -cma_spec = importlib.util.find_spec("cma") -found = cma_spec is not None -if found: - from dacbench.benchmarks.cma_benchmark import CMAESBenchmark - - __all__.append("CMAESBenchmark") -else: - warnings.warn( - "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -modea_spec = importlib.util.find_spec("modea") -found = modea_spec is not None -if found: - from dacbench.benchmarks.modea_benchmark import ModeaBenchmark - - __all__.append("ModeaBenchmark") -else: - warnings.warn( - "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -modcma_spec = importlib.util.find_spec("modcma") -found = modcma_spec is not None -if found: - from dacbench.benchmarks.modcma_benchmark import ModCMABenchmark - - __all__.append("ModCMABenchmark") -else: - warnings.warn( - "ModCMA Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -sgd_spec = importlib.util.find_spec("backpack") -found = sgd_spec is not None -if found: - from dacbench.benchmarks.sgd_benchmark import SGDBenchmark - - __all__.append("SGDBenchmark") -else: - warnings.warn( - "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -theory_spec = importlib.util.find_spec("uuid") -found = theory_spec is not None -if found: - from dacbench.benchmarks.theory_benchmark import TheoryBenchmark - - __all__.append("TheoryBenchmark") -else: - warnings.warn( - "Theory Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) diff --git a/build/lib/dacbench/benchmarks/cma_benchmark.py b/build/lib/dacbench/benchmarks/cma_benchmark.py deleted file mode 100644 index a22e393ee..000000000 --- a/build/lib/dacbench/benchmarks/cma_benchmark.py +++ /dev/null @@ -1,162 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import CMAESEnv -from gymnasium import spaces -import numpy as np -import os -import csv -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -HISTORY_LENGTH = 40 -INPUT_DIM = 10 - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -STEP_SIZE = CSH.UniformFloatHyperparameter(name='Step_size', lower=0, upper=10) -DEFAULT_CFG_SPACE.add_hyperparameter(STEP_SIZE) - -INFO = { - "identifier": "CMA-ES", - "name": "Step-size adaption in CMA-ES", - "reward": "Negative best function value", - "state_description": [ - "Loc", - "Past Deltas", - "Population Size", - "Sigma", - "History Deltas", - "Past Sigma Deltas", - ], -} - -CMAES_DEFAULTS = objdict( - { - "action_space_class": "Box", - "action_space_args": [np.array([0]), np.array([10])], - "config_space": DEFAULT_CFG_SPACE, - "observation_space_class": "Dict", - "observation_space_type": None, - "observation_space_args": [ - { - "current_loc": spaces.Box( - low=-np.inf, high=np.inf, shape=np.arange(INPUT_DIM).shape - ), - "past_deltas": spaces.Box( - low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH).shape - ), - "current_ps": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), - "current_sigma": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), - "history_deltas": spaces.Box( - low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH * 2).shape - ), - "past_sigma_deltas": spaces.Box( - low=-np.inf, high=np.inf, shape=np.arange(HISTORY_LENGTH).shape - ), - } - ], - "reward_range": (-(10 ** 9), 0), - "cutoff": 1e6, - "hist_length": HISTORY_LENGTH, - "popsize": 10, - "seed": 0, - "instance_set_path": "../instance_sets/cma/cma_train.csv", - "test_set_path": "../instance_sets/cma/cma_test.csv", - "benchmark_info": INFO, - } -) - - -class CMAESBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for CMA-ES - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize CMA Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(CMAESBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(CMAES_DEFAULTS.copy()) - - for key in CMAES_DEFAULTS: - if key not in self.config: - self.config[key] = CMAES_DEFAULTS[key] - - def get_environment(self): - """ - Return CMAESEnv env with current configuration - - Returns - ------- - CMAESEnv - CMAES environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - #Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - env = CMAESEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self, test=False): - """ - Read path of instances from config into list - """ - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - - self.config[keyword] = {} - with open(path, "r") as fh: - reader = csv.DictReader(fh) - for row in reader: - init_locs = [float(row[f"init_loc{i}"]) for i in range(int(row["dim"]))] - instance = [ - int(row["fcn_index"]), - int(row["dim"]), - float(row["init_sigma"]), - init_locs, - ] - self.config[keyword][int(row["ID"])] = instance - - def get_benchmark(self, seed=0): - """ - Get benchmark from the LTO paper - - Parameters - ------- - seed : int - Environment seed - - Returns - ------- - env : CMAESEnv - CMAES environment - """ - self.config = objdict(CMAES_DEFAULTS.copy()) - self.config.seed = seed - self.read_instance_set() - self.read_instance_set(test=True) - return CMAESEnv(self.config) diff --git a/build/lib/dacbench/benchmarks/fast_downward_benchmark.py b/build/lib/dacbench/benchmarks/fast_downward_benchmark.py deleted file mode 100644 index 3d526450d..000000000 --- a/build/lib/dacbench/benchmarks/fast_downward_benchmark.py +++ /dev/null @@ -1,192 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import FastDownwardEnv - -import numpy as np -import os -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -HEURISTICS = [ - "tiebreaking([pdb(pattern=manual_pattern([0,1])),weight(g(),-1)])", - "tiebreaking([pdb(pattern=manual_pattern([0,2])),weight(g(),-1)])", -] - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -HEURISTIC = CSH.CategoricalHyperparameter(name='heuristic', choices=["toy1", "toy2"]) -DEFAULT_CFG_SPACE.add_hyperparameter(HEURISTIC) - -INFO = { - "identifier": "FastDownward", - "name": "Heuristic Selection for the FastDownward Planner", - "reward": "Negative Runtime (-1 per step)", - "state_description": [ - "Average Value (heuristic 1)", - "Max Value (heuristic 1)", - "Min Value (heuristic 1)", - "Open List Entries (heuristic 1)", - "Variance (heuristic 1)", - "Average Value (heuristic 2)", - "Max Value (heuristic 2)", - "Min Value (heuristic 2)", - "Open List Entries (heuristic 2)", - "Variance (heuristic 2)", - ], -} - -FD_DEFAULTS = objdict( - { - "heuristics": HEURISTICS, - "config_space": DEFAULT_CFG_SPACE, - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [ - np.array([-np.inf for _ in range(5 * len(HEURISTICS))]), - np.array([np.inf for _ in range(5 * len(HEURISTICS))]), - ], - "reward_range": (-np.inf, 0), - "cutoff": 1e6, - "use_general_state_info": True, - "host": "", - "port": 54322, - "control_interval": 0, - "fd_seed": 0, - "num_steps": None, - "state_type": 2, - "config_dir": ".", - "port_file_id": None, - "seed": 0, - "max_rand_steps": 0, - "instance_set_path": "../instance_sets/fast_downward/train", - "test_set_path": "../instance_sets/fast_downward/test", - "fd_path": os.path.dirname(os.path.abspath(__file__)) - + "/../envs/rl-plan/fast-downward/fast-downward.py", - "parallel": True, - "fd_logs": None, - "benchmark_info": INFO, - } -) - - -class FastDownwardBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for Sigmoid - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize FD Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(FastDownwardBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(FD_DEFAULTS.copy()) - - for key in FD_DEFAULTS: - if key not in self.config: - self.config[key] = FD_DEFAULTS[key] - - def get_environment(self): - """ - Return Luby env with current configuration - - Returns - ------- - LubyEnv - Luby environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - env = FastDownwardEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self, test=False): - """ - Read paths of instances from config into list - """ - instances = {} - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - import re - - for root, dirs, files in os.walk(path): - for f in files: - if (f.endswith(".pddl") or f.endswith(".sas")) and not f.startswith( - "domain" - ): - p = os.path.join(root, f) - if f.endswith(".pddl"): - index = p.split("/")[-1].split(".")[0] - else: - index = p.split("/")[-2] - index = int(re.sub("[^0-9]", "", index)) - instances[index] = p - if len(instances) == 0: - for f in os.listdir(path): - f = f.strip() - if (f.endswith(".pddl") or f.endswith(".sas")) and not f.startswith( - "domain" - ): - p = os.path.join(path, f) - if f.endswith(".pddl"): - index = p.split("/")[-1].split(".")[0] - else: - index = p.split("/")[-2] - index = re.sub("[^0-9]", "", index) - instances[index] = p - self.config[keyword] = instances - - if instances[list(instances.keys())[0]].endswith(".pddl"): - self.config.domain_file = os.path.join(path + "/domain.pddl") - - def set_heuristics(self, heuristics): - self.config.heuristics = heuristics - self.config.action_space_args = [len(heuristics)] - self.config.observation_space_args = [ - np.array([-np.inf for _ in range(5 * len(heuristics))]), - np.array([np.inf for _ in range(5 * len(heuristics))]), - ] - - def get_benchmark(self, seed=0): - """ - Get published benchmark - - Parameters - ------- - seed : int - Environment seed - - Returns - ------- - env : FastDownwardEnv - FD environment - """ - self.config = objdict(FD_DEFAULTS.copy()) - self.read_instance_set() - self.read_instance_set(test=True) - self.config.seed = seed - env = FastDownwardEnv(self.config) - return env diff --git a/build/lib/dacbench/benchmarks/geometric_benchmark.py b/build/lib/dacbench/benchmarks/geometric_benchmark.py deleted file mode 100644 index 4db8224e4..000000000 --- a/build/lib/dacbench/benchmarks/geometric_benchmark.py +++ /dev/null @@ -1,304 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import GeometricEnv - -import numpy as np -import os -import csv - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -FILE_PATH = os.path.dirname(__file__) -ACTION_VALUES = (5, 10) - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() - -INFO = { - "identifier": "Geometric", - "name": "High Dimensional Geometric Curve Approximation. Curves are geometrical orthogonal.", - "reward": "Overall Euclidean Distance between Point on Curve and Action Vector for all Dimensions", - "state_description": ["Remaining Budget", "Dimensions",], -} - -GEOMETRIC_DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [], - "reward_range": (0, 1), - "seed": 0, - "cutoff": 10, - "action_values": [], - "action_value_default": 4, - # if action_values_variable True action_value_mapping will be used instead of action_value_default to define action values - # action_value_mapping defines number of action values for differnet functions - # sigmoid is split in 3 actions, cubic in 7 etc. - "action_values_variable": False, - "action_value_mapping": { - "sigmoid": 3, - "linear": 3, - "parabel": 5, - "cubic": 7, - "logarithmic": 4, - "constant": 1, - "sinus": 9, - }, - "action_interval_mapping": {}, # maps actions to equally sized intervalls in interval [-1, 1] - "derivative_interval": 3, # defines how many values are used for derivative calculation - "realistic_trajectory": True, # True: coordiantes are used as trajectory, False: Actions are used as trajectories - "instance_set_path": os.path.join( - FILE_PATH, "../instance_sets/geometric/geometric_test.csv" - ), - # correlation table to chain dimensions -> if dim x changes dim y changes as well - # either assign numpy array to correlation table or use create_correlation_table() - "correlation_active": False, - "correlation_table": None, - "correlation_info": { - "high": [(1, 2, "+"), (2, 3, "-"), (1, 5, "+")], - "middle": [(4, 5, "-")], - "low": [(4, 6, "+"), (2, 3, "+"), (0, 2, "-")], - }, - "correlation_mapping": { - "high": (0.5, 1), - "middle": (0.1, 0.5), - "low": (0, 0.1), - }, - "correlation_depth": 4, - "benchmark_info": INFO, - } -) - - -class GeometricBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for Geometric - """ - - def __init__(self, config_path=None): - """ - Initialize Geometric Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(GeometricBenchmark, self).__init__(config_path) - if not self.config: - self.config = objdict(GEOMETRIC_DEFAULTS.copy()) - - for key in GEOMETRIC_DEFAULTS: - if key not in self.config: - self.config[key] = GEOMETRIC_DEFAULTS[key] - - if not self.config["observation_space_type"]: - self.config["observation_space_type"] = np.float32 - - def get_environment(self): - """ - Return Geometric env with current configuration - - Returns - ------- - GeometricEnv - Geometric environment - - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - self.set_action_values() - self.set_action_description() - - if ( - self.config.correlation_active - and not type(self.config.correlation_table) == np.ndarray - ): - self.create_correlation_table() - - env = GeometricEnv(self.config) - - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self): - """ - Read instance set from file - Creates a nested List for every Intance. - The List contains all functions with their respective values. - """ - path = os.path.join(FILE_PATH, self.config.instance_set_path) - self.config["instance_set"] = {} - with open(path, "r") as fh: - - known_ids = [] - reader = csv.DictReader(fh) - - for row in reader: - function_list = [] - id = int(row["ID"]) - - if id not in known_ids: - self.config.instance_set[id] = [] - known_ids.append(id) - - for index, element in enumerate(row.values()): - # if element == "0" and index != 0: - # break - - # read numbers from csv as floats - element = float(element) if index != 1 else element - - function_list.append(element) - - self.config.instance_set[id].append(function_list) - - def get_benchmark(self, dimension=None, seed=0): - """ - [summary] - - Parameters - ---------- - dimension : [type], optional - [description], by default None - seed : int, optional - [description], by default 0 - - Returns - ------- - [type] - [description] - """ - self.config = objdict(GEOMETRIC_DEFAULTS.copy()) - - self.config.benchmark_info["state_description"] = [ - "Remaining Budget", - "Dimensions", - ] - - self.config.seed = seed - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - self.set_action_values() - self.set_action_description() - - if ( - self.config.correlation_active - and not type(self.config.correlation_table) == np.ndarray - ): - self.create_correlation_table() - - env = GeometricEnv(self.config) - return env - - def set_action_values(self): - """ - Adapt action values and update dependencies - Number of actions can differ between functions if configured in DefaultDict - Set observation space args. - """ - - map_action_number = {} - if self.config.action_values_variable: - map_action_number = self.config.action_value_mapping - - values = [] - for function_info in self.config.instance_set[0]: - function_name = function_info[1] - - value = map_action_number.get( - function_name, self.config.action_value_default - ) - values.append(value) - - # map intervall [-1, 1] to action values - if function_name not in self.config.action_interval_mapping: - action_interval = [] - step_size = 2 / value - - for step in np.arange(-1, 1, step_size): - lower_bound = step - upper_bound = step + step_size - middle = (lower_bound + upper_bound) / 2 - - action_interval.append(middle) - - self.config.action_interval_mapping[function_name] = np.round( - action_interval, 3 - ) - - self.config.action_values = values - cs = CS.ConfigurationSpace() - actions = CSH.UniformIntegerHyperparameter( - name="curve_values", lower=0, upper=int(np.prod(values)) - ) - cs.add_hyperparameter(actions) - self.config.config_space = cs - - num_info = 2 - self.config.observation_space_args = [ - np.array([-1 for _ in range(num_info + 2 * len(values))]), - np.array( - [self.config["cutoff"] for _ in range(num_info + 2 * len(values))] - ), - ] - - def set_action_description(self): - """ - Add Information about Derivative and Coordinate to Description. - """ - if "Coordinate" in self.config.benchmark_info["state_description"]: - return - - for index in range(len(self.config.action_values)): - self.config.benchmark_info["state_description"].append(f"Derivative{index}") - - for index in range(len(self.config.action_values)): - self.config.benchmark_info["state_description"].append(f"Coordinate{index}") - - def create_correlation_table(self): - """ - Create correlation table from Config infos - """ - n_dimensions = len(self.config.instance_set[0]) - corr_table = np.zeros((n_dimensions, n_dimensions)) - - for corr_level, corr_info in self.config.correlation_info.items(): - for dim1, dim2, signum in corr_info: - low, high = self.config.correlation_mapping[corr_level] - value = np.random.uniform(low, high) - try: - corr_table[dim1, dim2] = value if signum == "+" else value * -1 - except IndexError: - print( - "Check your correlation_info dict. Does it have more dimensions than the instance_set?" - ) - - self.config.correlation_table = corr_table - - -if __name__ == "__main__": - from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import ( - quadratic_euclidean_distance_reward_geometric, - ) - - geo_bench = GeometricBenchmark() - geo_bench.config["correlation_active"] = True - geo_bench.config["reward_function"] = quadratic_euclidean_distance_reward_geometric - - env = geo_bench.get_environment() - - opt_policy = env.get_optimal_policy() - # env.render_dimensions([0, 1, 2, 3, 4, 5, 6], "/home/vonglahn/tmp/MultiDAC") - env.render_3d_dimensions([1, 3], "/home/eimer/tmp") - - while True: - env.reset() - done = False - while not done: - state, reward, done, info = env.step(np.random.randint(env.action_space.n)) - print(reward) diff --git a/build/lib/dacbench/benchmarks/luby_benchmark.py b/build/lib/dacbench/benchmarks/luby_benchmark.py deleted file mode 100644 index b209fc103..000000000 --- a/build/lib/dacbench/benchmarks/luby_benchmark.py +++ /dev/null @@ -1,189 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import LubyEnv, luby_gen -from dacbench.wrappers import RewardNoiseWrapper - -import numpy as np -import os -import csv -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -MAX_STEPS = 2 ** 6 -LUBY_SEQUENCE = np.log2([next(luby_gen(i)) for i in range(1, 2 * MAX_STEPS + 2)]) -HISTORY_LENGTH = 5 - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -SEQ = CSH.UniformIntegerHyperparameter(name='sequence_element', lower=0, upper=np.log2(MAX_STEPS)) -DEFAULT_CFG_SPACE.add_hyperparameter(SEQ) - -INFO = { - "identifier": "Luby", - "name": "Luby Sequence Approximation", - "reward": "Boolean sucess indication", - "state_description": [ - "Action t-2", - "Step t-2", - "Action t-1", - "Step t-1", - "Action t (current)", - "Step t (current)", - ], -} - -LUBY_DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [ - np.array([-1 for _ in range(HISTORY_LENGTH + 1)]), - np.array([2 ** max(LUBY_SEQUENCE + 1) for _ in range(HISTORY_LENGTH + 1)]), - ], - "reward_range": (-1, 0), - "cutoff": MAX_STEPS, - "hist_length": HISTORY_LENGTH, - "min_steps": 2 ** 3, - "seed": 0, - "instance_set_path": "../instance_sets/luby/luby_default.csv", - "benchmark_info": INFO, - } -) - - -class LubyBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for Sigmoid - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize Luby Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(LubyBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(LUBY_DEFAULTS.copy()) - - for key in LUBY_DEFAULTS: - if key not in self.config: - self.config[key] = LUBY_DEFAULTS[key] - - def get_environment(self): - """ - Return Luby env with current configuration - - Returns - ------- - LubyEnv - Luby environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - env = LubyEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def set_cutoff(self, steps): - """ - Set cutoff and adapt dependencies - - Parameters - ------- - int - Maximum number of steps - """ - self.config.cutoff = steps - self.config.action_space_args = [int(np.log2(steps))] - LUBY_SEQUENCE = np.log2([next(luby_gen(i)) for i in range(1, 2 * steps + 2)]) - self.config.observation_space_args = [ - np.array([-1 for _ in range(self.config.hist_length + 1)]), - np.array( - [ - 2 ** max(LUBY_SEQUENCE + 1) - for _ in range(self.config.hist_length + 1) - ] - ), - ] - - def set_history_length(self, length): - """ - Set history length and adapt dependencies - - Parameters - ------- - int - History length - """ - self.config.hist_length = length - self.config.observation_space_args = [ - np.array([-1 for _ in range(length + 1)]), - np.array([2 ** max(LUBY_SEQUENCE + 1) for _ in range(length + 1)]), - ] - - def read_instance_set(self, test=False): - """Read instance set from file""" - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - - self.config[keyword] = {} - with open(path, "r") as fh: - reader = csv.DictReader(fh) - for row in reader: - self.config[keyword][int(row["ID"])] = [ - float(shift) for shift in row["start"].split(",") - ] + [float(slope) for slope in row["sticky"].split(",")] - - def get_benchmark(self, L=8, fuzziness=1.5, seed=0): - """ - Get Benchmark from DAC paper - - Parameters - ------- - L : int - Minimum sequence lenght, was 8, 16 or 32 in the paper - fuzziness : float - Amount of noise applied. Was 1.5 for most of the experiments - seed : int - Environment seed - - Returns - ------- - env : LubyEnv - Luby environment - """ - self.config = objdict(LUBY_DEFAULTS.copy()) - self.config.min_steps = L - self.config.seed = seed - self.config.instance_set = {0: [0, 0]} - self.config.reward_range = (-10, 10) - env = LubyEnv(self.config) - rng = np.random.RandomState(self.config.seed) - - def fuzz(): - return rng.normal(-1, fuzziness) - - fuzzy_env = RewardNoiseWrapper(env, noise_function=fuzz) - return fuzzy_env diff --git a/build/lib/dacbench/benchmarks/modcma_benchmark.py b/build/lib/dacbench/benchmarks/modcma_benchmark.py deleted file mode 100644 index 16c2dc10b..000000000 --- a/build/lib/dacbench/benchmarks/modcma_benchmark.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import itertools - -import numpy as np -from modcma import Parameters - -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import ModCMAEnv, CMAStepSizeEnv - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -ACTIVE = CSH.CategoricalHyperparameter(name='0_active', choices=[True, False]) -ELITIST = CSH.CategoricalHyperparameter(name='1_elitist', choices=[True, False]) -ORTHOGONAL = CSH.CategoricalHyperparameter(name='2_orthogonal', choices=[True, False]) -SEQUENTIAL = CSH.CategoricalHyperparameter(name='3_sequential', choices=[True, False]) -THRESHOLD_CONVERGENCE = CSH.CategoricalHyperparameter(name='4_threshold_convergence', choices=[True, False]) -STEP_SIZE_ADAPTION = CSH.CategoricalHyperparameter(name='5_step_size_adaption', choices=["csa", "tpa", "msr", "xnes", "m-xnes", "lp-xnes", "psr"]) -MIRRORED = CSH.CategoricalHyperparameter(name='6_mirrored', choices=["None", "mirrored", "mirrored pairwise"]) -BASE_SAMPLER = CSH.CategoricalHyperparameter(name='7_base_sampler', choices=["gaussian", "sobol", "halton"]) -WEIGHTS_OPTION = CSH.CategoricalHyperparameter(name='8_weights_option', choices=["default", "equal", "1/2^lambda"]) -LOCAL_RESTART = CSH.CategoricalHyperparameter(name='90_local_restart', choices=["None", "IPOP", "BIPOP"]) -BOUND_CORRECTION = CSH.CategoricalHyperparameter(name='91_bound_correction', choices=["None", "saturate", "unif_resample", "COTN", "toroidal", "mirror"]) - -DEFAULT_CFG_SPACE.add_hyperparameter(ACTIVE) -DEFAULT_CFG_SPACE.add_hyperparameter(ELITIST) -DEFAULT_CFG_SPACE.add_hyperparameter(ORTHOGONAL) -DEFAULT_CFG_SPACE.add_hyperparameter(SEQUENTIAL) -DEFAULT_CFG_SPACE.add_hyperparameter(THRESHOLD_CONVERGENCE) -DEFAULT_CFG_SPACE.add_hyperparameter(STEP_SIZE_ADAPTION) -DEFAULT_CFG_SPACE.add_hyperparameter(MIRRORED) -DEFAULT_CFG_SPACE.add_hyperparameter(BASE_SAMPLER) -DEFAULT_CFG_SPACE.add_hyperparameter(WEIGHTS_OPTION) -DEFAULT_CFG_SPACE.add_hyperparameter(LOCAL_RESTART) -DEFAULT_CFG_SPACE.add_hyperparameter(BOUND_CORRECTION) - -INFO = { - "identifier": "ModCMA", - "name": "Online Selection of CMA-ES Variants", - "reward": "Negative best function value", - "state_description": [ - "Generation Size", - "Sigma", - "Remaining Budget", - "Function ID", - "Instance ID", - ], -} - - -MODCMA_DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "action_space_class": "MultiDiscrete", - "action_space_args": [ - list( - map( - lambda m: len( - getattr(getattr(Parameters, m), "options", [False, True]) - ), - Parameters.__modules__, - ) - ) - ], - "observation_space_class": "Box", - "observation_space_args": [-np.inf * np.ones(5), np.inf * np.ones(5)], - "observation_space_type": np.float32, - "reward_range": (-(10 ** 12), 0), - "budget": 100, - "cutoff": 1e6, - "seed": 0, - "instance_set_path": os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "../instance_sets/modea/modea_train.csv", - ), - "test_set_path": os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "../instance_sets/modea/modea_train.csv", - ), - "benchmark_info": INFO, - } -) - - -class ModCMABenchmark(AbstractBenchmark): - def __init__(self, config_path: str = None, step_size=False, config=None): - super().__init__(config_path, config) - self.config = objdict(MODCMA_DEFAULTS.copy(), **(self.config or dict())) - self.step_size = step_size - - def get_environment(self): - if "instance_set" not in self.config: - self.read_instance_set() - - # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - if self.step_size: - self.config.action_space_class = "Box" - self.config.action_space_args = [np.array([0]), np.array([10])] - env = CMAStepSizeEnv(self.config) - else: - env = ModCMAEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - return env - - def read_instance_set(self, test=False): - if test: - path = self.config.test_set_path - keyword = "test_set" - else: - path = self.config.instance_set_path - keyword = "instance_set" - - self.config[keyword] = dict() - with open(path, "r") as fh: - for line in itertools.islice(fh, 1, None): - _id, dim, fid, iid, *representation = line.strip().split(",") - self.config[keyword][int(_id)] = [ - int(dim), - int(fid), - int(iid), - list(map(int, representation)), - ] - - def get_benchmark(self, seed: int = 0): - self.config = MODCMA_DEFAULTS.copy() - self.config.seed = seed - self.read_instance_set() - self.read_instance_set(test=True) - return ModCMAEnv(self.config) diff --git a/build/lib/dacbench/benchmarks/modea_benchmark.py b/build/lib/dacbench/benchmarks/modea_benchmark.py deleted file mode 100644 index aa6b9fc44..000000000 --- a/build/lib/dacbench/benchmarks/modea_benchmark.py +++ /dev/null @@ -1,114 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import ModeaEnv -import numpy as np -import os -import csv - -INFO = { - "identifier": "ModEA", - "name": "Online Selection of CMA-ES Variants", - "reward": "Negative best function value", - "state_description": [ - "Generation Size", - "Sigma", - "Remaining Budget", - "Function ID", - "Instance ID", - ], -} - -MODEA_DEFAULTS = objdict( - { - "action_space_class": "MultiDiscrete", - "action_space_args": [[2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3]], - "observation_space_class": "Box", - "observation_space_args": [-np.inf * np.ones(5), np.inf * np.ones(5)], - "observation_space_type": np.float32, - "reward_range": (-(10 ** 12), 0), - "budget": 100, - "cutoff": 1e6, - "seed": 0, - "instance_set_path": "../instance_sets/modea/modea_train.csv", - "benchmark_info": INFO, - } -) - - -class ModeaBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for Modea - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize Modea Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(ModeaBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(MODEA_DEFAULTS.copy()) - - for key in MODEA_DEFAULTS: - if key not in self.config: - self.config[key] = MODEA_DEFAULTS[key] - - def get_environment(self): - """ - Return ModeaEnv env with current configuration - - Returns - ------- - ModeaEnv - Modea environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - env = ModeaEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self, test=False): - """ - Read path of instances from config into list - """ - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - - self.config[keyword] = {} - with open(path, "r") as fh: - reader = csv.DictReader(fh) - for row in reader: - function = int(row["fcn_id"]) - instance = int(row["inst_id"]) - dimension = int(row["dim"]) - representation = [float(row[f"rep{i}"]) for i in range(11)] - instance = [ - dimension, - function, - instance, - representation, - ] - self.config[keyword][int(row["ID"])] = instance diff --git a/build/lib/dacbench/benchmarks/sgd_benchmark.py b/build/lib/dacbench/benchmarks/sgd_benchmark.py deleted file mode 100644 index 1122ae9a1..000000000 --- a/build/lib/dacbench/benchmarks/sgd_benchmark.py +++ /dev/null @@ -1,219 +0,0 @@ -import csv -import os - -import numpy as np -from gymnasium import spaces -from torch.nn import NLLLoss - -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import SGDEnv -from dacbench.envs.sgd import Reward - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -LR = CSH.UniformIntegerHyperparameter(name="learning_rate", lower=0, upper=10) -DEFAULT_CFG_SPACE.add_hyperparameter(LR) - - -def __default_loss_function(**kwargs): - return NLLLoss(reduction="none", **kwargs) - - -INFO = { - "identifier": "LR", - "name": "Learning Rate Adaption for Neural Networks", - "reward": "Negative Log Differential Validation Loss", - "state_description": [ - "Predictive Change Variance (Discounted Average)", - "Predictive Change Variance (Uncertainty)", - "Loss Variance (Discounted Average)", - "Loss Variance (Uncertainty)", - "Current Learning Rate", - "Training Loss", - "Validation Loss", - "Step", - "Alignment", - "Crashed", - ], -} - - -SGD_DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "action_space_class": "Box", - "action_space_args": [np.array([0]), np.array([10])], - "observation_space_class": "Dict", - "observation_space_type": None, - "observation_space_args": [ - { - "predictiveChangeVarDiscountedAverage": spaces.Box( - low=-np.inf, high=np.inf, shape=(1,) - ), - "predictiveChangeVarUncertainty": spaces.Box( - low=0, high=np.inf, shape=(1,) - ), - "lossVarDiscountedAverage": spaces.Box( - low=-np.inf, high=np.inf, shape=(1,) - ), - "lossVarUncertainty": spaces.Box(low=0, high=np.inf, shape=(1,)), - "currentLR": spaces.Box(low=0, high=1, shape=(1,)), - "trainingLoss": spaces.Box(low=0, high=np.inf, shape=(1,)), - "validationLoss": spaces.Box(low=0, high=np.inf, shape=(1,)), - "step": spaces.Box(low=0, high=np.inf, shape=(1,)), - "alignment": spaces.Box(low=0, high=1, shape=(1,)), - "crashed": spaces.Discrete(2), - } - ], - "reward_type": Reward.LogDiffTraining, - "cutoff": 1e3, - "lr": 1e-3, - "discount_factor": 0.9, - "optimizer": "rmsprop", - "loss_function": __default_loss_function, - "loss_function_kwargs": {}, - "val_loss_function": __default_loss_function, - "val_loss_function_kwargs": {}, - "training_batch_size": 64, - "validation_batch_size": 64, - "train_validation_ratio": 0.8, - "dataloader_shuffle": True, - "no_cuda": False, - "beta1": 0.9, - "beta2": 0.9, - "epsilon": 1.0e-06, - "clip_grad": (-1.0, 1.0), - "seed": 0, - "cd_paper_reconstruction": False, - "cd_bias_correction": True, - "terminate_on_crash": False, - "crash_penalty": 0.0, - "instance_set_path": "../instance_sets/sgd/sgd_train_100instances.csv", - "benchmark_info": INFO, - "features": [ - "predictiveChangeVarDiscountedAverage", - "predictiveChangeVarUncertainty", - "lossVarDiscountedAverage", - "lossVarUncertainty", - "currentLR", - "trainingLoss", - "validationLoss", - "step", - "alignment", - "crashed", - ], - } -) - -# Set reward range based on the chosen reward type -SGD_DEFAULTS.reward_range = SGD_DEFAULTS["reward_type"].func.frange - - -class SGDBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for SGD - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize SGD Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(SGDBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(SGD_DEFAULTS.copy()) - - for key in SGD_DEFAULTS: - if key not in self.config: - self.config[key] = SGD_DEFAULTS[key] - - def get_environment(self): - """ - Return SGDEnv env with current configuration - - Returns - ------- - SGDEnv - SGD environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if ( - "test_set" not in self.config.keys() - and "test_set_path" in self.config.keys() - ): - self.read_instance_set(test=True) - - env = SGDEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self, test=False): - """ - Read path of instances from config into list - """ - - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - self.config[keyword] = {} - with open(path, "r") as fh: - reader = csv.DictReader(fh, delimiter=";") - for row in reader: - if "_" in row["dataset"]: - dataset_info = row["dataset"].split("_") - dataset_name = dataset_info[0] - dataset_size = int(dataset_info[1]) - else: - dataset_name = row["dataset"] - dataset_size = None - instance = [ - dataset_name, - int(row["seed"]), - row["architecture"], - int(row["steps"]), - dataset_size, - ] - self.config[keyword][int(row["ID"])] = instance - - def get_benchmark(self, instance_set_path=None, seed=0): - """ - Get benchmark from the LTO paper - - Parameters - ------- - seed : int - Environment seed - - Returns - ------- - env : SGDEnv - SGD environment - """ - self.config = objdict(SGD_DEFAULTS.copy()) - if instance_set_path is not None: - self.config["instance_set_path"] = instance_set_path - self.config.seed = seed - self.read_instance_set() - return SGDEnv(self.config) diff --git a/build/lib/dacbench/benchmarks/sigmoid_benchmark.py b/build/lib/dacbench/benchmarks/sigmoid_benchmark.py deleted file mode 100644 index a6a9366e6..000000000 --- a/build/lib/dacbench/benchmarks/sigmoid_benchmark.py +++ /dev/null @@ -1,254 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import SigmoidEnv, ContinuousSigmoidEnv, ContinuousStateSigmoidEnv - -import numpy as np -import os -import csv -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -ACTION_VALUES = (5, 10) - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -X = CSH.UniformIntegerHyperparameter(name='value_index', lower=0, upper=int(np.prod(ACTION_VALUES))) -DEFAULT_CFG_SPACE.add_hyperparameter(X) - -INFO = { - "identifier": "Sigmoid", - "name": "Sigmoid Function Approximation", - "reward": "Multiplied Differences between Function and Action in each Dimension", - "state_description": [ - "Remaining Budget", - "Shift (dimension 1)", - "Slope (dimension 1)", - "Shift (dimension 2)", - "Slope (dimension 2)", - "Action 1", - "Action 2", - ], -} - -SIGMOID_DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "action_space_class": "Discrete", - "action_space_args": [int(np.prod(ACTION_VALUES))], - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [ - np.array([-np.inf for _ in range(1 + len(ACTION_VALUES) * 3)]), - np.array([np.inf for _ in range(1 + len(ACTION_VALUES) * 3)]), - ], - "reward_range": (0, 1), - "cutoff": 10, - "action_values": ACTION_VALUES, - "slope_multiplier": 2.0, - "seed": 0, - "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", - "test_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_test.csv", - "benchmark_info": INFO, - } -) - - -class SigmoidBenchmark(AbstractBenchmark): - """ - Benchmark with default configuration & relevant functions for Sigmoid - """ - - def __init__(self, config_path=None, config=None): - """ - Initialize Sigmoid Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(SigmoidBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(SIGMOID_DEFAULTS.copy()) - - for key in SIGMOID_DEFAULTS: - if key not in self.config: - self.config[key] = SIGMOID_DEFAULTS[key] - - def get_environment(self): - """ - Return Sigmoid env with current configuration - - Returns - ------- - SigmoidEnv - Sigmoid environment - - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): - self.read_instance_set(test=True) - - if ( - "env_type" in self.config - ): # The env_type determines which Sigmoid environment to use. - if self.config["env_type"].lower() in [ - "continuous", - "cont", - ]: # Either continuous ... - if ( - self.config["action_space"] == "Box" - ): # ... in both actions and x-axis state, only ... - env = ContinuousSigmoidEnv(self.config) - elif ( - self.config["action_space"] == "Discrete" - ): # ... continuous in the x-axis state or ... - env = ContinuousStateSigmoidEnv(self.config) - else: - raise Exception( - f'The given environment type "{self.config["env_type"]}" does not support the' - f' chosen action_space "{self.config["action_space"]}". The action space has to' - f' be either of type "Box" for continuous actions or "Discrete".' - ) - else: # ... discrete. - env = SigmoidEnv(self.config) - else: # If the type is not specified we the simplest, fully discrete version. - env = SigmoidEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def set_action_values(self, values): - """ - Adapt action values and update dependencies - - Parameters - ---------- - values: list - A list of possible actions per dimension - """ - self.config.action_values = values - self.config.action_space_args = [int(np.prod(values))] - self.config.observation_space_args = [ - np.array([-np.inf for _ in range(1 + len(values) * 3)]), - np.array([np.inf for _ in range(1 + len(values) * 3)]), - ] - - def read_instance_set(self, test=False): - """Read instance set from file""" - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - - self.config[keyword] = {} - with open(path, "r") as f: - reader = csv.reader(f) - for row in reader: - f = [] - inst_id = None - for i in range(len(row)): - if i == 0: - try: - inst_id = int(row[i]) - except Exception: - continue - else: - try: - f.append(float(row[i])) - except Exception: - continue - - if not len(f) == 0: - self.config[keyword][inst_id] = f - - def get_benchmark(self, dimension=None, seed=0): - """ - Get Benchmark from DAC paper - - Parameters - ------- - dimension : int - Sigmoid dimension, was 1, 2, 3 or 5 in the paper - seed : int - Environment seed - - Returns - ------- - env : SigmoidEnv - Sigmoid environment - """ - self.config = objdict(SIGMOID_DEFAULTS.copy()) - if dimension == 1: - self.set_action_values([3]) - self.config.instance_set_path = ( - "../instance_sets/sigmoid/sigmoid_1D3M_train.csv" - ) - self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_1D3M_test.csv" - self.config.benchmark_info["state_description"] = [ - "Remaining Budget", - "Shift (dimension 1)", - "Slope (dimension 1)", - "Action", - ] - if dimension == 2: - self.set_action_values([3, 3]) - if dimension == 3: - self.set_action_values((3, 3, 3)) - self.config.instance_set_path = ( - "../instance_sets/sigmoid/sigmoid_3D3M_train.csv" - ) - self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_3D3M_test.csv" - self.config.benchmark_info["state_description"] = [ - "Remaining Budget", - "Shift (dimension 1)", - "Slope (dimension 1)", - "Shift (dimension 2)", - "Slope (dimension 2)", - "Shift (dimension 3)", - "Slope (dimension 3)", - "Action 1", - "Action 2", - "Action 3", - ] - if dimension == 5: - self.set_action_values((3, 3, 3, 3, 3)) - self.config.instance_set_path = ( - "../instance_sets/sigmoid/sigmoid_5D3M_train.csv" - ) - self.config.test_set_path = "../instance_sets/sigmoid/sigmoid_5D3M_test.csv" - self.config.benchmark_info["state_description"] = [ - "Remaining Budget", - "Shift (dimension 1)", - "Slope (dimension 1)", - "Shift (dimension 2)", - "Slope (dimension 2)", - "Shift (dimension 3)", - "Slope (dimension 3)", - "Shift (dimension 4)", - "Slope (dimension 4)", - "Shift (dimension 5)", - "Slope (dimension 5)", - "Action 1", - "Action 2", - "Action 3", - "Action 4", - "Action 5", - ] - self.config.seed = seed - self.read_instance_set() - self.read_instance_set(test=True) - env = SigmoidEnv(self.config) - return env diff --git a/build/lib/dacbench/benchmarks/theory_benchmark.py b/build/lib/dacbench/benchmarks/theory_benchmark.py deleted file mode 100644 index 2f48b031b..000000000 --- a/build/lib/dacbench/benchmarks/theory_benchmark.py +++ /dev/null @@ -1,169 +0,0 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv - -import numpy as np -import os -import pandas as pd -import gymnasium as gym - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -INFO = { - "identifier": "Theory", - "name": "DAC benchmark with RLS algorithm and LeadingOne problem", - "reward": "Negative number of iterations until solution", - "state_description": "specified by user", -} - -THEORY_DEFAULTS = { - "observation_description": "n, f(x)", # examples: n, f(x), delta_f(x), optimal_k, k, k_{t-0..4}, f(x)_{t-1}, f(x)_{t-0..4} - "reward_range": [-np.inf, np.inf], # the true reward range is instance dependent - "reward_choice": "imp_minus_evals", # possible values: see envs/theory.py for more details - "cutoff": 1e6, # if using as a "train" environment, a cutoff of 0.8*n^2 where n is problem size will be used (for more details, please see https://arxiv.org/abs/2202.03259) - # see get_environment function of TheoryBenchmark on how to specify a train/test environment - "seed": 0, - "seed_action_space": False, # set this one to True for reproducibility when random action is sampled in the action space with gym.action_space.sample() - "problem": "LeadingOne", # possible values: "LeadingOne" - "instance_set_path": "lo_rls_50.csv", # if the instance list file cannot be found in the running directory, it will be looked up in /dacbench/instance_sets/theory/ - "discrete_action": True, # action space is discrete - "action_choices": [1, 2, 4, 8, 16], # portfolio of k values - "benchmark_info": INFO, - "name": "LeadingOnesDAC", -} - - -class TheoryBenchmark(AbstractBenchmark): - """ - Benchmark with various settings for (1+(lbd, lbd))-GA and RLS - """ - - def __init__(self, config=None): - """ - Initialize a theory benchmark - - Parameters - ------- - base_config_name: str - OneLL's config name - possible values: see ../additional_configs/onell/configs.py - config : str - a dictionary, all options specified in this argument will override the one in base_config_name - - """ - super(TheoryBenchmark, self).__init__() - - self.config = objdict(THEORY_DEFAULTS) - - if config: - for key, val in config.items(): - self.config[key] = val - - self.read_instance_set() - - # initialise action space and environment class - cfg_space = CS.ConfigurationSpace() - if self.config.discrete_action: - assert ( - "action_choices" in self.config - ), "ERROR: action_choices must be specified" - assert ("min_action" not in self.config) and ( - "max_action" not in self.config - ), "ERROR: min_action and max_action should not be used for discrete action space" - assert ( - "max_action" not in self.config - ), "ERROR: max_action should not be used for discrete action space" - self.config.env_class = "RLSEnvDiscrete" - n_acts = len(self.config["action_choices"]) - action = CSH.UniformIntegerHyperparameter(name="", lower=0, upper=n_acts) - else: - assert ( - "action_chocies" not in self.config - ), "ERROR: action_choices is only used for discrete action space" - assert ("min_action" in self.config) and ( - "max_action" in self.config - ), "ERROR: min_action and max_action must be specified" - self.config.env_class = "RLSEnv" - action = CSH.UniformFloatHyperparameter( - name="Step_size", - lower=self.config["min_action"], - upper=self.config["max_action"], - ) - - cfg_space.add_hyperparameter(action) - self.config["config_space"] = cfg_space - - # create observation space - self.env_class = globals()[self.config.env_class] - assert self.env_class == RLSEnv or self.env_class == RLSEnvDiscrete - - self.config[ - "observation_space" - ] = self.create_observation_space_from_description( - self.config["observation_description"], self.env_class - ) - - def create_observation_space_from_description( - self, obs_description, env_class=RLSEnvDiscrete - ): - """ - Create a gym observation space (Box only) based on a string containing observation variable names, e.g. "n, f(x), k, k_{t-1}" - Return: - A gym.spaces.Box observation space - """ - obs_var_names = [s.strip() for s in obs_description.split(",")] - low = [] - high = [] - for var_name in obs_var_names: - l, h = env_class.get_obs_domain_from_name(var_name) - low.append(l) - high.append(h) - obs_space = gym.spaces.Box(low=np.array(low), high=np.array(high)) - return obs_space - - def get_environment(self, test_env=False): - """ - Return an environment with current configuration - - Parameters: - test_env: whether the enviroment is used for train an agent or for testing. - if test_env=False: - cutoff time for an episode is set to 0.8*n^2 (n: problem size) - if an action is out of range, stop the episode immediately and return a large negative reward (see envs/theory.py for more details) - otherwise: benchmark's original cutoff time is used, and out-of-range action will be clipped to nearest valid value and the episode will continue. - """ - - env = self.env_class(self.config, test_env) - - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self): - """ - Read instance set from file - we look at the current directory first, if the file doesn't exist, we look in /dacbench/instance_sets/theory/ - """ - assert self.config.instance_set_path - if os.path.isfile(self.config.instance_set_path): - path = self.config.instance_set_path - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/../instance_sets/theory/" - + self.config.instance_set_path - ) - - self.config["instance_set"] = pd.read_csv(path, index_col=0).to_dict("id") - - assert len(self.config["instance_set"].items()) > 0, "ERROR: empty instance set" - assert ( - "initObj" in self.config["instance_set"][0].keys() - ), "ERROR: initial solution (initObj) must be specified in instance set" - assert ( - "size" in self.config["instance_set"][0].keys() - ), "ERROR: problem size must be specified in instance set" - - for key, val in self.config["instance_set"].items(): - self.config["instance_set"][key] = objdict(val) diff --git a/build/lib/dacbench/benchmarks/toysgd_benchmark.py b/build/lib/dacbench/benchmarks/toysgd_benchmark.py deleted file mode 100644 index 716a4f9c4..000000000 --- a/build/lib/dacbench/benchmarks/toysgd_benchmark.py +++ /dev/null @@ -1,122 +0,0 @@ -import os - -import numpy as np -import pandas as pd -from gymnasium import spaces - -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import ToySGDEnv - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH - -DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -LR = CSH.UniformFloatHyperparameter(name="0_log_learning_rate", lower=-10, upper=0) -MOMENTUM = CSH.UniformFloatHyperparameter(name="1_log_momentum", lower=-10, upper=0) -DEFAULT_CFG_SPACE.add_hyperparameter(LR) -DEFAULT_CFG_SPACE.add_hyperparameter(MOMENTUM) - - -INFO = { - "identifier": "toy_sgd", - "name": "Learning Rate and Momentum Adaption for SGD on Toy Functions", - "reward": "Negative Log Regret", - "state_description": [ - "Remaining Budget", - "Gradient", - "Current Learning Rate", - "Current Momentum", - ], - "action_description": ["Log Learning Rate", "Log Momentum"], -} - -DEFAULTS = objdict( - { - "config_space": DEFAULT_CFG_SPACE, - "observation_space_class": "Dict", - "observation_space_type": None, - "observation_space_args": [ - { - "remaining_budget": spaces.Box(low=0, high=np.inf, shape=(1,)), - "gradient": spaces.Box(low=-np.inf, high=np.inf, shape=(1,)), - "learning_rate": spaces.Box(low=0, high=1, shape=(1,)), - "momentum": spaces.Box(low=0, high=1, shape=(1,)), - } - ], - "reward_range": (-np.inf, np.inf), - "cutoff": 10, - "seed": 0, - "instance_set_path": "../instance_sets/toysgd/toysgd_default.csv", - "benchmark_info": INFO, - } -) - - -class ToySGDBenchmark(AbstractBenchmark): - def __init__(self, config_path=None, config=None): - """ - Initialize SGD Benchmark - - Parameters - ------- - config_path : str - Path to config file (optional) - """ - super(ToySGDBenchmark, self).__init__(config_path, config) - if not self.config: - self.config = objdict(DEFAULTS.copy()) - - for key in DEFAULTS: - if key not in self.config: - self.config[key] = DEFAULTS[key] - - def get_environment(self): - """ - Return SGDEnv env with current configuration - - Returns - ------- - SGDEnv - SGD environment - """ - if "instance_set" not in self.config.keys(): - self.read_instance_set() - - # Read test set if path is specified - if ( - "test_set" not in self.config.keys() - and "test_set_path" in self.config.keys() - ): - self.read_instance_set(test=True) - - env = ToySGDEnv(self.config) - for func in self.wrap_funcs: - env = func(env) - - return env - - def read_instance_set(self, test=False): - """ - Read path of instances from config into list - """ - if test: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.test_set_path - ) - keyword = "test_set" - else: - path = ( - os.path.dirname(os.path.abspath(__file__)) - + "/" - + self.config.instance_set_path - ) - keyword = "instance_set" - - self.config[keyword] = {} - with open(path, "r") as fh: - # reader = csv.DictReader(fh, delimiter=";") - df = pd.read_csv(fh, sep=";") - for index, instance in df.iterrows(): - self.config[keyword][int(instance["ID"])] = instance diff --git a/build/lib/dacbench/container/__init__.py b/build/lib/dacbench/container/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/build/lib/dacbench/container/container_utils.py b/build/lib/dacbench/container/container_utils.py deleted file mode 100644 index 3f13df81c..000000000 --- a/build/lib/dacbench/container/container_utils.py +++ /dev/null @@ -1,191 +0,0 @@ -import enum -import json -import os -import socket -import time -from typing import Any, Union, Tuple, List, Dict - -import gym -import numpy as np - - -class Encoder(json.JSONEncoder): - """ Json Encoder to save tuple and or numpy arrays | numpy floats / integer. - Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py - Serializing tuple/numpy array may not work. We need to annotate those types, to reconstruct them correctly. - """ - - @staticmethod - def hint(item): - # Annotate the different item types - if isinstance(item, tuple): - return {'__type__': 'tuple', '__items__': [Encoder.hint(e) for e in item]} - if isinstance(item, np.ndarray): - return {'__type__': 'np.ndarray', '__items__': item.tolist()} - if isinstance(item, np.floating): - return {'__type__': 'np.float', '__items__': float(item)} - if isinstance(item, np.integer): - return {'__type__': 'np.int', '__items__': item.tolist()} - if isinstance(item, enum.Enum): - return str(item) - if isinstance(item, np.random.RandomState): - return serialize_random_state(item) - if isinstance(item, gym.Space): - return Encoder.encode_space(item) - if isinstance(item, np.dtype): - return {'__type__': 'np.dtype', '__items__': str(item)} - - # If it is a container data structure, go also through the items. - if isinstance(item, list): - return [Encoder.hint(e) for e in item] - if isinstance(item, dict): - return {key: Encoder.hint(value) for key, value in item.items()} - return item - # pylint: disable=arguments-differ - def encode(self, obj): - return super(Encoder, self).encode(Encoder.hint(obj)) - - @staticmethod - def encode_space(space_obj : gym.Space): - properties = [( - '__type__', - '.'.join([space_obj.__class__.__module__, space_obj.__class__.__name__] - ) - )] - - if not isinstance(space_obj, (gym.spaces.Dict, gym.spaces.Tuple)): - properties.append(('np_random', serialize_random_state(space_obj.np_random))) - - if isinstance(space_obj, (gym.spaces.Box, gym.spaces.Discrete, gym.spaces.MultiDiscrete, gym.spaces.MultiBinary)): - # by default assume all constrcutor arguments are stored under the same name - # for box we need to drop shape, since either shape or a array for low and height is required - __init__ = space_obj.__init__.__func__.__code__ - local_vars = __init__.co_varnames - - # drop self and non-args (self, arg1, arg2, ..., local_var1, local_var2, ...) - arguments = local_vars[1:__init__.co_argcount] - attributes_to_serialize = list(filter(lambda att: att not in ['shape'], arguments)) - - for attribute in attributes_to_serialize: - if hasattr(space_obj, attribute): - properties.append((attribute, Encoder.hint(getattr(space_obj, attribute)))) - elif isinstance(space_obj, gym.spaces.Tuple): - properties.append(('spaces', [Encoder.encode_space(space) for space in space_obj.spaces])) - elif isinstance(space_obj, gym.spaces.Dict): - properties.append(('spaces', {name:Encoder.encode_space(space) for name, space in space_obj.spaces.items()})) - else: - raise NotImplemented(f"Serialisation for type {properties['__type__']} not implemented") - - return dict(properties) - -class Decoder(json.JSONDecoder): - """ - Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py - - """ - def __init__(self, *args, **kwargs): - json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) - - def object_hook(self, obj: Any) -> Union[Union[tuple, np.ndarray, float, float, int], Any]: - if '__type__' in obj: - __type = obj['__type__'] - if __type == 'tuple': - return tuple(obj['__items__']) - if __type == 'np.ndarray': - return np.array(obj['__items__']) - if __type == 'np.float': - return np.float(obj['__items__']) - if __type == 'np.int': - return np.int(obj['__items__']) - if __type == 'random_state': - return deserialize_random_state(obj) - if __type == 'np.dtype': - return np.dtype(obj['__items__']) - if __type.startswith('gym.spaces.'): - return self.decode_space(obj) - return obj - - - def decode_space(self, space_dict: Dict) -> gym.Space: - __type = space_dict['__type__'] - __class = getattr(gym.spaces, __type.split('.')[-1]) - - args = {name:value for name, value in space_dict.items() if name not in ['__type__', 'np_random', 'shape']} - - # temporally remove subspace since constructor reseeds them - if issubclass(__class,(gym.spaces.Tuple, gym.spaces.Dict)): - spaces = args['spaces'] - args['spaces'] = type(args['spaces'])() - - space_object = __class(**args) - - # re-insert afterwards - if issubclass(__class, (gym.spaces.Tuple, gym.spaces.Dict)): - space_object.spaces = spaces - - if isinstance(space_object, gym.spaces.Tuple): - space_object.spaces = tuple(space_object.spaces) - - if not isinstance(space_object, (gym.spaces.Dict, gym.spaces.Tuple)): - space_object.np_random = space_dict['np_random'] - - return space_object - - -def deserialize_random_state(random_state_dict: Dict) -> np.random.RandomState: - (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state_dict['__items__'] - rnd1 = np.array(rnd1, dtype=np.uint32) - random_state = np.random.RandomState() - random_state.set_state((rnd0, rnd1, rnd2, rnd3, rnd4)) - return random_state - -def serialize_random_state(random_state: np.random.RandomState) -> Tuple[int, List, int, int, int]: - (rnd0, rnd1, rnd2, rnd3, rnd4) = random_state.get_state() - rnd1 = rnd1.tolist() - return {'__type__': 'random_state', '__items__': [rnd0, rnd1, rnd2, rnd3, rnd4]} - - -def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: - """ - Wait for a UNIX socket to be created. - - :param path: path to the socket - :param timeout: timeout in seconds - :return: - """ - start = time.time() - while not os.path.exists(path): - if time.time() - start > timeout: - raise TimeoutError(f"Timeout ({timeout}s) waiting for UNIX socket {path} to be created") - time.sleep(0.1) - -def wait_for_port(port, host='localhost', timeout=5.0): - """ - Taken from https://gist.github.com/butla/2d9a4c0f35ea47b7452156c96a4e7b12 - Wait until a port starts accepting TCP connections. - - Parameters - ---------- - port : int - Port number to check. - host : str - Host to check. - timeout : float - Timeout in seconds. - - Raises: - ------ - TimeoutError: The port isn't accepting connection after time specified in `timeout`. - """ - start_time = time.perf_counter() - while True: - try: - with socket.create_connection((host, port), timeout=timeout): - break - except OSError as ex: - time.sleep(0.01) - if time.perf_counter() - start_time >= timeout: - raise TimeoutError('Waited too long for the port {} on host {} to start accepting ' - 'connections.'.format(port, host)) from ex - - diff --git a/build/lib/dacbench/container/remote_env.py b/build/lib/dacbench/container/remote_env.py deleted file mode 100644 index 60381d44f..000000000 --- a/build/lib/dacbench/container/remote_env.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -from numbers import Number - -from typing import Dict, Union, List, Tuple - -import Pyro4 -import numpy as np - - -from dacbench.abstract_env import AbstractEnv -from dacbench.container.container_utils import Encoder, Decoder - -NumpyTypes = Union[np.ndarray, np.int, np.float, np.random.RandomState] -DefaultJsonable = Union[ - bool, None, Dict[str, 'DefaultJsonable'], List['DefaultJsonable'], Tuple['DefaultJsonable'], str, float, int] -Jsonable = Union[List['Jsonable'], Dict[str, 'Jsonable'], Tuple['Jsonable'], DefaultJsonable, NumpyTypes] - - -def json_encode(obj: Jsonable) -> str: - return json.dumps(obj, indent=None, cls=Encoder) - - -def json_decode(json_str: str) -> Jsonable: - return json.loads(json_str, cls=Decoder) - - -@Pyro4.expose -class RemoteEnvironmentServer: - - def __init__(self, env): - self.__env: AbstractEnv = env - - def step(self, action: Union[Dict[str, List[Number]], List[Number]]): - action = json_decode(action) - json_str = json_encode(self.__env.step(action)) - return json_str - - def reset(self): - state = self.__env.reset() - state = json_encode(state) - return state - - def render(self, mode="human"): - # ever used? - pass - - def close(self): - self.__env.close() - - @property - def action_space(self): - return json_encode(self.__env.action_space) - - - -class RemoteEnvironmentClient: - - def __init__(self, env: RemoteEnvironmentServer): - self.__env = env - - def step(self, action: Union[Dict[str, np.ndarray], np.ndarray]) \ - -> Tuple[Union[Dict[str, np.ndarray], np.ndarray], Number, bool, dict]: - action = json_encode(action) - - json_str = self.__env.step(action) - - state, reward, done, info = json_decode(json_str) - - return state, reward, done, info - - def reset(self) -> Union[Dict[str, np.ndarray], np.ndarray]: - state = self.__env.reset() - state = json_decode(state) - return state - - def close(self): - self.__env.close() - - @property - def action_space(self): - return json_decode(self.__env.action_space) diff --git a/build/lib/dacbench/container/remote_runner.py b/build/lib/dacbench/container/remote_runner.py deleted file mode 100644 index 1be5919df..000000000 --- a/build/lib/dacbench/container/remote_runner.py +++ /dev/null @@ -1,278 +0,0 @@ -""" -This is strongly guided and partially copy from -https://github.com/automl/HPOBench/blob/master/hpobench/container/client_abstract_benchmark.py -""" -import argparse -import logging -import os -import subprocess -import sys -from pathlib import Path -from typing import Tuple, Optional, Union -from uuid import uuid1 - -import Pyro4 -import Pyro4.naming - -from dacbench.abstract_agent import AbstractDACBenchAgent -from dacbench.abstract_benchmark import AbstractBenchmark -from dacbench.argument_parsing import PathType -from dacbench.container.container_utils import wait_for_unixsocket -from dacbench.container.remote_env import RemoteEnvironmentServer, RemoteEnvironmentClient - -# Needed in order to combine event loops of name_server and daemon -Pyro4.config.SERVERTYPE = "multiplex" - -# Read in the verbosity level from the environment variable -log_level_str = os.environ.get('DACBENCH_DEBUG', 'false') - -LOG_LEVEL = logging.INFO -LOG_LEVEL = logging.DEBUG if log_level_str == 'true' else logging.INFO - -root = logging.getLogger() -root.setLevel(level=LOG_LEVEL) - -logger = logging.getLogger(__name__) -logger.setLevel(level=LOG_LEVEL) - -# This option improves the quality of stacktraces if a container crashes -sys.excepthook = Pyro4.util.excepthook -# os.environ["PYRO_LOGFILE"] = "pyro.log" -# os.environ["PYRO_LOGLEVEL"] = "DEBUG" - -# Number of tries to connect to server -MAX_TRIES = 5 - -SOCKET_PATH = Path('/tmp/dacbench/sockets') - - -@Pyro4.expose -class RemoteRunnerServer: - def __init__(self, pyro_demon): - self.benchmark = None - self.pyro_demon = pyro_demon - - def start(self, config: str, benchmark: Tuple[str, str]): - benchmark = AbstractBenchmark.import_from(*benchmark) - - self.benchmark = benchmark.from_json(config) - - def get_environment(self) -> str: - env = self.benchmark.get_environment() - - # set up logger and stuff - - self.env = RemoteEnvironmentServer(env) - uri = self.pyro_demon.register(self.env) - return uri - - -class RemoteRunner: - FACTORY_NAME: str = "RemoteRunnerServerFactory" - - def __init__(self, benchmark: AbstractBenchmark, container_name: str = None, container_source: Optional[str] = None, - container_tag: str = 'latest', env_str: Optional[str] = '', bind_str: Optional[str] = '', - gpu: Optional[bool] = False, socket_id=None): - """ - - Parameters: - ---------------- - - benchmark: AbstractBenchmark - The benchmark to run - container_source : Optional[str] - Path to the container. Either local path or url to a hosting - platform, e.g. singularity hub. - container_tag : str - Singularity containers are specified by an address as well as a container tag. We use the tag as a version - number. By default the tag is set to `latest`, which then pulls the latest container from the container - source. The tag-versioning allows the users to rerun an experiment, which was performed with an older - container version. Take a look in the container_source to find the right tag to use. - bind_str : Optional[str] - Defaults to ''. You can bind further directories into the container. - This string have the form src[:dest[:opts]]. - For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html - env_str : Optional[str] - Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some - environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. - For more information, see - https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview - gpu : bool - If True, the container has access to the local cuda-drivers. - (Not tested) - socket_id : Optional[str] - Setting up the container is done in two steps: - 1) Start the benchmark on a random generated socket id. - 2) Create a proxy connection to the container via this socket id. - - When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is - stored in the class attribute Benchmark.socket_id - - When a `socket_id` is given, instead of creating a new container, connect only to the container that is - reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. - - """ - logger.info(f'Logging level: {logger.level}') - # connect to already running server if a socket_id is given. In this case, skip the init of - # the benchmark - self.__proxy_only = socket_id is not None - self.__socket_path = SOCKET_PATH - - if not self.__proxy_only: - self.__socket_id = self.id_generator() - # todo for now only work with given container source (local) - self.load_benchmark(benchmark=benchmark, container_name=container_name, - container_source=container_source, container_tag=container_tag,) - self.__start_server(env_str=env_str, bind_str=bind_str, gpu=gpu) - else: - self.__socket_id = socket_id - - self.__connect_to_server(benchmark) - - @property - def socket(self) -> Path: - return self.socket_from_id(self.__socket_id) - - @staticmethod - def id_generator() -> str: - """ Helper function: Creates unique socket ids for the benchmark server """ - return str(uuid1()) - - @staticmethod - def socket_from_id(socket_id: str) -> Path: - return Path(SOCKET_PATH) / f'{socket_id}.unixsock' - - def __start_server(self, env_str, bind_str, gpu): - """ - Starts container and the pyro server - - Parameters - ---------- - env_str : str - Environment string for the container - bind_str : str - Bind string for the container - gpu : bool - True if the container should use gpu, False otherwise - """ - # start container - logger.debug(f'Starting server on {self.socket}') - - # todo add mechanism to to retry if failing - self.daemon_process = subprocess.Popen( - [ - "singularity", - "run", - "-e", - str(self.container_source), - "-u", - str(self.socket) - ] - ) - - # todo should be configurable - wait_for_unixsocket(self.socket, 10) - - def __connect_to_server(self, benchmark: AbstractBenchmark): - """ - Connects to the server and initializes the benchmark - """ - # Pyro4.config.REQUIRE_EXPOSE = False - # Generate Pyro 4 URI for connecting to client - ns = Pyro4.Proxy(f"PYRO:Pyro.NameServer@./u:{self.socket}") - factory_uri = ns.lookup(self.FACTORY_NAME) - - factory = Pyro4.Proxy(factory_uri) - remote_runner_uri = factory.create() - self.remote_runner: RemoteRunnerServer = Pyro4.Proxy(remote_runner_uri) - - serialized_config = benchmark.to_json() - serialized_type = benchmark.class_to_str() - self.remote_runner.start(serialized_config, serialized_type) - self.env = None - - def get_environment(self): - if self.env is None: - env_uri = self.remote_runner.get_environment() - remote_env_server = Pyro4.Proxy(env_uri) - self.env = RemoteEnvironmentClient(remote_env_server) - return self.env - - def run(self, agent: AbstractDACBenchAgent, number_of_episodes: int): - # todo: seeding - env = self.get_environment() - - for _ in range(number_of_episodes): - state = env.reset() - done = False - reward = 0 - while not done: - action = agent.act(state, reward) - next_state, reward, done, _ = env.step(action) - agent.train(next_state, reward) - state = next_state - agent.end_episode(state, reward) - - env.close() - self.env = None - - def close(self): - # todo add context manager - self.daemon_process.terminate() - self.daemon_process.wait() - - def __del__(self): - self.close() - - def load_benchmark(self, benchmark : AbstractBenchmark, container_name : str, container_source : Union[str, Path], container_tag : str): - # see for implementation guideline hpobench hpobench/container/client_abstract_benchmark.py - # in the end self.container_source should contain the path to the file to run - - logger.warning("Only container source is used") - container_source = container_source if isinstance(container_source, Path) else Path(container_source) - - self.container_source = container_source - - -@Pyro4.expose -class RemoteRunnerServerFactory: - def __init__(self, pyro_demon): - self.pyro_demon = pyro_demon - - def create(self): - remote_runner_server = RemoteRunnerServer(pyro_demon=self.pyro_demon) - remote_runner_server_uri = daemon.register(remote_runner_server) - return remote_runner_server_uri - - def __call__(self): - return self.create() - - -if __name__ == '__main__': - # todo refactor move to RemoverRunnerServer - parser = argparse.ArgumentParser(description='Runs the benchmark remote server inside a container') - - parser.add_argument('--unixsocket', '-u', type=PathType(exists=False, type='socket'), required=False, default=None, - dest='socket', - help="The path to a exiting socket to run the name server on. If none a new socket unixsocket is created.") - - args = parser.parse_args() - - daemon_socket = RemoteRunner.socket_from_id(RemoteRunner.id_generator()) - ns_socket = args.socket if args.socket else RemoteRunner.socket_from_id(RemoteRunner.id_generator()) - print(ns_socket) - daemon_socket.parent.mkdir(parents=True, exist_ok=True) - ns_socket.parent.mkdir(parents=True, exist_ok=True) - - print(f'Starting Pyro4 Nameserver on {ns_socket} and Pyro4 Daemon on {daemon_socket}') - name_server_uir, name_server_daemon, _ = Pyro4.naming.startNS(unixsocket=str(ns_socket)) - daemon = Pyro4.Daemon(unixsocket=str(daemon_socket)) - daemon.combine(name_server_daemon) - factory = RemoteRunnerServerFactory(daemon) - factory_uri = daemon.register(factory) - name_server_daemon.nameserver.register("RemoteRunnerServerFactory", factory_uri) - - daemon.requestLoop() - - daemon_socket.unlink() - ns_socket.unlink() diff --git a/build/lib/dacbench/envs/__init__.py b/build/lib/dacbench/envs/__init__.py deleted file mode 100644 index b853a7629..000000000 --- a/build/lib/dacbench/envs/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -# flake8: noqa: F401 -from dacbench.envs.luby import LubyEnv, luby_gen -from dacbench.envs.sigmoid import ( - SigmoidEnv, - ContinuousSigmoidEnv, - ContinuousStateSigmoidEnv, -) -from dacbench.envs.fast_downward import FastDownwardEnv -from dacbench.envs.toysgd import ToySGDEnv -from dacbench.envs.geometric import GeometricEnv - -__all__ = [ - "LubyEnv", - "luby_gen", - "SigmoidEnv", - "FastDownwardEnv", - "ToySGDEnv", - "GeometricEnv", -] - - -import importlib -import warnings - -cma_spec = importlib.util.find_spec("cma") -found = cma_spec is not None -if found: - from dacbench.envs.cma_es import CMAESEnv - - __all__.append("CMAESEnv") -else: - warnings.warn( - "CMA-ES Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -modea_spec = importlib.util.find_spec("modea") -found = modea_spec is not None -if found: - from dacbench.envs.modea import ModeaEnv - - __all__.append("ModeaEnv") -else: - warnings.warn( - "Modea Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -modcma_spec = importlib.util.find_spec("modcma") -found = modcma_spec is not None -if found: - from dacbench.envs.cma_step_size import CMAStepSizeEnv - from dacbench.envs.modcma import ModCMAEnv - - __all__.append("ModCMAEnv") - __all__.append("CMAStepSizeEnv") -else: - warnings.warn( - "ModCMA Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -sgd_spec = importlib.util.find_spec("backpack") -found = sgd_spec is not None -if found: - from dacbench.envs.sgd import SGDEnv - - __all__.append("SGDEnv") -else: - warnings.warn( - "SGD Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) - -theory_spec = importlib.util.find_spec("uuid") -found = theory_spec is not None -if found: - from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv - - __all__.append("RLSEnv") - __all__.append("RLSEnvDiscrete") -else: - warnings.warn( - "Theory Benchmark not installed. If you want to use this benchmark, please follow the installation guide." - ) diff --git a/build/lib/dacbench/envs/cma_es.py b/build/lib/dacbench/envs/cma_es.py deleted file mode 100644 index af89fc074..000000000 --- a/build/lib/dacbench/envs/cma_es.py +++ /dev/null @@ -1,255 +0,0 @@ -""" -CMA-ES environment adapted from CMAWorld in -"Learning Step-size Adaptation in CMA-ES" -by G.Shala and A. Biedenkapp and N.Awad and S. Adriaensen and M.Lindauer and F. Hutter. -Original author: Gresa Shala -""" - -import numpy as np -from collections import deque -from cma.evolution_strategy import CMAEvolutionStrategy -from cma import bbobbenchmarks as bn -import threading -import warnings -from dacbench import AbstractEnv -import resource -import sys - -resource.setrlimit(resource.RLIMIT_STACK, (2 ** 35, -1)) -sys.setrecursionlimit(10 ** 9) - -warnings.filterwarnings("ignore") - - -def _norm(x): - return np.sqrt(np.sum(np.square(x))) - - -# IDEA: if we ask cma instead of ask_eval, we could make this parallel - - -class CMAESEnv(AbstractEnv): - """ - Environment to control the step size of CMA-ES - """ - - def __init__(self, config): - """ - Initialize CMA Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super(CMAESEnv, self).__init__(config) - self.b = None - self.bounds = [None, None] - self.fbest = None - self.history_len = config.hist_length - self.history = deque(maxlen=self.history_len) - self.past_obj_vals = deque(maxlen=self.history_len) - self.past_sigma = deque(maxlen=self.history_len) - self.solutions = None - self.func_values = [] - self.cur_obj_val = -1 - # self.chi_N = dim ** 0.5 * (1 - 1.0 / (4.0 * dim) + 1.0 / (21.0 * dim ** 2)) - self.lock = threading.Lock() - self.popsize = config["popsize"] - self.cur_ps = self.popsize - - if "reward_function" in config.keys(): - self.get_reward = config["reward_function"] - else: - self.get_reward = self.get_default_reward - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - def step(self, action): - """ - Execute environment step - - Parameters - ---------- - action : list - action to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, info - """ - truncated = super(CMAESEnv, self).step_() - self.history.append([self.f_difference, self.velocity]) - terminated = self.es.stop() != {} - if not (terminated or truncated): - """Moves forward in time one step""" - sigma = action - self.es.tell(self.solutions, self.func_values) - self.es.sigma = np.maximum(sigma, 0.2) - self.solutions, self.func_values = self.es.ask_and_eval(self.fcn) - - self.f_difference = np.nan_to_num( - np.abs(np.amax(self.func_values) - self.cur_obj_val) - / float(self.cur_obj_val) - ) - self.velocity = np.nan_to_num( - np.abs(np.amin(self.func_values) - self.cur_obj_val) - / float(self.cur_obj_val) - ) - self.fbest = min(self.es.best.f, np.amin(self.func_values)) - - self.past_obj_vals.append(self.cur_obj_val) - self.past_sigma.append(self.cur_sigma) - self.cur_ps = _norm(self.es.adapt_sigma.ps) - self.cur_loc = self.es.best.x - try: - self.cur_sigma = [self.es.sigma[0]] - except: - self.cur_sigma = [self.es.sigma] - self.cur_obj_val = self.es.best.f - - return self.get_state(self), self.get_reward(self), terminated, truncated, {} - - def reset(self): - """ - Reset environment - - Returns - ------- - np.array - Environment state - """ - super(CMAESEnv, self).reset_() - self.history.clear() - self.past_obj_vals.clear() - self.past_sigma.clear() - self.cur_loc = self.instance[3] - self.dim = self.instance[1] - self.init_sigma = self.instance[2] - self.cur_sigma = [self.init_sigma] - self.fcn = bn.instantiate(self.instance[0])[0] - - self.func_values = [] - self.f_vals = deque(maxlen=self.popsize) - self.es = CMAEvolutionStrategy( - self.cur_loc, - self.init_sigma, - {"popsize": self.popsize, "bounds": self.bounds, "seed": self.initial_seed}, - ) - self.solutions, self.func_values = self.es.ask_and_eval(self.fcn) - self.fbest = self.func_values[np.argmin(self.func_values)] - self.f_difference = np.abs( - np.amax(self.func_values) - self.cur_obj_val - ) / float(self.cur_obj_val) - self.velocity = np.abs(np.amin(self.func_values) - self.cur_obj_val) / float( - self.cur_obj_val - ) - self.es.mean_old = self.es.mean - self.history.append([self.f_difference, self.velocity]) - return self.get_state(self), {} - - def close(self): - """ - No additional cleanup necessary - - Returns - ------- - bool - Cleanup flag - """ - return True - - def render(self, mode: str = "human"): - """ - Render env in human mode - - Parameters - ---------- - mode : str - Execution mode - """ - if mode != "human": - raise NotImplementedError - - pass - - def get_default_reward(self, _): - """ - Compute reward - - Returns - ------- - float - Reward - - """ - reward = min(self.reward_range[1], max(self.reward_range[0], -self.fbest)) - return reward - - def get_default_state(self, _): - """ - Gather state description - - Returns - ------- - dict - Environment state - - """ - past_obj_val_deltas = [] - for i in range(1, len(self.past_obj_vals)): - past_obj_val_deltas.append( - (self.past_obj_vals[i] - self.past_obj_vals[i - 1] + 1e-3) - / float(self.past_obj_vals[i - 1]) - ) - if len(self.past_obj_vals) > 0: - past_obj_val_deltas.append( - (self.cur_obj_val - self.past_obj_vals[-1] + 1e-3) - / float(self.past_obj_vals[-1]) - ) - past_obj_val_deltas = np.array(past_obj_val_deltas).reshape(-1) - - history_deltas = [] - for i in range(len(self.history)): - history_deltas.append(self.history[i]) - history_deltas = np.array(history_deltas).reshape(-1) - past_sigma_deltas = [] - for i in range(len(self.past_sigma)): - past_sigma_deltas.append(self.past_sigma[i]) - past_sigma_deltas = np.array(past_sigma_deltas).reshape(-1) - past_obj_val_deltas = np.hstack( - ( - np.zeros((self.history_len - past_obj_val_deltas.shape[0],)), - past_obj_val_deltas, - ) - ) - history_deltas = np.hstack( - ( - np.zeros((self.history_len * 2 - history_deltas.shape[0],)), - history_deltas, - ) - ) - past_sigma_deltas = np.hstack( - ( - np.zeros((self.history_len - past_sigma_deltas.shape[0],)), - past_sigma_deltas, - ) - ) - - cur_loc = np.array(self.cur_loc) - cur_ps = np.array([self.cur_ps]) - cur_sigma = np.array(self.cur_sigma) - - state = { - "current_loc": cur_loc, - "past_deltas": past_obj_val_deltas, - "current_ps": cur_ps, - "current_sigma": cur_sigma, - "history_deltas": history_deltas, - "past_sigma_deltas": past_sigma_deltas, - } - return state diff --git a/build/lib/dacbench/envs/cma_step_size.py b/build/lib/dacbench/envs/cma_step_size.py deleted file mode 100644 index 2ca91fd1d..000000000 --- a/build/lib/dacbench/envs/cma_step_size.py +++ /dev/null @@ -1,54 +0,0 @@ -import numpy as np -from modcma import ModularCMAES, Parameters -from IOHexperimenter import IOH_function - -from dacbench import AbstractEnv - - -class CMAStepSizeEnv(AbstractEnv): - def __init__(self, config): - super().__init__(config) - - self.es = None - self.budget = config.budget - self.total_budget = self.budget - - self.get_reward = config.get("reward_function", self.get_default_reward) - self.get_state = config.get("state_method", self.get_default_state) - - def reset(self): - super().reset_() - self.dim, self.fid, self.iid, self.representation = self.instance - self.objective = IOH_function( - self.fid, self.dim, self.iid, target_precision=1e-8 - ) - self.es = ModularCMAES( - self.objective, - parameters=Parameters.from_config_array(self.dim, self.representation), - ) - return self.get_state(self), {} - - def step(self, action): - truncated = super().step_() - self.es.parameters.sigma = action - terminated = not self.es.step() - return self.get_state(self), self.get_reward(self), terminated, truncated, {} - - def close(self): - return True - - def get_default_reward(self, *_): - return max( - self.reward_range[0], min(self.reward_range[1], -self.es.parameters.fopt) - ) - - def get_default_state(self, *_): - return np.array( - [ - self.es.parameters.lambda_, - self.es.parameters.sigma, - self.budget - self.es.parameters.used_budget, - self.fid, - self.iid, - ] - ) diff --git a/build/lib/dacbench/envs/fast_downward.py b/build/lib/dacbench/envs/fast_downward.py deleted file mode 100644 index ebe9d277f..000000000 --- a/build/lib/dacbench/envs/fast_downward.py +++ /dev/null @@ -1,452 +0,0 @@ -""" -Planning environment from -"Learning Heuristic Selection with Dynamic Algorithm Configuration" -by David Speck, André Biedenkapp, Frank Hutter, Robert Mattmüller und Marius Lindauer. -Original environment authors: David Speck, André Biedenkapp -""" - -import socket -import time -import typing -from copy import deepcopy -from enum import Enum -from os import remove -from os.path import join as joinpath -import subprocess -import os -import numpy as np -from dacbench import AbstractEnv - - -class StateType(Enum): - """Class to define numbers for state types""" - - RAW = 1 - DIFF = 2 - ABSDIFF = 3 - NORMAL = 4 - NORMDIFF = 5 - NORMABSDIFF = 6 - - -class FastDownwardEnv(AbstractEnv): - """ - Environment to control Solver Heuristics of FastDownward - """ - - def __init__(self, config): - """ - Initialize FD Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super(FastDownwardEnv, self).__init__(config) - self._heuristic_state_features = [ - "Average Value", # 'Dead Ends Reliable', - "Max Value", - "Min Value", - "Open List Entries", - "Varianz", - ] - self._general_state_features = [ # 'evaluated_states', 'evaluations', 'expanded_states', - # 'generated_ops', - # 'generated_states', 'num_variables', - # 'registered_states', 'reopened_states', - # "cg_num_eff_to_eff", "cg_num_eff_to_pre", "cg_num_pre_to_eff" - ] - - total_state_features = len(config.heuristics) * len( - self._heuristic_state_features - ) - self._use_gsi = config.use_general_state_info - if config.use_general_state_info: - total_state_features += len(self._general_state_features) - - self.__skip_transform = [False for _ in range(total_state_features)] - if config.use_general_state_info: - self.__skip_transform[4] = True # skip num_variables transform - self.__skip_transform[7] = True - self.__skip_transform[8] = True - self.__skip_transform[9] = True - - self.heuristics = config.heuristics - self.host = config.host - self._port = config.get("port", 0) - if config["parallel"]: - self.port = 0 - - self.fd_seed = config.fd_seed - self.control_interval = config.control_interval - - if config.fd_logs is None: - self.logpath_out = os.devnull - self.logpath_err = os.devnull - else: - self.logpath_out = os.path.join(config.fd_logs, "fdout.txt") - self.logpath_err = os.path.join(config.fd_logs, "fderr.txt") - self.fd_path = config.fd_path - self.fd = None - if "domain_file" in config.keys(): - self.domain_file = config["domain_file"] - - self.socket = None - self.conn = None - - self._prev_state = None - self.num_steps = config.num_steps - - self.__state_type = StateType(config.state_type) - self.__norm_vals = [] - self._config_dir = config.config_dir - self._port_file_id = config.port_file_id - - self._transformation_func = None - # create state transformation function with inputs (current state, previous state, normalization values) - if self.__state_type == StateType.DIFF: - self._transformation_func = lambda x, y, z, skip: x - y if not skip else x - elif self.__state_type == StateType.ABSDIFF: - self._transformation_func = ( - lambda x, y, z, skip: abs(x - y) if not skip else x - ) - elif self.__state_type == StateType.NORMAL: - self._transformation_func = ( - lambda x, y, z, skip: FastDownwardEnv._save_div(x, z) if not skip else x - ) - elif self.__state_type == StateType.NORMDIFF: - self._transformation_func = ( - lambda x, y, z, skip: FastDownwardEnv._save_div(x, z) - - FastDownwardEnv._save_div(y, z) - if not skip - else x - ) - elif self.__state_type == StateType.NORMABSDIFF: - self._transformation_func = ( - lambda x, y, z, skip: abs( - FastDownwardEnv._save_div(x, z) - FastDownwardEnv._save_div(y, z) - ) - if not skip - else x - ) - - self.max_rand_steps = config.max_rand_steps - self.__start_time = None - self.done = True # Starts as true as the expected behavior is that before normal resets an episode was done. - - @property - def port(self): - if self._port == 0: - if self.socket is None: - raise ValueError( - "Automatic port selection enabled. Port not know at the moment" - ) - _, port = self.socket.getsockname() - else: - port = self._port - return port - - @port.setter - def port(self, port): - self._port = port - - @property - def argstring(self): - # if a socket is bound to 0 it will automatically choose a free port - return f"rl_eager(rl([{''.join(f'{h},' for h in self.heuristics)[:-1]}],random_seed={self.fd_seed}),rl_control_interval={self.control_interval},rl_client_port={self.port})" - - @staticmethod - def _save_div(a, b): - """ - Helper method for safe division - - Parameters - ---------- - a : list or np.array - values to be divided - b : list or np.array - values to divide by - - Returns - ------- - np.array - Division result - """ - return np.divide(a, b, out=np.zeros_like(a), where=b != 0) - - def send_msg(self, msg: bytes): - """ - Send message and prepend the message size - - Based on comment from SO see [1] - [1] https://stackoverflow.com/a/17668009 - - Parameters - ---------- - msg : bytes - The message as byte - """ - # Prefix each message with a 4-byte length (network byte order) - msg = str.encode("{:>04d}".format(len(msg))) + msg - self.conn.sendall(msg) - - def recv_msg(self): - """ - Recieve a whole message. The message has to be prepended with its total size - Based on comment from SO see [1] - - Returns - ---------- - bytes - The message as byte - """ - # Read message length and unpack it into an integer - raw_msglen = self.recvall(4) - if not raw_msglen: - return None - msglen = int(raw_msglen.decode()) - # Read the message data - return self.recvall(msglen) - - def recvall(self, n: int): - """ - Given we know the size we want to recieve, we can recieve that amount of bytes. - Based on comment from SO see [1] - - Parameters - --------- - n: int - Number of bytes to expect in the data - - Returns - ---------- - bytes - The message as byte - """ - # Helper function to recv n bytes or return None if EOF is hit - data = b"" - while len(data) < n: - packet = self.conn.recv(n - len(data)) - if not packet: - return None - data += packet - return data - - def _process_data(self): - """ - Split received json into state reward and done - - Returns - ---------- - np.array, float, bool - state, reward, done - """ - msg = self.recv_msg().decode() - # print("----------------------------") - # print(msg) - # print("=>") - msg = msg.replace("-inf", "0") - msg = msg.replace("inf", "0") - # print(msg) - data = eval(msg) - r = data["reward"] - done = data["done"] - del data["reward"] - del data["done"] - - state = [] - - if self._use_gsi: - for feature in self._general_state_features: - state.append(data[feature]) - for heuristic_id in range(len(self.heuristics)): # process heuristic data - for feature in self._heuristic_state_features: - state.append(data["%d" % heuristic_id][feature]) - - if self._prev_state is None: - self.__norm_vals = deepcopy(state) - self._prev_state = deepcopy(state) - if ( - self.__state_type != StateType.RAW - ): # Transform state to DIFF state or normalize - tmp_state = state - state = list( - map( - self._transformation_func, - state, - self._prev_state, - self.__norm_vals, - self.__skip_transform, - ) - ) - self._prev_state = tmp_state - return np.array(state), r, done - - def step(self, action: typing.Union[int, typing.List[int]]): - """ - Environment step - - Parameters - --------- - action: typing.Union[int, List[int]] - Parameter(s) to apply - - Returns - ---------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, info - """ - self.done = super(FastDownwardEnv, self).step_() - if not np.issubdtype( - type(action), np.integer - ): # check for core int and any numpy-int - try: - action = action[0] - except IndexError as e: - print(type(action)) - raise e - if self.num_steps: - msg = ",".join([str(action), str(self.num_steps)]) - else: - msg = str(action) - self.send_msg(str.encode(msg)) - s, r, terminated = self._process_data() - r = max(self.reward_range[0], min(self.reward_range[1], r)) - info = {} - if terminated: - self.done = True - self.kill_connection() - if self.c_step > self.n_steps: - info["needs_reset"] = True - self.send_msg(str.encode("END")) - self.kill_connection() - return s, r, terminated, self.done, info - - def reset(self): - """ - Reset environment - - Returns - ---------- - np.array - State after reset - dict - Meta-info - """ - super(FastDownwardEnv, self).reset_() - self._prev_state = None - self.__start_time = time.time() - if not self.done: # This means we interrupt FD before a plan was found - # Inform FD about imminent shutdown of the connection - self.send_msg(str.encode("END")) - self.done = False - if self.conn: - self.conn.shutdown(2) - self.conn.close() - self.conn = None - if not self.socket: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.settimeout(10) - self.socket.bind((self.host, self.port)) - - if self.fd: - self.fd.terminate() - - if self.instance.endswith(".pddl"): - command = [ - "python3", - f"{self.fd_path}", - self.domain_file, - self.instance, - "--search", - self.argstring, - ] - else: - command = [ - "python3", - f"{self.fd_path}", - self.instance, - "--search", - self.argstring, - ] - - with open(self.logpath_out, "a+") as fout, open(self.logpath_err, "a+") as ferr: - err_output = subprocess.STDOUT if self.logpath_err == "/dev/null" else ferr - self.fd = subprocess.Popen(command, stdout=fout, stderr=err_output) - - # write down port such that FD can potentially read where to connect to - if self._port_file_id: - fp = joinpath(self._config_dir, "port_{:d}.txt".format(self._port_file_id)) - else: - fp = joinpath(self._config_dir, f"port_{self.port}.txt") - with open(fp, "w") as portfh: - portfh.write(str(self.port)) - - self.socket.listen() - try: - self.conn, address = self.socket.accept() - except socket.timeout: - raise OSError( - "Fast downward subprocess not reachable (time out). " - "Possible solutions:\n" - " (1) Did you run './dacbench/envs/rl-plan/fast-downward/build.py' " - "in order to build the fd backend?\n" - " (2) Try to fix this by setting OPENBLAS_NUM_THREADS=1. " - "For more details see https://github.com/automl/DACBench/issues/96" - ) - - s, _, _ = self._process_data() - if self.max_rand_steps > 1: - for _ in range(self.np_random.randint(1, self.max_rand_steps + 1)): - s, _, _, _ = self.step(self.action_space.sample()) - if self.conn is None: - return self.reset() - else: - s, _, _, _ = self.step(0) # hard coded to zero as initial step - - remove( - fp - ) # remove the port file such that there is no chance of loading the old port - return s, {} - - def kill_connection(self): - """Kill the connection""" - if self.conn: - self.conn.shutdown(2) - self.conn.close() - self.conn = None - if self.socket: - self.socket.shutdown(2) - self.socket.close() - self.socket = None - - def close(self): - """ - Close Env - - Returns - ------- - bool - Closing confirmation - """ - if self.socket is None: - return True - fp = joinpath(self._config_dir, f"port_{self.port}.txt") - if os.path.exists(fp): - remove(fp) - - self.kill_connection() - return True - - def render(self, mode: str = "human") -> None: - """ - Required by gym.Env but not implemented - - Parameters - ------- - mode : str - Rendering mode - """ - pass diff --git a/build/lib/dacbench/envs/geometric.py b/build/lib/dacbench/envs/geometric.py deleted file mode 100644 index e3e2aacb0..000000000 --- a/build/lib/dacbench/envs/geometric.py +++ /dev/null @@ -1,665 +0,0 @@ -""" -Geometric environment. -Original environment authors: Rasmus von Glahn -""" -import bisect -import os -import itertools -import math -from typing import List, Dict, Tuple - -from mpl_toolkits import mplot3d -from matplotlib import pyplot as plt -import numpy as np -import seaborn as sns - -sns.set_theme(style="darkgrid") - -from dacbench import AbstractEnv - - -class GeometricEnv(AbstractEnv): - """ - Environment for tracing different curves that are orthogonal to each other - Use product approach: f(t,x,y,z) = X(t,x) * Y(t,y) * Z(t,z) - Normalize Function Value on a Scale between 0 and 1 - - min and max value for normalization over all timesteps - """ - - def __init__(self, config) -> None: - """ - Initialize Geometric Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super(GeometricEnv, self).__init__(config) - - self.action_vals = config["action_values"] - self.action_interval_mapping = config["action_interval_mapping"] - self.realistic_trajectory = config["realistic_trajectory"] - self.derivative_interval = config["derivative_interval"] - - self.correlation_table = config["correlation_table"] - self.correlation_active = config["correlation_active"] - self.correlation_depth = config["correlation_depth"] - self.n_steps = config["cutoff"] - - self._prev_state = None - self.action = None - self.n_actions = len(self.action_vals) - self.action_mapper = {} - - # Functions - self.functions = Functions( - self.n_steps, - self.n_actions, - len(self.instance_set), - self.correlation_active, - self.correlation_table, - self.correlation_depth, - self.derivative_interval, - ) - self.functions.calculate_norm_values(self.instance_set) - - # Trajectories - self.action_trajectory = [] - self.coord_trajectory = [] - self.action_trajectory_set = {} - self.coord_trajectory_set = {} - - self.derivative = [] - self.derivative_set = {} - - # Map actions from int to vector representation - for idx, prod_idx in zip( - range(np.prod(config["action_values"])), - itertools.product(*[np.arange(val) for val in config["action_values"]]), - ): - self.action_mapper[idx] = prod_idx - - if "reward_function" in config.keys(): - self.get_reward = config["reward_function"] - else: - self.get_reward = self.get_default_reward - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - def get_optimal_policy( - self, instance: List = None, vector_action: bool = True - ) -> List[np.array]: - """ - Calculates the optimal policy for an instance - - Parameters - ---------- - instance : List, optional - instance with information about function config. - vector_action : bool, optional - if True return multidim actions else return onedimensional action, by default True - - Returns - ------- - List[np.array] - List with entry for each timestep that holds all optimal values in an array or as int - """ - if not instance: - instance = self.instance - - optimal_policy_coords = self.functions.get_coordinates(instance).transpose() - optimal_policy = np.zeros(((self.n_steps, self.n_actions))) - - for step in range(self.n_steps): - for dimension in range(self.n_actions): - step_size = 2 / self.action_vals[dimension] - interval = [step for step in np.arange(-1, 1, step_size)][1:] - - optimal_policy[step, dimension] = bisect.bisect_left( - interval, optimal_policy_coords[step, dimension] - ) - - optimal_policy = optimal_policy.astype(int) - if not vector_action: - reverse_action_mapper = {v: k for k, v in self.action_mapper.items()} - optimal_policy = [ - reverse_action_mapper[tuple(vec)] for vec in optimal_policy - ] - - return optimal_policy - - def step(self, action: int): - """ - Execute environment step - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, info - """ - self.done = super(GeometricEnv, self).step_() - - # map integer action to vector - action_vec = self.action_mapper[action] - assert self.n_actions == len( - action_vec - ), f"action should be of length {self.n_actions}." - self.action = action_vec - - coords = self.functions.get_coordinates_at_time_step(self.c_step) - self.coord_trajectory.append(coords) - self.action_trajectory.append(np.array(action_vec)) - - self.coord_trajectory_set[self.inst_id] = self.coord_trajectory - self.action_trajectory_set[self.inst_id] = self.action_trajectory - - if self.realistic_trajectory: - self.derivative = self.functions.calculate_derivative( - self.coord_trajectory, self.c_step - ) - else: - self.derivative = self.functions.calculate_derivative( - self.action_trajectory, self.c_step - ) - - self.derivative_set[self.inst_id] = self.derivative - - next_state = self.get_state(self) - self._prev_state = next_state - - reward = self.get_reward(self) - if reward > 1: - print(f"Instance: {self.instance}, Reward:{reward}, step: {self.c_step}") - raise ValueError(f"Reward zu Hoch Coords: {coords}, step: {self.c_step}") - if math.isnan(reward): - raise ValueError(f"Reward NAN Coords: {coords}, step: {self.c_step}") - - return next_state, reward, False, self.done, {} - - def reset(self) -> List[int]: - """ - Resets env - - Returns - ------- - numpy.array - Environment state - dict - Meta-info - """ - super(GeometricEnv, self).reset_() - self.functions.set_instance(self.instance, self.instance_index) - - if self.c_step: - self.action_trajectory = self.action_trajectory_set.get(self.inst_id) - - self.coord_trajectory = self.coord_trajectory_set.get( - self.inst_id, [self.functions.get_coordinates_at_time_step(self.c_step)] - ) - - self.derivative = self.derivative_set.get( - self.inst_id, np.zeros(self.n_actions) - ) - self._prev_state = None - - return self.get_state(self), {} - - def get_default_reward(self, _) -> float: - """ - Calculate euclidean distance between action vector and real position of Curve. - - Parameters - ---------- - _ : self - ignore - - Returns - ------- - float - Euclidean distance - """ - coords, action_coords, highest_coords, lowest_actions = self._pre_reward() - euclidean_dist = np.linalg.norm(action_coords - coords) - - max_dist = np.linalg.norm(highest_coords - lowest_actions) - reward = 1 - (euclidean_dist / max_dist) - - return abs(reward) - - def get_default_state(self, _) -> np.array: - """ - Gather state information. - - Parameters - ---------- - _ : - ignore param - - Returns - ------- - np.array - numpy array with state information - """ - remaining_budget = self.n_steps - self.c_step - next_state = [remaining_budget] - - next_state += [self.n_actions] - - if self.c_step == 0: - next_state += [0 for _ in range(self.n_actions)] - next_state += [0 for _ in range(self.n_actions)] - else: - next_state += list(self.derivative) - next_state += list(self.coord_trajectory[self.c_step]) - - return np.array(next_state, dtype="float32") - - def close(self) -> bool: - """ - Close Env - - Returns - ------- - bool - Closing confirmation - """ - return True - - def render(self, dimensions: List, absolute_path: str): - """ - Multiplot for specific dimensions of benchmark with policy actions. - - Parameters - ---------- - dimensions : List - List of dimensions that get plotted - """ - coordinates = self.functions.get_coordinates() - - fig, axes = plt.subplots( - len(dimensions), sharex=True, sharey=True, figsize=(15, 4 * len(dimensions)) - ) - plt.xlabel("time steps", fontsize=32) - plt.ylim(-1.1, 1.1) - plt.xlim(-0.1, self.n_steps - 0.9) - plt.xticks(np.arange(0, self.n_steps, 1), fontsize=24.0) - - for idx, dim in zip(range(len(dimensions)), dimensions): - function_info = self.instance[dim] - title = function_info[1] + " - Dimension " + str(dim) - axes[idx].tick_params(axis="both", which="major", labelsize=24) - axes[idx].set_yticks((np.arange(-1, 1.1, 2 / self.action_vals[dim]))) - axes[idx].set_title(title, size=32) - axes[idx].plot(coordinates[dim], label="Function", marker="o", linewidth=3)[ - 0 - ].axes - axes[idx].xaxis.grid(False) - axes[idx].vlines(x=[3.5, 7.5], ymin=-1, ymax=1, colors="white", ls="--") - """ - axes[idx].legend( - loc="lower right", - framealpha=1, - shadow=True, - borderpad=1, - frameon=True, - ncol=1, - edgecolor="0.2", - ) - """ - - fig_title = f"GeoBench-Dimensions{len(dimensions)}" - fig.savefig(os.path.join(absolute_path, fig_title + ".jpg")) - - def render_3d_dimensions(self, dimensions: List, absolute_path: str): - """ - Plot 2 Dimensions in 3D space - - Parameters - ---------- - dimensions : List - List of dimensions that get plotted. Max 2 - """ - assert len(dimensions) == 2 - print(mplot3d) - - coordinates = self.functions.get_coordinates() - - fig = plt.figure(figsize=(10, 10)) - ax = plt.axes(projection="3d") - - x = list(range(self.n_steps)) - z = coordinates[dimensions[0]][x] - y = coordinates[dimensions[1]][x] - - ax.set_title("3D line plot") - - ax.plot3D(x, y, z, "blue") - ax.view_init() - fig.savefig(os.path.join(absolute_path, "3D.jpg")) - - ax.set_yticklabels([]) - ax.set_yticks([]) - ax.view_init(elev=0, azim=-90) - fig.savefig(os.path.join(absolute_path, "3D-90side.jpg")) - - def _pre_reward(self) -> Tuple[np.ndarray, List]: - """ - Prepare actions and coordinates for reward calculation. - - Returns - ------- - Tuple[np.ndarray, List] - [description] - """ - coordinates = self.functions.get_coordinates_at_time_step(self.c_step) - function_names = [function_info[1] for function_info in self.instance] - - # map action values to their interval mean - mapping_list = [self.action_interval_mapping[name] for name in function_names] - action_intervall = [ - mapping_list[count][index] for count, index in enumerate(self.action) - ] - highest_coords = np.ones(self.n_actions) - lowest_actions = np.array([val[0] for val in mapping_list]) - - return coordinates, action_intervall, highest_coords, lowest_actions - - -class Functions: - def __init__( - self, - n_steps: int, - n_actions: int, - n_instances: int, - correlation: bool, - correlation_table: np.ndarray, - correlation_depth: int, - derivative_interval: int, - ) -> None: - self.instance = None - self.instance_idx = None - - self.coord_array = np.zeros((n_actions, n_steps)) - self.calculated_instance = None - self.norm_calculated = False - self.norm_values = np.ones((n_instances, n_actions)) - - self.correlation = correlation - self.correlation_table = correlation_table - self.correlation_changes = np.zeros(n_actions) - self.correlation_depth = correlation_depth - - self.n_steps = n_steps - self.n_actions = n_actions - self.derivative_interval = derivative_interval - - def set_instance(self, instance: List, instance_index): - """update instance""" - self.instance = instance - self.instance_idx = instance_index - - def get_coordinates(self, instance: List = None) -> List[np.array]: - """ - Calculates coordinates for instance over all time_steps. - The values will change if correlation is applied and not optimal actions are taken. - - Parameters - ---------- - instance : List, optional - Instance that holds information about functions, by default None - - Returns - ------- - List[np.array] - Index of List refers to time step - """ - if not instance: - instance = self.instance - assert instance - - if self.instance_idx == self.calculated_instance: - optimal_coords = self.coord_array - else: - optimal_coords = np.zeros((self.n_actions, self.n_steps)) - for time_step in range(self.n_steps): - optimal_coords[:, time_step] = self.get_coordinates_at_time_step( - time_step + 1 - ) - - if self.norm_calculated: - self.coord_array = optimal_coords - self.calculated_instance = self.instance_idx - - return optimal_coords - - def get_coordinates_at_time_step(self, time_step: int) -> np.array: - """ - Calculate coordiantes at time_step. - Apply correlation. - - Parameters - ---------- - instance : List - Instance that holds information about functions - time_step : int - Time step of functions - - Returns - ------- - np.array - array of function values at timestep - """ - if self.instance_idx == self.calculated_instance: - value_array = self.coord_array[:, time_step - 1] - else: - value_array = np.zeros(self.n_actions) - for index, function_info in enumerate(self.instance): - value_array[index] = self._calculate_function_value( - time_step, function_info, index - ) - - if self.correlation and time_step > 1 and self.norm_calculated: - value_array = self._add_correlation(value_array, time_step) - - return value_array - - def calculate_derivative(self, trajectory: List, c_step: int) -> np.array: - """ - Calculate derivatives of each dimension, based on trajectories. - - Parameters - ---------- - trajectory: List - List of actions or coordinates already taken - c_step: int - current timestep - - Returns - ------- - np.array - derivatives for each dimension - """ - if c_step > 1: - upper_bound = c_step + 1 - lower_bound = max(upper_bound - self.derivative_interval, 1) - - derrivative = np.zeros(self.n_actions) - for step in range(lower_bound, upper_bound): - der = np.subtract( - np.array(trajectory[step], dtype=np.float), - np.array(trajectory[step - 1], dtype=np.float), - ) - derrivative = np.add(derrivative, der) - - derrivative /= upper_bound - lower_bound - - elif c_step == 1: - derrivative = np.subtract( - np.array(trajectory[c_step], dtype=np.float), - np.array(trajectory[c_step - 1], dtype=np.float), - ) - - else: - derrivative = np.zeros(self.n_actions) - - return derrivative - - def calculate_norm_values(self, instance_set: Dict): - """ - Norm Functions to Intervall between -1 and 1 - """ - for key, instance in instance_set.items(): - self.set_instance(instance, key) - instance_values = self.get_coordinates() - - for dim, function_values in enumerate(instance_values): - - if abs(min(function_values)) > max(function_values): - norm_factor = abs(min(function_values)) - else: - norm_factor = max(function_values) - - self.norm_values[key][dim] = norm_factor - - self.norm_calculated = True - - def _calculate_function_value( - self, time_step: int, function_infos: List, func_idx: int - ) -> float: - """ - Call different functions with their speicifc parameters and norm them. - - Parameters - ---------- - function_infos : List - Consists of function name and the coefficients - time_step: int - time step for each function - calculate_norm : bool, optional - True if norm gets calculated, by default False - - Returns - ------- - float - coordinate in dimension of function - """ - assert self.instance_idx == function_infos[0] - - function_name = function_infos[1] - coefficients = function_infos[2:] - if self.norm_calculated: - norm_value = self.norm_values[self.instance_idx, func_idx] - if norm_value == 0: - norm_value = 1 - else: - norm_value = 1 - - function_value = 0 - - if "sigmoid" == function_name: - function_value = self._sigmoid(time_step, coefficients[0], coefficients[1]) - - elif "linear" == function_name: - function_value = self._linear(time_step, coefficients[0], coefficients[1]) - - elif "constant" == function_name: - function_value = self._constant(coefficients[0]) - - elif "logarithmic" == function_name: - function_value = self._logarithmic(time_step, coefficients[0]) - - elif "cubic" in function_name: - function_value = self._cubic( - time_step, coefficients[0], coefficients[1], coefficients[2] - ) - - elif "parabel" in function_name: - function_value = self._parabel( - time_step, coefficients[0], coefficients[1], coefficients[2] - ) - - elif "sinus" in function_name: - function_value = self._sinus(time_step, coefficients[0]) - - function_value = np.round(function_value / norm_value, 5) - if self.norm_calculated: - function_value = max(min(function_value, 1), -1) - - return function_value - - def _add_correlation(self, value_array: np.ndarray, time_step: int): - """ - Adds correlation between dimensions but clips at -1 and 1. - Correlation table holds numbers between -1 and 1. - e.g. correlation_table[0][2] = 0.5 if dimension 1 changes dimension 3 changes about 50% of dimension one - - Parameters - ---------- - correlation_table : np.array - table that holds all values of correlation between dimensions [n,n] - """ - prev_values = self.coord_array[:, time_step - 1] - diff_values = value_array - prev_values - - new_values = [] - for idx, diff in enumerate(diff_values): - self._apply_correlation_update(idx, diff, self.correlation_depth) - - new_values = self.correlation_changes + value_array - clipped_values = np.clip(new_values, a_min=-1, a_max=1) - self.correlation_changes = np.zeros(self.n_actions) - - return clipped_values - - def _apply_correlation_update(self, idx: int, diff: float, depth): - """ - Recursive function for correlation updates - Call function recursively till depth is 0 or diff is too small. - """ - if not depth or diff < 0.001: - return - - for coeff_idx, corr_coeff in enumerate(self.correlation_table[:][idx]): - change = corr_coeff * diff - self.correlation_changes[coeff_idx] += change - self._apply_correlation_update(coeff_idx, change, depth - 1) - - def _sigmoid(self, t: float, scaling: float, inflection: float): - """Simple sigmoid function""" - return 1 / (1 + np.exp(-scaling * (t - inflection))) - - def _linear(self, t: float, a: float, b: float): - """Linear function""" - return a * t + b - - def _parabel(self, t: float, sig: int, x_int: int, y_int: int): - """Parabel function""" - return sig * (t - x_int) ** 2 + y_int - - def _cubic(self, t: float, sig: int, x_int: int, y_int: int): - """cubic function""" - return sig * (t - x_int) ** 3 + y_int - - def _logarithmic(self, t: float, a: float): - """Logarithmic function""" - if t != 0: - return a * np.log(t) - else: - return 1000 - - def _constant(self, c: float): - """Constant function""" - return c - - def _sinus(self, t: float, scale: float): - """Sinus function""" - return np.sin(scale * t) diff --git a/build/lib/dacbench/envs/luby.py b/build/lib/dacbench/envs/luby.py deleted file mode 100644 index aebe00a97..000000000 --- a/build/lib/dacbench/envs/luby.py +++ /dev/null @@ -1,180 +0,0 @@ -""" -Luby environment from -"Dynamic Algorithm Configuration:Foundation of a New Meta-Algorithmic Framework" -by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. -Original environment authors: André Biedenkapp, H. Furkan Bozkurt -""" - -from typing import List -import numpy as np - -from dacbench import AbstractEnv - - -# Instance IDEA 1: shift luby seq -> feat is sum of skipped action values -# Instance IDEA 2: "Wiggle" luby i.e. luby(t + N(0, 0.1)) -> feat is sampled value - - -class LubyEnv(AbstractEnv): - """ - Environment to learn Luby Sequence - """ - - def __init__(self, config) -> None: - """ - Initialize Luby Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super().__init__(config) - - self._hist_len = config["hist_length"] - self._ms = self.n_steps - self._mi = config["min_steps"] - self._state = np.array([-1 for _ in range(self._hist_len + 1)]) - self._r = 0 - self._genny = luby_gen(1) - self._next_goal = next(self._genny) - # Generate luby sequence up to 2*max_steps + 2 as mode 1 could potentially shift up to max_steps - self._seq = np.log2( - [next(luby_gen(i)) for i in range(1, 2 * config["cutoff"] + 2)] - ) - self._jenny_i = 1 - self._start_dist = None - self._sticky_dis = None - self._sticky_shif = 0 - self._start_shift = 0 - self.__lower, self.__upper = 0, 0 - self.__error = 0 - self.done = None - self.action = None - - if "reward_function" in config.keys(): - self.get_reward = config["reward_function"] - else: - self.get_reward = self.get_default_reward - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - def step(self, action: int): - """ - Execute environment step - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, info - """ - self.done = super(LubyEnv, self).step_() - self.prev_state = self._state.copy() - self.action = action - reward = self.get_reward(self) - if ( - self.__error < self.__lower - ): # needed to avoid too long sequences of sticky actions - self.__error += np.abs(self.__lower) - elif self.__error > self.__upper: - self.__error -= np.abs(self.__upper) - self._jenny_i += 1 - self.__error += self._sticky_shif - - # next target in sequence at step luby_t is determined by the current time step (jenny_i), the start_shift - # value and the sticky error. Additive sticky error leads to sometimes rounding to the next time_step and - # thereby repeated actions. With check against lower/upper we reset the sequence to the correct timestep in - # the t+1 timestep. - luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) - self._next_goal = self._seq[luby_t - 1] - return self.get_state(self), reward, False, self.done, {} - - def reset(self) -> List[int]: - """ - Resets env - - Returns - ------- - numpy.array - Environment state - """ - super(LubyEnv, self).reset_() - self._start_shift = self.instance[0] - self._sticky_shif = self.instance[1] - self._r = 0 - self.n_steps = self._mi - - self.__error = 0 + self._sticky_shif - self._jenny_i = 1 - luby_t = max(1, int(np.round(self._jenny_i + self._start_shift + self.__error))) - self._next_goal = self._seq[luby_t - 1] - self.done = False - return self.get_state(self), {} - - def get_default_reward(self, _): - if self.action == self._next_goal: - self._r = 0 # we don't want to allow for exploiting large rewards by tending towards long sequences - else: # mean and var chosen s.t. ~1/4 of rewards are positive - self._r = -1 - self._r = max(self.reward_range[0], min(self.reward_range[1], self._r)) - return self._r - - def get_default_state(self, _): - if self.c_step == 0: - self._state = [-1 for _ in range(self._hist_len + 1)] - else: - if self.c_step - 1 < self._hist_len: - self._state[(self.c_step - 1)] = self.action - else: - self._state[:-2] = self._state[1:-1] - self._state[-2] = self.action - self._state[-1] = self.c_step - 1 - next_state = np.array(self._state if not self.done else self.prev_state) - return next_state - - def close(self) -> bool: - """ - Close Env - - Returns - ------- - bool - Closing confirmation - """ - return True - - # TODO: this should render! - - def render(self, mode: str = "human") -> None: - """ - Render env in human mode - - Parameters - ---------- - mode : str - Execution mode - """ - if mode != "human": - raise NotImplementedError - - pass - - -def luby_gen(i): - """ Generator for the Luby Sequence """ - for k in range(1, 33): - if i == ((1 << k) - 1): - yield 1 << (k - 1) - - for k in range(1, 9999): - if 1 << (k - 1) <= i < (1 << k) - 1: - for x in luby_gen(i - (1 << (k - 1)) + 1): - yield x diff --git a/build/lib/dacbench/envs/modcma.py b/build/lib/dacbench/envs/modcma.py deleted file mode 100644 index 2760b1dc1..000000000 --- a/build/lib/dacbench/envs/modcma.py +++ /dev/null @@ -1,60 +0,0 @@ -import numpy as np -from modcma import ModularCMAES, Parameters -from IOHexperimenter import IOH_function - -from dacbench import AbstractEnv - - -class ModCMAEnv(AbstractEnv): - def __init__(self, config): - super().__init__(config) - - self.es = None - self.budget = config.budget - self.total_budget = self.budget - - self.get_reward = config.get("reward_function", self.get_default_reward) - self.get_state = config.get("state_method", self.get_default_state) - - def reset(self): - super().reset_() - self.dim, self.fid, self.iid, self.representation = self.instance - self.representation = np.array(self.representation) - self.objective = IOH_function( - self.fid, self.dim, self.iid, target_precision=1e-8 - ) - self.es = ModularCMAES( - self.objective, - parameters=Parameters.from_config_array( - self.dim, np.array(self.representation).astype(int) - ), - ) - return self.get_state(self), {} - - def step(self, action): - truncated = super().step_() - new_parameters = Parameters.from_config_array(self.dim, action) - self.es.parameters.update( - {m: getattr(new_parameters, m) for m in Parameters.__modules__} - ) - terminated = not self.es.step() - return self.get_state(self), self.get_reward(self), terminated, truncated, {} - - def close(self): - return True - - def get_default_reward(self, *_): - return max( - self.reward_range[0], min(self.reward_range[1], -self.es.parameters.fopt) - ) - - def get_default_state(self, *_): - return np.array( - [ - self.es.parameters.lambda_, - self.es.parameters.sigma, - self.budget - self.es.parameters.used_budget, - self.fid, - self.iid, - ] - ) diff --git a/build/lib/dacbench/envs/modea.py b/build/lib/dacbench/envs/modea.py deleted file mode 100644 index 28499086b..000000000 --- a/build/lib/dacbench/envs/modea.py +++ /dev/null @@ -1,289 +0,0 @@ -# Most of this code is taken from the paper "Online CMA-ES Selection" by Vermetten et al. -# Github: https://github.com/Dvermetten/Online_CMA-ES_Selection - -from modea.Algorithms import CustomizedES -from modea.Parameters import Parameters -import modea.Sampling as Sam -import modea.Mutation as Mut -import modea.Selection as Sel -import modea.Recombination as Rec -from dacbench import AbstractEnv -from modea.Utils import getOpts, getVals, options, initializable_parameters -from cma import bbobbenchmarks as bn -from functools import partial -import numpy as np - - -class ModeaEnv(AbstractEnv): - def __init__(self, config): - super(ModeaEnv, self).__init__(config) - self.es = None - self.budget = config.budget - self.total_budget = self.budget - - if "reward_function" in config.keys(): - self.get_reward = config["reward_function"] - else: - self.get_reward = self.get_default_reward - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - def reset(self): - super(ModeaEnv, self).reset_() - self.dim = self.instance[0] - self.function_id = self.instance[1] - self.instance_id = self.instance[2] - self.representation = self.ensureFullLengthRepresentation(self.instance[3]) - - opts = getOpts(self.representation[: len(options)]) - self.lambda_ = self.representation[len(options)] - self.mu = self.representation[len(options) + 1] - values = getVals(self.representation[len(options) + 2 :]) - - self.function, self.target = bn.instantiate(int(self.function_id)) - self.es = CustomizedES( - self.dim, self.function, self.budget, self.mu, self.lambda_, opts, values - ) - parameter_opts = self.es.parameters.getParameterOpts() - # print("Local restart on") - if parameter_opts["lambda_"]: - self.lambda_init = parameter_opts["lambda_"] - elif parameter_opts["local_restart"] in ["IPOP", "BIPOP"]: - self.lambda_init = int(4 + np.floor(3 * np.log(parameter_opts["n"]))) - else: - self.lambda_init = None - parameter_opts["lambda_"] = self.lambda_init - - # BIPOP Specific parameters - self.lambda_ = {"small": None, "large": self.lambda_init} - self.budgets = {"small": None, "large": None} - self.regime = "first" - self.update_parameters() - return self.get_state(self), {} - - def step(self, action): - truncated = super(ModeaEnv, self).step_() - terminated = False - self.representation = self.ensureFullLengthRepresentation(action) - opts = getOpts(self.representation[: len(options)]) - self.switchConfiguration(opts) - - self.es.runOneGeneration() - self.es.recordStatistics() - - if ( - self.es.budget <= self.es.used_budget - or self.es.parameters.checkLocalRestartConditions(self.es.used_budget) - ): - terminated = self.restart() - if self.es.total_used_budget < self.es.total_budget: - self.update_parameters() - else: - terminated = True - - return self.get_state(self), self.get_reward(self), terminated, truncated, {} - - def update_parameters(self): - # Every local restart needs its own parameters, so parameter update/mutation must also be linked every time - parameter_opts = self.es.parameters.getParameterOpts() - self.es.parameters = Parameters(**parameter_opts) - self.es.seq_cutoff = self.es.parameters.mu_int * self.es.parameters.seq_cutoff - self.es.mutateParameters = self.es.parameters.adaptCovarianceMatrix - - self.es.initializePopulation() - parameter_opts["wcm"] = self.es.population[0].genotype - self.es.new_population = self.es.recombine( - self.es.population, self.es.parameters - ) - - def restart(self): - done = False - parameter_opts = self.es.parameters.getParameterOpts() - self.es.total_used_budget += self.es.used_budget - if self.target is not None: - # TODO: make threshold an env parameter - if self.es.best_individual.fitness - self.target <= 1e-8: - done = True - # Increasing Population Strategies - if parameter_opts["local_restart"] == "IPOP": - parameter_opts["lambda_"] *= 2 - - elif parameter_opts["local_restart"] == "BIPOP": - try: - self.budgets[self.regime] -= self.es.used_budget - self.determineRegime() - except KeyError: # Setup of the two regimes after running regularily for the first time - remaining_budget = self.total_budget - self.es.used_budget - self.budgets["small"] = remaining_budget // 2 - self.budgets["large"] = remaining_budget - self.budgets["small"] - self.regime = "large" - - if self.regime == "large": - self.lambda_["large"] *= 2 - parameter_opts["sigma"] = 2 - elif self.regime == "small": - rand_val = self.np_random.random() ** 2 - self.lambda_["small"] = int( - np.floor( - self.lambda_init - * (0.5 * self.es.lambda_["large"] / self.lambda_init) - ** rand_val - ) - ) - parameter_opts["sigma"] = 2e-2 * self.np_random.random() - - self.es.budget = self.budgets[self.regime] - self.es.used_budget = 0 - parameter_opts["budget"] = self.budget - parameter_opts["lambda_"] = self.lambda_[self.regime] - return done - - def determineRegime(self): - large = self.budgets["large"] - small = self.budgets["small"] - if large <= 0: - self.regime = "small" - elif small <= 0: - self.regime = "large" - elif large > small: - self.regime = "large" - else: - self.regime = "small" - - def get_default_state(self, _): - return np.array( - [ - self.es.gen_size, - self.es.parameters.sigma, - self.budget - self.es.used_budget, - self.function_id, - self.instance_id, - ] - ) - - def get_default_reward(self, _): - return max( - self.reward_range[0], - min(self.reward_range[1], -self.es.best_individual.fitness), - ) - - def close(self): - return True - - def switchConfiguration(self, opts): - selector = Sel.pairwise if opts["selection"] == "pairwise" else Sel.best - - def select(pop, new_pop, _, param): - return selector(pop, new_pop, param) - - # Pick the lowest-level sampler - if opts["base-sampler"] == "quasi-sobol": - sampler = Sam.QuasiGaussianSobolSampling(self.es.n) - elif opts["base-sampler"] == "quasi-halton" and Sam.halton_available: - sampler = Sam.QuasiGaussianHaltonSampling(self.es.n) - else: - sampler = Sam.GaussianSampling(self.es.n) - - # Create an orthogonal sampler using the determined base_sampler - if opts["orthogonal"]: - orth_lambda = self.es.parameters.eff_lambda - if opts["mirrored"]: - orth_lambda = max(orth_lambda // 2, 1) - sampler = Sam.OrthogonalSampling( - self.es.n, lambda_=orth_lambda, base_sampler=sampler - ) - - # Create a mirrored sampler using the sampler (structure) chosen so far - if opts["mirrored"]: - sampler = Sam.MirroredSampling(self.es.n, base_sampler=sampler) - - parameter_opts = { - "weights_option": opts["weights_option"], - "active": opts["active"], - "elitist": opts["elitist"], - "sequential": opts["sequential"], - "tpa": opts["tpa"], - "local_restart": opts["ipop"], - } - - # In case of pairwise selection, sequential evaluation may only stop after 2mu instead of mu individuals - - if opts["sequential"] and opts["selection"] == "pairwise": - parameter_opts["seq_cutoff"] = 2 - self.es.parameters.seq_cutoff = 2 - - # Init all individuals of the first population at the same random point in the search space - - # We use functions/partials here to 'hide' the additional passing of parameters that are algorithm specific - recombine = Rec.weighted - mutate = partial( - Mut.CMAMutation, sampler=sampler, threshold_convergence=opts["threshold"] - ) - - functions = { - "recombine": recombine, - "mutate": mutate, - "select": select, - # 'mutateParameters': None - } - self.setConfigurationParameters(functions, parameter_opts) - lambda_, eff_lambda, mu = self.es.calculateDependencies(opts, None, None) - self.es.parameters.lambda_ = lambda_ - self.es.parameters.eff_lambda = eff_lambda - self.es.parameters.mu = mu - self.es.parameters.weights = self.es.parameters.getWeights( - self.es.parameters.weights_option - ) - self.es.parameters.mu_eff = 1 / np.sum(np.square(self.es.parameters.weights)) - mu_eff = self.es.parameters.mu_eff # Local copy - n = self.es.parameters.n - self.es.parameters.c_sigma = (mu_eff + 2) / (mu_eff + n + 5) - self.es.parameters.c_c = (4 + mu_eff / n) / (n + 4 + 2 * mu_eff / n) - self.es.parameters.c_1 = 2 / ((n + 1.3) ** 2 + mu_eff) - self.es.parameters.c_mu = min( - 1 - self.es.parameters.c_1, - self.es.parameters.alpha_mu - * ( - (mu_eff - 2 + 1 / mu_eff) - / ((n + 2) ** 2 + float(self.es.parameters.alpha_mu) * mu_eff / 2) - ), - ) - self.es.parameters.damps = ( - 1 - + 2 * np.max([0, np.sqrt((mu_eff - 1) / (n + 1)) - 1]) - + self.es.parameters.c_sigma - ) - self.es.seq_cutoff = self.es.parameters.mu_int * self.es.parameters.seq_cutoff - - def setConfigurationParameters(self, functions, parameters): - self.es.recombine = functions["recombine"] - self.es.mutate = functions["mutate"] - self.es.select = functions["select"] - # self.mutateParameters = functions['mutateParameters'] - self.es.parameters.weights_option = parameters["weights_option"] - self.es.parameters.active = parameters["active"] - self.es.parameters.elitist = parameters["elitist"] - self.es.parameters.sequential = parameters["sequential"] - self.es.parameters.tpa = parameters["tpa"] - self.es.parameters.local_restart = parameters["local_restart"] - - def ensureFullLengthRepresentation(self, representation): - """ - Given a (partial) representation, ensure that it is padded to become a full length customizedES representation, - consisting of the required number of structure, population and parameter values. - >>> ensureFullLengthRepresentation([]) - [0,0,0,0,0,0,0,0,0,0,0, None,None, None,None,None,None,None,None,None,None,None,None,None,None,None] - :param representation: List representation of a customizedES instance to check and pad if needed - :return: Guaranteed full-length version of the representation - """ - default_rep = ( - [0] * len(options) + [None, None] + [None] * len(initializable_parameters) - ) - if len(representation) < len(default_rep): - representation = np.append( - representation, default_rep[len(representation) :] - ).flatten() - return representation diff --git a/build/lib/dacbench/envs/policies/__init__.py b/build/lib/dacbench/envs/policies/__init__.py deleted file mode 100644 index 6a1f123cf..000000000 --- a/build/lib/dacbench/envs/policies/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from dacbench.envs.policies.csa_cma import csa -from dacbench.envs.policies.optimal_fd import get_optimum as optimal_fd -from dacbench.envs.policies.optimal_luby import get_optimum as optimal_luby -from dacbench.envs.policies.optimal_sigmoid import get_optimum as optimal_sigmoid - -OPTIMAL_POLICIES = { - "LubyBenchmark": optimal_luby, - "SigmoidBenchmark": optimal_sigmoid, - "FastDownwardBenchmark": optimal_fd, -} - -NON_OPTIMAL_POLICIES = {"CMAESBenchmark": csa} - -ALL_POLICIES = {**OPTIMAL_POLICIES, **NON_OPTIMAL_POLICIES} diff --git a/build/lib/dacbench/envs/policies/csa_cma.py b/build/lib/dacbench/envs/policies/csa_cma.py deleted file mode 100644 index 1b7c0d631..000000000 --- a/build/lib/dacbench/envs/policies/csa_cma.py +++ /dev/null @@ -1,7 +0,0 @@ -def csa(env, state): - u = env.es.sigma - hsig = env.es.adapt_sigma.hsig(env.es) - env.es.hsig = hsig - delta = env.es.adapt_sigma.update2(env.es, function_values=env.cur_obj_val) - u *= delta - return u diff --git a/build/lib/dacbench/envs/policies/optimal_fd.py b/build/lib/dacbench/envs/policies/optimal_fd.py deleted file mode 100644 index 47c0e7daf..000000000 --- a/build/lib/dacbench/envs/policies/optimal_fd.py +++ /dev/null @@ -1,8 +0,0 @@ -import json - - -def get_optimum(env, state): - instance = env.get_instance()[:-12] + "optimal.json" - with open(instance, "r+") as fp: - optimal = json.load(fp) - return optimal[env.c_step] diff --git a/build/lib/dacbench/envs/policies/optimal_luby.py b/build/lib/dacbench/envs/policies/optimal_luby.py deleted file mode 100644 index 5e602b8d4..000000000 --- a/build/lib/dacbench/envs/policies/optimal_luby.py +++ /dev/null @@ -1,14 +0,0 @@ -def luby_gen(i): - """ Generator for the Luby Sequence """ - for k in range(1, 33): - if i == ((1 << k) - 1): - yield 1 << (k - 1) - - for k in range(1, 9999): - if 1 << (k - 1) <= i < (1 << k) - 1: - for x in luby_gen(i - (1 << (k - 1)) + 1): - yield x - - -def get_optimum(env, state): - return env._next_goal diff --git a/build/lib/dacbench/envs/policies/optimal_sigmoid.py b/build/lib/dacbench/envs/policies/optimal_sigmoid.py deleted file mode 100644 index d7d6e8859..000000000 --- a/build/lib/dacbench/envs/policies/optimal_sigmoid.py +++ /dev/null @@ -1,25 +0,0 @@ -import numpy as np - - -def sig(x, scaling, inflection): - """ Simple sigmoid function """ - return 1 / (1 + np.exp(-scaling * (x - inflection))) - - -def get_optimum(env, state): - sigmoids = [ - np.abs(sig(env.c_step, slope, shift)) - for slope, shift in zip(env.shifts, env.slopes) - ] - action = [] - for i in range(len(env.action_vals)): - best_action = None - dist = 100 - for a in range(env.action_vals[i] + 1): - if np.abs(sigmoids[i] - a / (env.action_vals[i] - 1)) < dist: - dist = np.abs(sigmoids[i] - a / (env.action_vals[i])) - best_action = a - action.append(best_action) - for k in env.action_mapper.keys(): - if env.action_mapper[k] == tuple(action): - return k diff --git a/build/lib/dacbench/envs/policies/sgd_ca.py b/build/lib/dacbench/envs/policies/sgd_ca.py deleted file mode 100644 index 03b256a8b..000000000 --- a/build/lib/dacbench/envs/policies/sgd_ca.py +++ /dev/null @@ -1,33 +0,0 @@ -import math -from dacbench.abstract_agent import AbstractDACBenchAgent - - -class CosineAnnealingAgent(AbstractDACBenchAgent): - def __init__(self, env, base_lr=0.1, t_max=1000, eta_min=0): - self.eta_min = eta_min - self.t_max = t_max - self.base_lr = base_lr - self.current_lr = base_lr - self.last_epoch = -1 - super(CosineAnnealingAgent, self).__init__(env) - - def act(self, state, reward): - self.last_epoch += 1 - if self.last_epoch == 0: - return self.base_lr - elif (self.last_epoch - 1 - self.t_max) % (2 * self.t_max) == 0: - return ( - self.current_lr - + (self.base_lr - self.eta_min) - * (1 - math.cos(math.pi / self.t_max)) - / 2 - ) - return (1 + math.cos(math.pi * self.last_epoch / self.t_max)) / ( - 1 + math.cos(math.pi * (self.last_epoch - 1) / self.t_max) - ) * (self.current_lr - self.eta_min) + self.eta_min - - def train(self, state, reward): - pass - - def end_episode(self, state, reward): - pass diff --git a/build/lib/dacbench/envs/sgd.py b/build/lib/dacbench/envs/sgd.py deleted file mode 100644 index 38ab9bd8d..000000000 --- a/build/lib/dacbench/envs/sgd.py +++ /dev/null @@ -1,891 +0,0 @@ -import math -import numbers -import warnings -import json -from functools import reduce -from enum import IntEnum, auto - -import numpy as np -import torch -from backpack import backpack, extend -from backpack.extensions import BatchGrad -from numpy import float32 -from torchvision import datasets, transforms -from dacbench import AbstractEnv -import random - -warnings.filterwarnings("ignore") - - -def reward_range(frange): - def wrapper(f): - f.frange = frange - return f - return wrapper - - -class Reward(IntEnum): - TrainingLoss = auto() - ValidationLoss = auto() - LogTrainingLoss = auto() - LogValidationLoss = auto() - DiffTraining = auto() - DiffValidation = auto() - LogDiffTraining = auto() - LogDiffValidation = auto() - FullTraining = auto() - - def __call__(self, f): - if hasattr(self, 'func'): - raise ValueError('Can not assign the same reward to a different function!') - self.func = f - return f - - -class SGDEnv(AbstractEnv): - """ - Environment to control the learning rate of adam - """ - - def __init__(self, config): - """ - Initialize SGD Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super(SGDEnv, self).__init__(config) - - self.batch_size = config.training_batch_size - self.validation_batch_size = config.validation_batch_size - self.no_cuda = config.no_cuda - self.current_batch_size = config.training_batch_size - self.on_features = config.features - self.cd_paper_reconstruction = config.cd_paper_reconstruction - self.cd_bias_correction = config.cd_bias_correction - self.crashed = False - self.terminate_on_crash = config.terminate_on_crash - self.crash_penalty = config.crash_penalty - - if isinstance(config.reward_type, Reward): - self.reward_type = config.reward_type - elif isinstance(config.reward_type, str): - try: - self.reward_type = getattr(Reward, config.reward_type) - except AttributeError: - raise ValueError(f'{config.reward_type} is not a valid reward type!') - else: - raise ValueError(f'Type {type(config.reward_type)} is not valid!') - - self.use_cuda = not self.no_cuda and torch.cuda.is_available() - self.device = torch.device("cuda" if self.use_cuda else "cpu") - - self.training_validation_ratio = config.train_validation_ratio - self.dataloader_shuffle = config.dataloader_shuffle - # self.test_dataset = None - self.train_dataset = None - self.validation_dataset = None - self.train_loader = None - # self.test_loader = None - self.validation_loader = None - self.train_loader_it = None - self.validation_loader_it = None - - self.train_batch_index = 0 - self.epoch_index = 0 - - self.current_training_loss = None - self.loss_batch = None - self.prev_training_loss = None - self._current_validation_loss = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self._current_validation_loss.calculated = False - self.prev_validation_loss = torch.zeros( - 1, device=self.device, requires_grad=False - ) - - self.model = None - self.val_model = None - # TODO: - """ - TODO: Samuel Mueller (PhD student in our group) also uses backpack and has ran into a similar memory leak. - He solved it calling this custom made RECURSIVE memory_cleanup function: - # from backpack import memory_cleanup - # def recursive_backpack_memory_cleanup(module: torch.nn.Module): - # memory_cleanup(module) - # for m in module.modules(): - # memory_cleanup(m) - (calling this after computing the training loss/gradients and after validation loss should suffice) - """ - self.parameter_count = 0 - self.layer_sizes = [] - - self.loss_function = config.loss_function(**config.loss_function_kwargs) - self.loss_function = extend(self.loss_function) - self.val_loss_function = config.loss_function(**config.val_loss_function_kwargs) - - self.initial_lr = config.lr * torch.ones( - 1, device=self.device, requires_grad=False - ) - self.current_lr = config.lr * torch.ones( - 1, device=self.device, requires_grad=False - ) - - self.optimizer_name = config.optimizer - - self.beta1 = config.beta1 - self.beta2 = config.beta2 - self.epsilon = config.epsilon - # RMSprop parameters - self.beta2 = config.beta2 - self.m = 0 - self.v = 0 - # Momentum parameters - self.sgd_momentum_v = 0 - self.sgd_rho = 0.9 - - self.clip_grad = config.clip_grad - - self.t = 0 - self.step_count = torch.zeros(1, device=self.device, requires_grad=False) - - self.prev_direction = None - self.current_direction = None - - self.predictiveChangeVarDiscountedAverage = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.predictiveChangeVarUncertainty = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.lossVarDiscountedAverage = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.lossVarUncertainty = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.discount_factor = config.discount_factor - self.firstOrderMomentum = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.secondOrderMomentum = torch.zeros( - 1, device=self.device, requires_grad=False - ) - - if self.optimizer_name=="adam": - self.get_optimizer_direction = self.get_adam_direction - elif self.optimizer_name=="rmsprop": - self.get_optimizer_direction = self.get_rmsprop_direction - elif self.optimizer_name=="momentum": - self.get_optimizer_direction = self.get_momentum_direction - else: - raise NotImplementedError - - if "reward_function" in config.keys(): - self._get_reward = config["reward_function"] - else: - self._get_reward = self.reward_type.func - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - self.reward_range = self.reward_type.func.frange - - def get_reward(self): - return self._get_reward(self) - - @reward_range([-(10**9), 0]) - @Reward.TrainingLoss - def get_training_reward(self): - return -self.current_training_loss.item() - - @reward_range([-(10**9), 0]) - @Reward.ValidationLoss - def get_validation_reward(self): - return -self.current_validation_loss.item() - - @reward_range([-(10**9), (10**9)]) - @Reward.LogTrainingLoss - def get_log_training_reward(self): - return -torch.log(self.current_training_loss).item() - - @reward_range([-(10**9), (10**9)]) - @Reward.LogValidationLoss - def get_log_validation_reward(self): - return -torch.log(self.current_validation_loss).item() - - @reward_range([-(10**9), (10**9)]) - @Reward.LogDiffTraining - def get_log_diff_training_reward(self): - return -(torch.log(self.current_training_loss) - torch.log(self.prev_training_loss)).item() - - @reward_range([-(10**9), (10**9)]) - @Reward.LogDiffValidation - def get_log_diff_validation_reward(self): - return -(torch.log(self.current_validation_loss) - torch.log(self.prev_validation_loss)).item() - - @reward_range([-(10**9), (10**9)]) - @Reward.DiffTraining - def get_diff_training_reward(self): - return (self.current_training_loss - self.prev_training_loss).item() - - @reward_range([-(10**9), (10**9)]) - @Reward.DiffValidation - def get_diff_validation_reward(self): - return (self.current_validation_loss - self.prev_validation_loss).item() - - @reward_range([-(10**9), 0]) - @Reward.FullTraining - def get_full_training_reward(self): - return -self._get_full_training_loss(loader=self.train_loader).item() - - def get_full_training_loss(self): - return -self.get_full_training_reward() - - @property - def crash(self): - self.crashed = True - if self.c_step >= self.n_steps: - done = True - else: - done = self.terminate_on_crash - return self.get_state(self), self.crash_penalty, done, {} - - def seed(self, seed=None, seed_action_space=False): - """ - Set rng seed - - Parameters - ---------- - seed: - seed for rng - seed_action_space: bool, default False - if to seed the action space as well - """ - (seed,) = super().seed(seed, seed_action_space) - if seed is not None: - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.cuda.manual_seed_all(seed) - torch.backends.cudnn.benchmark = False - torch.backends.cudnn.deterministic = True - return [seed] - - def step(self, action): - """ - Execute environment step - - Parameters - ---------- - action : list - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, info - """ - truncated = super(SGDEnv, self).step_() - - self.step_count += 1 - index = 0 - - if not isinstance(action, int) and not isinstance(action, float): - action = action.item() - if not isinstance(action, numbers.Number): - action = action[0] - - if np.isnan(action): - return self.crash - - new_lr = torch.Tensor([action]).to(self.device) - self.current_lr = new_lr - - direction = self.get_optimizer_direction() - if np.isnan(direction).any(): - return self.crash - - self.current_direction = direction - - delta_w = torch.mul(new_lr, direction) - - for i, p in enumerate(self.model.parameters()): - layer_size = self.layer_sizes[i] - p.data = p.data - delta_w[index : index + layer_size].reshape( - shape=p.data.shape - ) - index += layer_size - - self.model.zero_grad() - - self.prev_training_loss = self.current_training_loss - if self._current_validation_loss.calculated: - self.prev_validation_loss = self.current_validation_loss - - self.train_network() - reward = self.get_reward() - - if np.isnan(reward): - return self.crash - - state = self.get_state(self) - for value in state.values(): - if np.isnan(value): - return self.crash - return state, reward, False, truncated, {} - - def _architecture_constructor(self, arch_str): - layer_specs = [] - layer_strs = arch_str.split("-") - for layer_str in layer_strs: - idx = layer_str.find("(") - if idx == -1: - nn_module_name = layer_str - vargs = [] - else: - nn_module_name = layer_str[:idx] - vargs_json_str = '{"tmp": [' + layer_str[idx + 1 : -1] + "]}" - vargs = json.loads(vargs_json_str)["tmp"] - layer_specs.append((getattr(torch.nn, nn_module_name), vargs)) - - def model_constructor(): - layers = [cls(*vargs) for cls, vargs in layer_specs] - return torch.nn.Sequential(*layers) - - return model_constructor - - def reset(self): - """ - Reset environment - - Returns - ------- - np.array - Environment state - """ - super(SGDEnv, self).reset_() - - dataset = self.instance[0] - instance_seed = self.instance[1] - construct_model = self._architecture_constructor(self.instance[2]) - self.n_steps = self.instance[3] - dataset_size = self.instance[4] - - self.crashed = False - - self.seed(instance_seed) - - self.model = construct_model().to(self.device) - self.val_model = construct_model().to(self.device) - - def init_weights(m): - if type(m) == torch.nn.Linear or type(m) == torch.nn.Conv2d: - torch.nn.init.xavier_normal(m.weight) - m.bias.data.fill_(0.0) - - if self.cd_paper_reconstruction: - self.model.apply(init_weights) - - train_dataloader_args = {"batch_size": self.batch_size, "drop_last": True, - 'shuffle': self.dataloader_shuffle} - validation_dataloader_args = {"batch_size": self.validation_batch_size, - "drop_last": True, 'shuffle': False} # SA: shuffling empty data loader causes exception - if self.use_cuda: - param = {"num_workers": 1, "pin_memory": True} - train_dataloader_args.update(param) - validation_dataloader_args.update(param) - - if dataset == "MNIST": - transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize((0.1307,), (0.3081,)) - ]) - - train_dataset = datasets.MNIST( - "../data", train=True, download=True, transform=transform - ) - # self.test_dataset = datasets.MNIST('../data', train=False, transform=transform) - elif dataset == "CIFAR": - transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), - ]) - - train_dataset = datasets.CIFAR10( - "../data", train=True, download=True, transform=transform - ) - # self.test_dataset = datasets.MNIST('../data', train=False, transform=transform) - else: - raise NotImplementedError - - if dataset_size is not None: - train_dataset = torch.utils.data.Subset( - train_dataset, range(0, dataset_size) - ) - - training_dataset_limit = math.floor( - len(train_dataset) * self.training_validation_ratio - ) - validation_dataset_limit = len(train_dataset) - - self.train_dataset = torch.utils.data.Subset( - train_dataset, range(0, training_dataset_limit - 1) - ) - self.validation_dataset = torch.utils.data.Subset( - train_dataset, range(training_dataset_limit, validation_dataset_limit) - ) - - self.train_loader = torch.utils.data.DataLoader( - self.train_dataset, **train_dataloader_args - ) - # self.test_loader = torch.utils.data.DataLoader(self.test_dataset, **train_dataloader_args) - self.validation_loader = torch.utils.data.DataLoader( - self.validation_dataset, **validation_dataloader_args - ) - - self.train_batch_index = 0 - self.epoch_index = 0 - self.train_loader_it = iter(self.train_loader) - self.validation_loader_it = iter(self.validation_loader) - - self.parameter_count = 0 - self.layer_sizes = [] - for p in self.model.parameters(): - layer_size = reduce(lambda x, y: x * y, p.shape) - self.layer_sizes.append(layer_size) - self.parameter_count += layer_size - - self.model = extend(self.model) - - self.model.zero_grad() - self.model.train() - self.val_model.eval() - - self.current_training_loss = None - self.loss_batch = None - - # Momentum parameters - self.m = 0 - self.v = 0 - self.sgd_momentum_v = 0 - - self.t = 0 - - self.step_count = torch.zeros(1, device=self.device, requires_grad=False) - - self.current_lr = self.initial_lr - self.prev_direction = torch.zeros( - (self.parameter_count,), device=self.device, requires_grad=False - ) - self.current_direction = torch.zeros( - (self.parameter_count,), device=self.device, requires_grad=False - ) - - self.predictiveChangeVarDiscountedAverage = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.predictiveChangeVarUncertainty = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.lossVarDiscountedAverage = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.lossVarUncertainty = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.firstOrderMomentum = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.secondOrderMomentum = torch.zeros( - 1, device=self.device, requires_grad=False - ) - - self._current_validation_loss = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self._current_validation_loss.calculated = False - self.prev_validation_loss = torch.zeros( - 1, device=self.device, requires_grad=False - ) - self.train_network() - - return self.get_state(self), {} - - def set_writer(self, writer): - self.writer = writer - - def close(self): - """ - No additional cleanup necessary - - Returns - ------- - bool - Cleanup flag - """ - return True - - def render(self, mode: str = "human"): - """ - Render env in human mode - - Parameters - ---------- - mode : str - Execution mode - """ - if mode != "human": - raise NotImplementedError - - pass - - def get_default_state(self, _): - """ - Gather state description - - Returns - ------- - dict - Environment state - - """ - self.gradients = self._get_gradients() - self.gradients = self.gradients.clip(*self.clip_grad) - - self.firstOrderMomentum, self.secondOrderMomentum, self.sgdMomentum = self._get_momentum(self.gradients) - - if 'predictiveChangeVarDiscountedAverage' in self.on_features or 'predictiveChangeVarUncertainty' in self.on_features: - predictiveChangeVarDiscountedAverage, predictiveChangeVarUncertainty = \ - self._get_predictive_change_features(self.current_lr) - - if 'lossVarDiscountedAverage' in self.on_features or 'lossVarUncertainty' in self.on_features: - lossVarDiscountedAverage, lossVarUncertainty = self._get_loss_features() - - if 'alignment' in self.on_features: - alignment = self._get_alignment() - - state = {} - - if 'predictiveChangeVarDiscountedAverage' in self.on_features: - state["predictiveChangeVarDiscountedAverage"] = predictiveChangeVarDiscountedAverage.item() - if 'predictiveChangeVarUncertainty' in self.on_features: - state["predictiveChangeVarUncertainty"] = predictiveChangeVarUncertainty.item() - if 'lossVarDiscountedAverage' in self.on_features: - state["lossVarDiscountedAverage"] = lossVarDiscountedAverage.item() - if 'lossVarUncertainty' in self.on_features: - state["lossVarUncertainty"] = lossVarUncertainty.item() - if 'currentLR' in self.on_features: - state["currentLR"] = self.current_lr.item() - if 'trainingLoss' in self.on_features: - if self.crashed: - state["trainingLoss"] = 0.0 - else: - state["trainingLoss"] = self.current_training_loss.item() - if 'validationLoss' in self.on_features: - if self.crashed: - state["validationLoss"] = 0.0 - else: - state["validationLoss"] = self.current_validation_loss.item() - if 'step' in self.on_features: - state["step"] = self.step_count.item() - if 'alignment' in self.on_features: - state["alignment"] = alignment.item() - if 'crashed' in self.on_features: - state["crashed"] = self.crashed - - return state - - def _train_batch_(self): - (data, target) = self.train_loader_it.next() - data, target = data.to(self.device), target.to(self.device) - self.current_batch_size = data.size()[0] - output = self.model(data) - loss = self.loss_function(output, target) - - with backpack(BatchGrad()): - loss.mean().backward() - - loss_value = loss.mean() - - self.loss_batch = loss - self.current_training_loss = torch.unsqueeze(loss_value.detach(), dim=0) - self.train_batch_index += 1 - self._current_validation_loss.calculated = False - - def train_network(self): - try: - self._train_batch_() - except StopIteration: - self.train_batch_index = 0 - self.epoch_index += 1 - self.train_loader_it = iter(self.train_loader) - self._train_batch_() - - def _get_full_training_loss(self, loader): - for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): - target_param.data.copy_(param.data) - loss = torch.zeros(1, device=self.device, requires_grad=False) - with torch.no_grad(): - for data, target in loader: - data, target = data.to(self.device), target.to(self.device) - output = self.val_model(data) - loss += self.val_loss_function(output, target).sum().detach().detach() - - loss /= len(loader.dataset) - return loss - - @property - def current_validation_loss(self): - if not self._current_validation_loss.calculated: - self._current_validation_loss = self._get_validation_loss() - self._current_validation_loss.calculated = True - return self._current_validation_loss - - def _get_validation_loss_(self): - with torch.no_grad(): - (data, target) = self.validation_loader_it.next() - data, target = data.to(self.device), target.to(self.device) - output = self.val_model(data) - validation_loss = self.val_loss_function(output, target).mean() - validation_loss = torch.unsqueeze(validation_loss.detach(), dim=0) - - return validation_loss - - def _get_validation_loss(self): - for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): - target_param.data.copy_(param.data) - try: - validation_loss = self._get_validation_loss_() - except StopIteration: - self.validation_loader_it = iter(self.validation_loader) - validation_loss = self._get_validation_loss_() - - return validation_loss - - def _get_gradients(self): - gradients = [] - for p in self.model.parameters(): - if p.grad is None: - continue - gradients.append(p.grad.flatten()) - - gradients = torch.cat(gradients, dim=0) - - return gradients - - def _get_momentum(self, gradients): - self.t += 1 - self.m = self.beta1 * self.m + (1 - self.beta1) * gradients - self.v = self.beta2 * self.v + (1 - self.beta2) * torch.square(gradients) - bias_corrected_m = self.m / (1 - self.beta1 ** self.t) - bias_corrected_v = self.v / (1 - self.beta2 ** self.t) - - self.sgd_momentum_v = self.sgd_rho * self.sgd_momentum_v + gradients - - return bias_corrected_m, bias_corrected_v, self.sgd_momentum_v - - def get_adam_direction(self): - return self.firstOrderMomentum / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) - - def get_rmsprop_direction(self): - return self.gradients / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) - - def get_momentum_direction(self): - return self.sgd_momentum_v - - def _get_loss_features(self): - if self.crashed: - return torch.tensor(0.0), torch.tensor(0.0) - bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 - with torch.no_grad(): - loss_var = torch.log(torch.var(self.loss_batch)) - self.lossVarDiscountedAverage = ( - self.discount_factor * self.lossVarDiscountedAverage - + (1 - self.discount_factor) * loss_var - ) - self.lossVarUncertainty = ( - self.discount_factor * self.lossVarUncertainty - + (1 - self.discount_factor) - * (loss_var - self.lossVarDiscountedAverage/bias_correction) ** 2 - ) - - return self.lossVarDiscountedAverage/bias_correction, self.lossVarUncertainty/bias_correction - - def _get_predictive_change_features(self, lr): - if self.crashed: - return torch.tensor(0.0), torch.tensor(0.0) - bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 - batch_gradients = [] - for i, (name, param) in enumerate(self.model.named_parameters()): - grad_batch = param.grad_batch.reshape( - self.current_batch_size, self.layer_sizes[i] - ) - batch_gradients.append(grad_batch) - - batch_gradients = torch.cat(batch_gradients, dim=1) - - update_value = torch.mul(lr, self.get_optimizer_direction()) - - predictive_change = torch.log( - torch.var(-1 * torch.matmul(batch_gradients, update_value)) - ) - - self.predictiveChangeVarDiscountedAverage = ( - self.discount_factor * self.predictiveChangeVarDiscountedAverage - + (1 - self.discount_factor) * predictive_change - ) - self.predictiveChangeVarUncertainty = ( - self.discount_factor * self.predictiveChangeVarUncertainty - + (1 - self.discount_factor) - * (predictive_change - self.predictiveChangeVarDiscountedAverage/bias_correction) ** 2 - ) - - return ( - self.predictiveChangeVarDiscountedAverage/bias_correction, - self.predictiveChangeVarUncertainty/bias_correction, - ) - - def _get_alignment(self): - if self.crashed: - return torch.tensor(0.0) - alignment = torch.mean(torch.sign(torch.mul(self.prev_direction, self.current_direction))) - alignment = torch.unsqueeze(alignment, dim=0) - self.prev_direction = self.current_direction - return alignment - - def generate_instance_file(self, file_name, mode='test', n=100): - header = ['ID', 'dataset', 'architecture', 'seed', 'steps'] - - # dataset name, architecture, dataset size, sample dimension, number of max pool layers, hidden layers, test architecture convolutional layers - architectures = [ - ('MNIST', - 'Conv2d(1, {0}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({0}, {1}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-Flatten-Linear({3}, 10)-LogSoftmax(1)', - 60000, - 28, - 2, - 3, - [20, 50, 500] - ), - ('CIFAR', - 'Conv2d(3, {0}, 3, 1, 1)-MaxPool2d(2, 2)-ReLU-Conv2d({0}, {1}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({2}, {3}, 3, 1, 1)-ReLU-Flatten-Linear({4}, 10)-LogSoftmax(1)', - 60000, - 32, - 3, - 4, - [32, 32, 64, 64] - ) - ] - if mode is 'test': - - seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] - - for i in range(len(architectures)): - - fname = file_name + "_" + architectures[i][0].lower() + ".csv" - - steps = int(1e8) - - conv = architectures[i][6] - hidden_layers = architectures[i][5] - - sample_size = architectures[i][3] - pool_layer_count = architectures[i][4] - linear_layer_size = conv[-1] * pow(sample_size / pow(2, pool_layer_count), 2) - linear_layer_size = int(round(linear_layer_size)) - - dataset = architectures[i][0] - - if hidden_layers == 3: - architecture = architectures[i][1].format(conv[0], conv[1], conv[2], linear_layer_size) - else: - architecture = architectures[i][1].format(conv[0], conv[1], conv[2], conv[3], linear_layer_size) - - # args = conv - # args.append(linear_layer_size) - # # architecture = architectures[i][1].format(**conv) - # args = {0: conv[0], 1: conv[1], 2: conv[2], 3: linear_layer_size} - # architecture = architectures[i][1].format(**args) - - with open(fname, 'w', encoding='UTF8') as f: - for h in header: - f.write(h + ";") - - f.write("\n") - - for id in range(0, n): - f.write(str(id) + ";") - - f.write(dataset + ";") - f.write(architecture + ";") - - seed = seed_list[id] - f.write(str(seed) + ";") - - f.write(str(steps) + ";") - - f.write("\n") - f.close() - - else: - dataset_index = 0 - - dataset_size_start = 0.1 - dataset_size_stop = 0.5 - - steps_start = 300 - steps_stop = 1000 - - conv1_start = 2 - conv1_stop = 10 - conv2_start = 5 - conv2_stop = 25 - conv3_start = 50 - conv3_stop = 250 - - dataset_list = [dataset_index for _ in range(n)] - - dataset_size_list = [random.uniform(dataset_size_start, dataset_size_stop) for _ in range(n)] - - seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] - - steps_list = [random.randrange(start=steps_start, stop=steps_stop) for _ in range(n)] - - conv1_list = [random.randrange(start=conv1_start, stop=conv1_stop) for _ in range(n)] - conv2_list = [random.randrange(start=conv2_start, stop=conv2_stop) for _ in range(n)] - conv3_list = [random.randrange(start=conv3_start, stop=conv3_stop) for _ in range(n)] - - fname = file_name + ".csv" - with open(fname, 'w', encoding='UTF8') as f: - for h in header: - f.write(h + ";") - - f.write("\n") - - for id in range(0, n): - f.write(str(id) + ";") - - sample_size = architectures[dataset_list[id]][3] - pool_layer_count = architectures[dataset_list[id]][4] - linear_layer_size = conv3_list[id] * pow(sample_size / pow(2, pool_layer_count), 2) - linear_layer_size = int(round(linear_layer_size)) - - dataset_size = int(dataset_size_list[id] * architectures[dataset_list[id]][2]) - dataset = architectures[dataset_list[id]][0] + "_" + str(dataset_size) - architecture = architectures[dataset_list[id]][1].format(conv1_list[id], conv2_list[id], conv3_list[id], linear_layer_size) - - f.write(dataset + ";") - f.write(architecture + ";") - - seed = seed_list[id] - f.write(str(seed) + ";") - - steps = steps_list[id] - f.write(str(steps) + ";") - - f.write("\n") - f.close() diff --git a/build/lib/dacbench/envs/sigmoid.py b/build/lib/dacbench/envs/sigmoid.py deleted file mode 100644 index 89dc8f2fa..000000000 --- a/build/lib/dacbench/envs/sigmoid.py +++ /dev/null @@ -1,325 +0,0 @@ -""" -Sigmoid environment from -"Dynamic Algorithm Configuration:Foundation of a New Meta-Algorithmic Framework" -by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. -Original environment authors: André Biedenkapp, H. Furkan Bozkurt -""" - -import itertools -from typing import List - -import matplotlib.cm as cm -import matplotlib.pyplot as plt -import numpy as np - -from dacbench import AbstractEnv - - -class SigmoidEnv(AbstractEnv): - """ - Environment for tracing sigmoid curves - """ - - def _sig(self, x, scaling, inflection): - """ Simple sigmoid function """ - return 1 / (1 + np.exp(-scaling * (x - inflection))) - - def __init__(self, config) -> None: - """ - Initialize Sigmoid Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super(SigmoidEnv, self).__init__(config) - - self.shifts = [self.n_steps / 2 for _ in config["action_values"]] - self.slopes = [-1 for _ in config["action_values"]] - self.slope_multiplier = config["slope_multiplier"] - self.action_vals = config["action_values"] - self.n_actions = len(self.action_vals) - self.action_mapper = {} - for idx, prod_idx in zip( - range(np.prod(config["action_values"])), - itertools.product(*[np.arange(val) for val in config["action_values"]]), - ): - self.action_mapper[idx] = prod_idx - self._prev_state = None - self.action = None - - if "reward_function" in config.keys(): - self.get_reward = config["reward_function"] - else: - self.get_reward = self.get_default_reward - - if "state_method" in config.keys(): - self.get_state = config["state_method"] - else: - self.get_state = self.get_default_state - - def step(self, action: int): - """ - Execute environment step - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, info - """ - self.done = super(SigmoidEnv, self).step_() - action = self.action_mapper[action] - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - - self.action = action - next_state = self.get_state(self) - self._prev_state = next_state - return next_state, self.get_reward(self), False, self.done, {} - - def reset(self) -> List[int]: - """ - Resets env - - Returns - ------- - numpy.array - Environment state - """ - super(SigmoidEnv, self).reset_() - self.shifts = self.instance[: self.n_actions] - self.slopes = self.instance[self.n_actions :] - self._prev_state = None - return self.get_state(self), {} - - def get_default_reward(self, _): - r = [ - 1 - np.abs(self._sig(self.c_step, slope, shift) - (act / (max_act - 1))) - for slope, shift, act, max_act in zip( - self.slopes, self.shifts, self.action, self.action_vals - ) - ] - r = np.prod(r) - r = max(self.reward_range[0], min(self.reward_range[1], r)) - return r, {} - - def get_default_state(self, _): - remaining_budget = self.n_steps - self.c_step - next_state = [remaining_budget] - for shift, slope in zip(self.shifts, self.slopes): - next_state.append(shift) - next_state.append(slope) - if self.c_step == 0: - next_state += [-1 for _ in range(self.n_actions)] - else: - next_state += self.action - return np.array(next_state) - - def close(self) -> bool: - """ - Close Env - - Returns - ------- - bool - Closing confirmation - """ - return True - - def render(self, mode: str) -> None: - """ - Render env in human mode - - Parameters - ---------- - mode : str - Execution mode - """ - if mode == "human" and self.n_actions == 2: - plt.ion() - plt.show() - plt.cla() - steps = np.arange(self.n_steps) - self.data = self._sig(steps, self.slopes[0], self.shifts[0]) * self._sig( - steps, self.slopes[1], self.shifts[1] - ).reshape(-1, 1) - - plt.imshow( - self.data, - extent=(0, self.n_steps - 1, 0, self.n_steps - 1), - interpolation="nearest", - cmap=cm.plasma, - ) - plt.axvline(x=self.c_step, color="r", linestyle="-", linewidth=2) - plt.axhline(y=self.c_step, color="r", linestyle="-", linewidth=2) - - plt.draw() - plt.pause(0.005) - - -class ContinuousStateSigmoidEnv(SigmoidEnv): - """ - Environment for tracing sigmoid curves with a continuous state on the x-axis - """ - - def __init__(self, config) -> None: - """ - Initialize Sigmoid Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super().__init__(config) - - def step(self, action: int): - """ - Execute environment step - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, info - """ - action = self.action_mapper[action] - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - - self.action = action - # The reward measures how wrong the choice was so we can take this error to determine how far we travel along - # the x-axis instead of always advancing + 1 - r = self.get_reward(self) - - # magic constants but such that the max step is ~1 and the min step is ~0.25 - self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25))/2 - - if self.c_step >= self.n_steps: - self.done = True - else: - self.done = False - - # self.c_step is used in get_next_state to show how much distance along the x-axis is left to cover - # Thus we get a continuous state this way. - next_state = self.get_state(self) - self._prev_state = next_state - return next_state, r, self.done, {} - -class ContinuousSigmoidEnv(SigmoidEnv): - """ - Environment for tracing sigmoid curves with a continuous state on the x-axis - """ - - def __init__(self, config) -> None: - """ - Initialize Sigmoid Env - - Parameters - ------- - config : objdict - Environment configuration - """ - super().__init__(config) - - def step(self, action: np.ndarray): - """ - Execute environment step. !!NOTE!! The action here is a list of floats and not a single number !!NOTE!! - - Parameters - ---------- - action : list of floats - action(s) to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, info - """ - assert self.n_actions == len( - action - ), f"action should be of length {self.n_actions}." - - self.action = action - # The reward measures how wrong the choice was so we can take this error to determine how far we travel along - # the x-axis instead of always advancing + 1 - r = self.get_reward(self) - - # magic constants but such that the max step is ~1 and the min step is ~0.25 - self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25)) / 2 - - if self.c_step >= self.n_steps: - self.done = True - else: - self.done = False - - # self.c_step is used in get_next_state to show how much distance along the x-axis is left to cover - # Thus we get a continuous state this way. - next_state = self.get_state(self) - self._prev_state = next_state - return next_state, r, self.done, {} - - -if __name__ == '__main__': - from dacbench.abstract_benchmark import objdict - config = objdict( - { - "action_space_class": "Box", - "action_space_args": [ - np.array([-np.inf for _ in range(1 + 2 * 3)]), - np.array([np.inf for _ in range(1 + 2 * 3)]), - ], - "observation_space_class": "Box", - "observation_space_type": np.float32, - "observation_space_args": [ - np.array([-np.inf for _ in range(1 + 2 * 3)]), - np.array([np.inf for _ in range(1 + 2 * 3)]), - ], - "reward_range": (0, 1), - "cutoff": 10, - "action_values": (2, 2), - "slope_multiplier": 2.0, - "seed": 0, - "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", - "benchmark_info": None, - 'instance_set': {0:[5.847291747472278,6.063505157165379,5.356361033331866,8.473324526654427], - 1:[5.699459023308639,0.17993881762205755,3.4218338308013356,8.486280024502191], - 2:[5.410536230957515,5.700091608324946,-5.3540400976249165,2.76787147719077], - 3:[1.5799464875295817,6.374885201056433,1.0378986341827443,4.219330699379608], - 4:[2.61235568666599,6.478051235772757,7.622760392199338,-3.0898869570275167]}, - } - ) - env = ContinuousSigmoidEnv(config) - done = False - s = env.reset() - env.render(mode='human') - while not done: - a = [np.random.rand(), np.random.rand()] - print(env.c_step, a) - s, r, done, _ = env.step(a) - env.render('human') - - - config['action_space'] = "Discrete" - config["action_space_args"] = [int(np.prod((2, 2)))], - env = ContinuousStateSigmoidEnv(config) - done = False - s = env.reset() - env.render(mode='human') - while not done: - a = np.random.randint(4) - print(env.c_step, a) - s, r, done, _ = env.step(a) - env.render('human') diff --git a/build/lib/dacbench/envs/theory.py b/build/lib/dacbench/envs/theory.py deleted file mode 100644 index d2caca966..000000000 --- a/build/lib/dacbench/envs/theory.py +++ /dev/null @@ -1,574 +0,0 @@ -import numpy as np -from copy import deepcopy -import logging -from collections import deque - -import uuid -import gym - -from dacbench import AbstractEnv - - -class BinaryProblem: - """ - An abstract class for an individual in binary representation - """ - - def __init__(self, n, rng=np.random.default_rng()): - self.data = rng.choice([True, False], size=n) - self.n = n - self.fitness = self.eval() - - def initialise_with_fixed_number_of_bits(self, k, rng=np.random.default_rng()): - nbits = self.data.sum() - if nbits < k: - ids = rng.choice( - np.where(self.data == False)[0], size=k - nbits, replace=False - ) - self.data[ids] = True - self.eval() - - def is_optimal(self): - pass - - def get_optimal(self): - pass - - def eval(self): - pass - - def get_fitness_after_flipping(self, locs): - """ - Calculate the change in fitness after flipping the bits at positions locs - - Parameters - ----------- - locs: 1d-array - positions where bits are flipped - - Returns: int - ----------- - objective after flipping - """ - raise NotImplementedError - - def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): - """ - Calculate fitness of the child aftering being crossovered with xprime - - Parameters - ----------- - xprime: 1d boolean array - the individual to crossover with - locs_x: 1d boolean/integer array - positions where we keep current bits of self - locs_xprime: : 1d boolean/integer array - positions where we change to xprime's bits - - Returns: fitness of the new individual after crossover - ----------- - """ - raise NotImplementedError - - def flip(self, locs): - """ - flip the bits at position indicated by locs - - Parameters - ----------- - locs: 1d-array - positions where bits are flipped - - Returns: the new individual after the flip - """ - child = deepcopy(self) - child.data[locs] = ~child.data[locs] - child.eval() - return child - - def combine(self, xprime, locs_xprime): - """ - combine (crossover) self and xprime by taking xprime's bits at locs_xprime and self's bits at other positions - - Parameters - ----------- - xprime: 1d boolean array - the individual to crossover with - locs_x: 1d boolean/integer array - positions where we keep current bits of self - locs_xprime: : 1d boolean/integer array - positions where we change to xprime's bits - - Returns: the new individual after the crossover - - """ - child = deepcopy(self) - child.data[locs_xprime] = xprime.data[locs_xprime] - child.eval() - return child - - def mutate(self, p, n_childs, rng=np.random.default_rng()): - """ - Draw l ~ binomial(n, p), l>0 - Generate n_childs children by flipping exactly l bits - Return: the best child (maximum fitness), its fitness and number of evaluations used - """ - assert p >= 0 - - if p == 0: - return self, self.fitness, 0 - - l = 0 - while l == 0: - l = rng.binomial(self.n, p) - - best_obj = -1 - best_locs = None - for i in range(n_childs): - locs = rng.choice(self.n, size=l, replace=False) - obj = self.get_fitness_after_flipping(locs) - if obj > best_obj: - best_locs = locs - best_obj = obj - - best_child = self.flip(best_locs) - - return best_child, best_child.fitness, n_childs - - def mutate_rls(self, l, rng=np.random.default_rng()): - """ - generate a child by flipping exactly l bits - Return: child, its fitness - """ - assert l >= 0 - - if l == 0: - return self, self.fitness, 0 - - locs = rng.choice(self.n, size=l, replace=False) - child = self.flip(locs) - - return child, child.fitness, 1 - - def crossover( - self, - xprime, - p, - n_childs, - include_xprime=True, - count_different_inds_only=True, - rng=np.random.default_rng(), - ): - """ - Crossover operator: - for each bit, taking value from x with probability p and from self with probability 1-p - Arguments: - x: the individual to crossover with - p (float): in [0,1] - """ - assert p <= 1 - - if p == 0: - if include_xprime: - return xprime, xprime.fitness, 0 - else: - return self, self.fitness, 0 - - if include_xprime: - best_obj = xprime.fitness - else: - best_obj = -1 - best_locs = None - - n_evals = 0 - ls = rng.binomial(self.n, p, size=n_childs) - for l in ls: - locs_xprime = rng.choice(self.n, l, replace=False) - locs_x = np.full(self.n, True) - locs_x[locs_xprime] = False - obj = self.get_fitness_after_crossover(xprime, locs_x, locs_xprime) - - if (obj != self.fitness) and (obj != xprime.fitness): - n_evals += 1 - elif ( - not np.array_equal(xprime.data[locs_xprime], self.data[locs_xprime]) - ) and (not np.array_equal(self.data[locs_x], xprime.data[locs_x])): - n_evals += 1 - - if obj > best_obj: - best_obj = obj - best_locs = locs_xprime - - if best_locs is not None: - child = self.combine(xprime, best_locs) - else: - child = xprime - - if not count_different_inds_only: - n_evals = n_childs - - return child, child.fitness, n_evals - - -class LeadingOne(BinaryProblem): - """ - An individual for LeadingOne problem - The aim is to maximise the number of leading (and consecutive) 1 bits in the string - """ - - def __init__(self, n, rng=np.random.default_rng(), initObj=None): - if initObj is None: - super(LeadingOne, self).__init__(n=n, rng=rng) - else: - self.data = rng.choice([True, False], size=n) - self.data[: int(initObj)] = True - self.data[int(initObj)] = False - self.n = n - self.fitness = self.eval() - - def eval(self): - k = self.data.argmin() - if self.data[k]: - self.fitness = self.n - else: - self.fitness = k - return self.fitness - - def is_optimal(self): - return self.data.all() - - def get_optimal(self): - return self.n - - def get_fitness_after_flipping(self, locs): - min_loc = locs.min() - if min_loc < self.fitness: - return min_loc - elif min_loc > self.fitness: - return self.fitness - else: - old_fitness = self.fitness - self.data[locs] = ~self.data[locs] - new_fitness = self.eval() - self.data[locs] = ~self.data[locs] - self.fitness = old_fitness - return new_fitness - - def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): - child = self.combine(xprime, locs_xprime) - child.eval() - return child.fitness - - -MAX_INT = 1e8 -HISTORY_LENGTH = 5 - - -class RLSEnv(AbstractEnv): - """ - Environment for RLS with step size - Current assumption: we only consider (1+1)-RLS, so there's only one parameter to tune (r) - """ - - def __init__(self, config, test_env=False) -> None: - """ - Initialize RLSEnv - - Parameters - ------- - config : objdict - Environment configuration - """ - super(RLSEnv, self).__init__(config) - self.logger = logging.getLogger(self.__str__()) - - self.test_env = test_env - - self.name = config.name - - # name of reward function - assert config.reward_choice in [ - "imp_div_evals", - "imp_div_evals_new", - "imp_minus_evals", - "minus_evals", - "imp", - "minus_evals_normalised", - "imp_minus_evals_normalised", - ] - self.reward_choice = config.reward_choice - # print("Reward choice: " + self.reward_choice) - - # get problem - self.problem = globals()[config.problem] - - # read names of all observation variables - self.obs_description = config.observation_description - self.obs_var_names = [ - s.strip() for s in config.observation_description.split(",") - ] - - # functions to get values of the current state from histories - # (see reset() function for those history variables) - self.state_functions = [] - for var_name in self.obs_var_names: - if var_name == "n": - self.state_functions.append(lambda: self.n) - elif var_name in ["r"]: - self.state_functions.append( - lambda his="history_" + var_name: vars(self)[his][-1] - ) - elif ( - "_{t-" in var_name - ): # TODO: this implementation only allow accessing history of r, but not delta_f(x), optimal_k, etc - k = int( - var_name.split("_{t-")[1][:-1] - ) # get the number in _{t-} - name = var_name.split("_{t-")[0] # get the variable name (r, f(x), etc) - self.state_functions.append( - lambda his="history_" + name: vars(self)[his][-(k + 1)] - ) # the last element is the value at the current time step, so we have to go one step back to access the history - elif var_name == "f(x)": - self.state_functions.append(lambda: self.history_fx[-1]) - elif var_name == "delta_f(x)": - self.state_functions.append( - lambda: self.history_fx[-1] - self.history_fx[-2] - ) - elif var_name == "optimal_r": - self.state_functions.append( - lambda: int(self.n / (self.history_fx[-1] + 1)) - ) - else: - raise Exception("Error: invalid state variable name: " + var_name) - - # the random generator used by RLS - if "seed" in config: - seed = config.seed - else: - seed = None - if "seed" in self.instance: - seed = self.instance.seed - self.seed(seed) - - # for logging - self.outdir = None - if "outdir" in config: - self.outdir = config.outdir + "/" + str(uuid.uuid4()) - - def get_obs_domain_from_name(var_name): - """ - Get default lower and upperbound of a observation variable based on its name. - The observation space will then be created - Return: - Two int values, e.g., 1, np.inf - """ - return 0, np.inf - - def reset(self): - """ - Resets env - - Returns - ------- - numpy.array - Environment state - """ - super(RLSEnv, self).reset_() - - # current problem size (n) & evaluation limit (max_evals) - self.n = self.instance.size - if self.test_env: - self.max_evals = self.n_steps - else: - self.max_evals = int(0.8 * self.n * self.n) - self.logger.info("n:%d, max_evals:%d" % (self.n, self.max_evals)) - - # set random seed - if "seed" in self.instance: - self.seed(self.instance.seed) - - # create an initial solution - if self.instance.initObj == "random": - self.x = self.problem(n=self.instance.size, rng=self.np_random) - else: - self.x = self.problem( - n=self.instance.size, rng=self.np_random, initObj=self.instance.initObj - ) - - # total number of evaluations so far - self.total_evals = 1 - - # reset histories - self.history_r = deque([0] * HISTORY_LENGTH, maxlen=HISTORY_LENGTH) - self.history_fx = deque( - [self.x.fitness] * HISTORY_LENGTH, maxlen=HISTORY_LENGTH - ) - - # for debug only - self.log_r = [] - self.log_reward = [] - self.log_fx = [] - self.init_obj = self.x.fitness - - return self.get_state(), {} - - def get_state(self): - return np.asarray([f() for f in self.state_functions]) - - def step(self, action): - """ - Execute environment step - - Parameters - ---------- - action : Box - action to execute - - Returns - ------- - state, reward, terminated, truncated, info - np.array, float, bool, bool, dict - """ - truncated = super(RLSEnv, self).step_() - - fitness_before_update = self.x.fitness - - # get r - if isinstance(action, np.ndarray) or isinstance(action, list): - assert len(action) == 1 - r = action[0] - else: - r = action - - # if r is out of range - stop = False - if r < 1 or r > self.n: - self.logger.info(f"WARNING: r={r} is out of bound") - - # if we're in the training phase, we return a large negative reward and stop the episode - if self.test_env is False: - terminated = True - n_evals = 0 - reward = -MAX_INT - stop = True - # if we're in the test phase, just clip r back to the range and continue - else: - r = np.clip(r, 1, self.n) - - if stop is False: - # flip r bits - r = int(r) - y, f_y, n_evals = self.x.mutate_rls(r, self.np_random) - - # update x - if self.x.fitness <= y.fitness: - self.x = y - - # update total number of evaluations - self.total_evals += n_evals - - # check stopping criteria - terminated = (self.total_evals >= self.max_evals) or (self.x.is_optimal()) - - # calculate reward - if self.reward_choice == "imp_div_evals": - reward = (self.x.fitness - fitness_before_update - 0.5) / n_evals - elif self.reward_choice == "imp_minus_evals": - reward = self.x.fitness - fitness_before_update - n_evals - elif self.reward_choice == "minus_evals": - reward = -n_evals - elif self.reward_choice == "minus_evals_normalised": - reward = -n_evals / self.max_evals - elif self.reward_choice == "imp_minus_evals_normalised": - reward = ( - self.x.fitness - fitness_before_update - n_evals - ) / self.max_evals - elif self.reward_choice == "imp": - reward = self.x.fitness - fitness_before_update - 0.5 - self.log_reward.append(reward) - - # update histories - self.history_fx.append(self.x.fitness) - self.history_r.append(r) - - # update logs - self.log_r.append(r) - self.log_fx.append(self.x.fitness) - self.log_reward.append(reward) - - returned_info = {"msg": "", "values": {}} - if terminated or truncated: - if hasattr(self, "env_type"): - msg = "Env " + self.env_type + ". " - else: - msg = "" - msg += "Episode done: n=%d; obj=%d; init_obj=%d; evals=%d; max_evals=%d; steps=%d; r_min=%.1f; r_max=%.1f; r_mean=%.1f; R=%.4f" % ( - self.n, - self.x.fitness, - self.init_obj, - self.total_evals, - self.max_evals, - self.c_step, - min(self.log_r), - max(self.log_r), - sum(self.log_r) / len(self.log_r), - sum(self.log_reward), - ) - # self.logger.info(msg) - returned_info["msg"] = msg - returned_info["values"] = { - "n": int(self.n), - "obj": int(self.x.fitness), - "init_obj": int(self.init_obj), - "evals": int(self.total_evals), - "max_evals": int(self.max_evals), - "steps": int(self.c_step), - "r_min": float(min(self.log_r)), - "r_max": float(max(self.log_r)), - "r_mean": float(sum(self.log_r) / len(self.log_r)), - "R": float(sum(self.log_reward)), - "log_r": [int(x) for x in self.log_r], - "log_fx": [int(x) for x in self.log_fx], - "log_reward": [float(x) for x in self.log_reward], - } - - return self.get_state(), reward, truncated, terminated, returned_info - - def close(self) -> bool: - """ - Close Env - - No additional cleanup necessary - - Returns - ------- - bool - Closing confirmation - """ - return True - - -class RLSEnvDiscrete(RLSEnv): - """ - RLS environment where the choices of r is discretised - """ - - def __init__(self, config, test_env=False): - super(RLSEnvDiscrete, self).__init__(config, test_env) - assert ( - "action_choices" in config - ), "Error: action_choices must be specified in benchmark's config" - assert isinstance( - self.action_space, gym.spaces.Discrete - ), "Error: action space must be discrete" - assert self.action_space.n == len(config["action_choices"]), ( - "Error: action space's size (%d) must be equal to the len(action_choices) (%d)" - % (self.action_space.n, len(config["action_choices"])) - ) - self.action_choices = config["action_choices"] - - def step(self, action): - if isinstance(action, np.ndarray) or isinstance(action, list): - assert len(action) == 1 - action = action[0] - return super(RLSEnvDiscrete, self).step(self.action_choices[action]) diff --git a/build/lib/dacbench/envs/toysgd.py b/build/lib/dacbench/envs/toysgd.py deleted file mode 100644 index 4f7e913d3..000000000 --- a/build/lib/dacbench/envs/toysgd.py +++ /dev/null @@ -1,234 +0,0 @@ -from dacbench import AbstractEnv -import numpy as np -from numpy.polynomial import Polynomial -from typing import Union, Tuple, Optional, Dict -import pandas as pd - - -def create_polynomial_instance_set( - out_fname: str, - n_samples: int = 100, - order: int = 2, - low: float = -10, - high: float = 10, -): - instances = [] - for i in range(n_samples): - coeffs = sample_coefficients(order=order, low=low, high=high) - instance = { - "ID": i, - "family": "polynomial", - "order": order, - "low": low, - "high": high, - "coefficients": coeffs, - } - instances.append(instance) - df = pd.DataFrame(instances) - df.to_csv(out_fname, sep=";", index=False) - - -def sample_coefficients(order: int = 2, low: float = -10, high: float = 10): - n_coeffs = order + 1 - coeffs = np.zeros((n_coeffs,)) - coeffs[0] = np.random.uniform(0, high, size=1) - coeffs[1:] = np.random.uniform(low, high, size=n_coeffs - 1) - return coeffs - - -class ToySGDEnv(AbstractEnv): - """ - Optimize toy functions with SGD + Momentum. - - - Action: [log_learning_rate, log_momentum] (log base 10) - State: Dict with entries remaining_budget, gradient, learning_rate, momentum - Reward: negative log regret of current and true function value - - An instance can look as follows: - ID 0 - family polynomial - order 2 - low -2 - high 2 - coefficients [ 1.40501053 -0.59899755 1.43337392] - - """ - - def __init__(self, config): - super(ToySGDEnv, self).__init__(config) - self.n_steps_max = config.get("cutoff", 1000) - - self.velocity = 0 - self.gradient = 0 - self.history = [] - self.n_dim = None # type: Optional[int] - self.objective_function = None - self.objective_function_deriv = None - self.x_min = None - self.f_min = None - self.x_cur = None - self.f_cur = None - self.momentum = 0 # type: Optional[float] - self.learning_rate = None # type: Optional[float] - self.n_steps = 0 # type: Optional[int] - - def build_objective_function(self): - if self.instance["family"] == "polynomial": - order = int(self.instance["order"]) - if order != 2: - raise NotImplementedError( - "Only order 2 is currently implemented for polynomial functions." - ) - self.n_dim = order - coeffs_str = self.instance["coefficients"] - coeffs_str = coeffs_str.strip("[]") - coeffs = [float(item) for item in coeffs_str.split()] - self.objective_function = Polynomial(coef=coeffs) - self.objective_function_deriv = self.objective_function.deriv( - m=1 - ) # lambda x0: derivative(self.objective_function, x0, dx=1.0, n=1, args=(), order=3) - self.x_min = -coeffs[1] / ( - 2 * coeffs[0] + 1e-10 - ) # add small epsilon to avoid numerical instabilities - self.f_min = self.objective_function(self.x_min) - - self.x_cur = self.get_initial_position() - else: - raise NotImplementedError( - "No other function families than polynomial are currently supported." - ) - - def get_initial_position(self): - return 0 # np.random.uniform(-5, 5, size=self.n_dim-1) - - def step( - self, action: Union[float, Tuple[float, float]] - ) -> Tuple[Dict[str, float], float, bool, Dict]: - """ - Take one step with SGD - - Parameters - ---------- - action: Tuple[float, Tuple[float, float]] - If scalar, action = (log_learning_rate) - If tuple, action = (log_learning_rate, log_momentum) - - Returns - ------- - Tuple[Dict[str, float], float, bool, Dict] - - - state : Dict[str, float] - State with entries "remaining_budget", "gradient", "learning_rate", "momentum" - - reward : float - - terminated : bool - - truncated : bool - - info : Dict - """ - truncated = super(ToySGDEnv, self).step_() - info = {} - - # parse action - if np.isscalar(action): - log_learning_rate = action - elif len(action) == 2: - log_learning_rate, log_momentum = action - self.momentum = 10**log_momentum - else: - raise ValueError - self.learning_rate = 10**log_learning_rate - - # SGD + Momentum update - self.velocity = ( - self.momentum * self.velocity + self.learning_rate * self.gradient - ) - self.x_cur -= self.velocity - self.gradient = self.objective_function_deriv(self.x_cur) - - # State - remaining_budget = self.n_steps_max - self.n_steps - state = { - "remaining_budget": remaining_budget, - "gradient": self.gradient, - "learning_rate": self.learning_rate, - "momentum": self.momentum, - } - - # Reward - # current function value - self.f_cur = self.objective_function(self.x_cur) - # log regret - log_regret = np.log10(np.abs(self.f_min - self.f_cur)) - reward = -log_regret - - self.history.append(self.x_cur) - - # Stop criterion - self.n_steps += 1 - - return state, reward, False, truncated, info - - def reset(self): - """ - Reset environment - - Returns - ------- - np.array - Environment state - dict - Meta-info - """ - super(ToySGDEnv, self).reset_() - - self.velocity = 0 - self.gradient = 0 - self.history = [] - self.objective_function = None - self.objective_function_deriv = None - self.x_min = None - self.f_min = None - self.x_cur = None - self.f_cur = None - self.momentum = 0 - self.learning_rate = 0 - self.n_steps = 0 - self.build_objective_function() - return { - "remaining_budget": self.n_steps_max, - "gradient": self.gradient, - "learning_rate": self.learning_rate, - "momentum": self.momentum, - }, {} - - def render(self, **kwargs): - import matplotlib.pyplot as plt - - history = np.array(self.history).flatten() - X = np.linspace(1.05 * np.amin(history), 1.05 * np.amax(history), 100) - Y = self.objective_function(X) - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(X, Y, label="True") - ax.plot( - history, - self.objective_function(history), - marker="x", - color="black", - label="Observed", - ) - ax.plot( - self.x_cur, - self.objective_function(self.x_cur), - marker="x", - color="red", - label="Current Optimum", - ) - ax.legend() - ax.set_xlabel("x") - ax.set_ylabel("y") - ax.set_title("instance: " + str(self.instance["coefficients"])) - plt.show() - - def close(self): - pass diff --git a/build/lib/dacbench/logger.py b/build/lib/dacbench/logger.py deleted file mode 100644 index 601786e70..000000000 --- a/build/lib/dacbench/logger.py +++ /dev/null @@ -1,915 +0,0 @@ -import json -from abc import ABCMeta, abstractmethod -from collections import defaultdict, ChainMap -from datetime import datetime -from functools import reduce -from itertools import chain -from numbers import Number -from pathlib import Path -from typing import Union, Dict, Any, Tuple, List - -import numpy as np -import pandas as pd - -from typing import Callable, Iterable -from dacbench import AbstractEnv, AbstractBenchmark -from dacbench.abstract_agent import AbstractDACBenchAgent - - -def load_logs(log_file: Path) -> List[Dict]: - """ - Loads the logs from a jsonl written by any logger. - - The result is the list of dicts in the format: - { - 'instance': 0, - 'episode': 0, - 'step': 1, - 'example_log_val': { - 'values': [val1, val2, ... valn], - 'times: [time1, time2, ..., timen], - } - ... - } - Parameters - ---------- - log_file: pathlib.Path - The path to the log file - - Returns - ------- - [Dict, ...] - """ - with open(log_file, "r") as log_file: - logs = list(map(json.loads, log_file)) - - return logs - - -def split(predicate: Callable, iterable: Iterable) -> Tuple[List, List]: - """ - Splits the iterable into two list depending on the result of predicate. - - Parameters - ---------- - predicate: Callable - A function taking an element of the iterable and return Ture or False - iterable: Iterable - - Returns - ------- - (positives, negatives) - """ - positives, negatives = [], [] - - for item in iterable: - (positives if predicate(item) else negatives).append(item) - - return positives, negatives - - -def flatten_log_entry(log_entry: Dict) -> List[Dict]: - """ - Transforms a log entry of format like - - - { - 'step': 0, - 'episode': 2, - 'some_value': { - 'values' : [34, 45], - 'times':['28-12-20 16:20:53', '28-12-20 16:21:30'], - } - } - into - [ - { 'step': 0,'episode': 2, 'value': 34, 'time': '28-12-20 16:20:53'}, - { 'step': 0,'episode': 2, 'value': 45, 'time': '28-12-20 16:21:30'} - ] - - Parameters - ---------- - log_entry: Dict - A log entry - - Returns - ------- - """ - dict_entries, top_level_entries = split( - lambda item: isinstance(item[1], dict), log_entry.items() - ) - rows = [] - for value_name, value_dict in dict_entries: - current_rows = ( - dict( - top_level_entries - + [("value", value), ("time", time), ("name", value_name)] - ) - for value, time in zip(value_dict["values"], value_dict["times"]) - ) - - rows.extend(map(dict, current_rows)) - - return rows - - -def list_to_tuple(list_: List) -> Tuple: - """ - Recursively transforms a list of lists into tuples of tuples - Parameters - ---------- - list_: - (nested) list - - Returns - ------- - (nested) tuple - """ - return tuple( - list_to_tuple(item) if isinstance(item, list) else item for item in list_ - ) - - -def log2dataframe( - logs: List[dict], wide: bool = False, drop_columns: List[str] = ["time"] -) -> pd.DataFrame: - """ - Converts a list of log entries to a pandas dataframe. - - Usually used in combination with load_dataframe. - - Parameters - ---------- - logs: List - List of log entries - wide: bool - wide=False (default) produces a dataframe with columns (episode, step, time, name, value) - wide=True returns a dataframe (episode, step, time, name_1, name_2, ...) if the variable name_n has not been logged - at (episode, step, time) name_n is NaN. - drop_columns: List[str] - List of column names to be dropped (before reshaping the long dataframe) mostly used in combination - with wide=True to reduce NaN values - - Returns - ------- - dataframe - """ - - flat_logs = map(flatten_log_entry, logs) - rows = reduce(lambda l1, l2: l1 + l2, flat_logs) - - dataframe = pd.DataFrame(rows) - dataframe.time = pd.to_datetime(dataframe.time) - - if drop_columns is not None: - dataframe = dataframe.drop(columns=drop_columns) - - dataframe = dataframe.infer_objects() - list_column_candidates = dataframe.dtypes == object - - for i, candidate in enumerate(list_column_candidates): - if candidate: - dataframe.iloc[:, i] = dataframe.iloc[:, i].apply( - lambda x: list_to_tuple(x) if isinstance(x, list) else x - ) - - if wide: - primary_index_columns = ["episode", "step"] - field_id_column = "name" - additional_columns = list( - set(dataframe.columns) - - set(primary_index_columns + ["time", "value", field_id_column]) - ) - index_columns = primary_index_columns + additional_columns + [field_id_column] - dataframe = dataframe.set_index(index_columns) - dataframe = dataframe.unstack() - dataframe.reset_index(inplace=True) - dataframe.columns = [a if b == "" else b for a, b in dataframe.columns] - - return dataframe.infer_objects() - - -def seed_mapper(self): - if self.env is None: - return None - return self.env.initial_seed - - -def instance_mapper(self): - if self.env is None: - return None - return self.env.get_inst_id() - - -class AbstractLogger(metaclass=ABCMeta): - """ - Logger interface. - - The logger classes provide a way of writing structured logs as jsonl files and also help to track information like - current episode, step, time ... - - In the jsonl log file each row corresponds to a step. - """ - - valid_types = { - "recursive": [dict, list, tuple, np.ndarray], - "primitive": [str, int, float, bool, np.number], - } - - def __init__( - self, - experiment_name: str, - output_path: Path, - step_write_frequency: int = None, - episode_write_frequency: int = 1, - ): - """ - - Parameters - ---------- - experiment_name: str - Name of the folder to store the result in - output_path: pathlib.Path - Path under which the experiment folder is created - step_write_frequency: int - number of steps after which the loggers writes to file. - If None only the data is only written to file if write is called, if triggered by episode_write_frequency - or on close - episode_write_frequency: int - see step_write_frequency - """ - self.experiment_name = experiment_name - self.output_path = output_path - self.log_dir = self._init_logging_dir(self.output_path / self.experiment_name) - self.step_write_frequency = step_write_frequency - self.episode_write_frequency = episode_write_frequency - self._additional_info = {} - self.additional_info_auto_mapper = { - "instance": instance_mapper, - "seed": seed_mapper, - } - self.env = None - - @property - def additional_info(self): - additional_info = self._additional_info.copy() - auto_info = { - key: mapper(self) - for key, mapper in self.additional_info_auto_mapper.items() - if mapper(self) is not None - } - - additional_info.update(auto_info) - - return additional_info - - def set_env(self, env: AbstractEnv) -> None: - """ - Needed to infer automatically logged information like the instance id - Parameters - ---------- - env: AbstractEnv - - Returns - ------- - - """ - self.env = env - - @staticmethod - def _pretty_valid_types() -> str: - """ - Returns a string pretty string representation of the types that can be logged as values - Returns - ------- - - """ - valid_types = chain( - AbstractLogger.valid_types["recursive"], - AbstractLogger.valid_types["primitive"], - ) - return ", ".join(map(lambda type_: type_.__name__, valid_types)) - - @staticmethod - def _init_logging_dir(log_dir: Path) -> None: - """ - Prepares the logging directory - Parameters - ---------- - log_dir: pathlib.Path - - Returns - ------- - None - """ - log_dir.mkdir(parents=True, exist_ok=True) - return log_dir - - def is_of_valid_type(self, value: Any) -> bool: - f""" - Checks if the value of any type in {AbstractLogger._pretty_valid_types()} - Parameters - ---------- - value - - Returns - ------- - bool - """ - - if any(isinstance(value, type) for type in self.valid_types["primitive"]): - return True - - elif any(isinstance(value, type) for type in self.valid_types["recursive"]): - value = value.vlaues() if isinstance(value, dict) else value - return all(self.is_of_valid_type(sub_value) for sub_value in value) - - else: - return False - - @abstractmethod - def close(self) -> None: - """ - Makes sure, that all remaining entries in the are written to file and the file is closed. - - Returns - ------- - - """ - pass - - @abstractmethod - def next_step(self) -> None: - """ - Call at the end of the step. - Updates the internal state and dumps the information of the last step into a json - - Returns - ------- - - """ - pass - - @abstractmethod - def next_episode(self) -> None: - """ - Call at the end of episode. - - See next_step - Returns - ------- - - """ - pass - - @abstractmethod - def write(self) -> None: - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ - pass - - @abstractmethod - def log(self, key: str, value) -> None: - f""" - Writes value to list of values and save the current time for key - - Parameters - ---------- - key: str - value: - the value must of of a type that is json serializable. - Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. - - Returns - ------- - - """ - pass - - @abstractmethod - def log_dict(self, data): - """ - Alternative to log if more the one value should be logged at once. - - Parameters - ---------- - data: dict - a dict with key-value so that each value is a valid value for log - - Returns - ------- - - """ - pass - - @abstractmethod - def log_space(self, key: str, value: Union[np.ndarray, Dict], space_info=None): - """ - Special for logging gym.spaces. - - Currently three types are supported: - * Numbers: e.g. samples from Discrete - * Fixed length arrays like MultiDiscrete or Box - * Dict: assuming each key has fixed length array - - Parameters - ---------- - key: - see log - value: - see log - space_info: - a list of column names. The length of this list must equal the resulting number of columns. - - Returns - ------- - - """ - pass - - -class ModuleLogger(AbstractLogger): - """ - A logger for handling logging of one module. e.g. a wrapper or toplevel general logging. - - Don't create manually use Logger to manage ModuleLoggers - """ - - def __init__( - self, - output_path: Path, - experiment_name: str, - module: str, - step_write_frequency: int = None, - episode_write_frequency: int = 1, - ) -> None: - """ - All results are placed under 'output_path / experiment_name' - - Parameters - ---------- - experiment_name: str - Name of the folder to store the result in - output_path: pathlib.Path - Path under which the experiment folder is created - module: str - the module (mostly name of the wrapper), each wrapper gets its own file - step_write_frequency: int - number of steps after which the loggers writes to file. - If None only the data is only written to file if write is called, if triggered by episode_write_frequency - or on close - episode_write_frequency: int - see step_write_frequency - output_path: - The path where logged information should be stored - - """ - super(ModuleLogger, self).__init__( - experiment_name, output_path, step_write_frequency, episode_write_frequency - ) - - self.log_file = open(self.log_dir / f"{module}.jsonl", "w") - - self.step = 0 - self.episode = 0 - self.buffer = [] - self.current_step = self.__init_dict() - - def get_logfile(self) -> Path: - """ - Returns - ------- - pathlib.Path - the path to the log file of this logger - """ - return Path(self.log_file.name) - - def close(self): - """ - Makes sure, that all remaining entries in the are written to file and the file is closed. - - Returns - ------- - - """ - if not self.log_file.closed: - self.write() - self.log_file.close() - - def __del__(self): - if not self.log_file.closed: - self.close() - - @staticmethod - def __json_default(object): - """ - Add supoort for dumping numpy arrays and numbers to json - Parameters - ---------- - object - - Returns - ------- - - """ - if isinstance(object, np.ndarray): - return object.tolist() - elif isinstance(object, np.number): - return object.item() - else: - raise ValueError(f"Type {type(object)} not supported") - - def __end_step(self): - if self.current_step: - self.current_step["step"] = self.step - self.current_step["episode"] = self.episode - self.current_step.update(self.additional_info) - self.buffer.append( - json.dumps(self.current_step, default=self.__json_default) - ) - self.current_step = self.__init_dict() - - @staticmethod - def __init_dict(): - return defaultdict(lambda: {"times": [], "values": []}) - - def reset_episode(self) -> None: - """ - Resets the episode and step. - - Be aware that this can lead to ambitious keys if no instance or seed or other identifying additional info is set - - Returns - ------- - - """ - self.__end_step() - self.episode = 0 - self.step = 0 - - def __reset_step(self): - self.__end_step() - self.step = 0 - - def next_step(self): - """ - Call at the end of the step. - Updates the internal state and dumps the information of the last step into a json - - Returns - ------- - - """ - self.__end_step() - if ( - self.step_write_frequency is not None - and self.step % self.step_write_frequency == 0 - ): - self.write() - self.step += 1 - - def next_episode(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ - self.__reset_step() - if ( - self.episode_write_frequency is not None - and self.episode % self.episode_write_frequency == 0 - ): - self.write() - self.episode += 1 - - def write(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ - self.__end_step() - self.__buffer_to_file() - - def __buffer_to_file(self): - if len(self.buffer) > 0: - self.log_file.write("\n".join(self.buffer)) - self.log_file.write("\n") - self.buffer.clear() - self.log_file.flush() - - def set_additional_info(self, **kwargs): - """ - Can be used to log additional information for each step e.g. for seed, and instance id. - Parameters - ---------- - kwargs - - Returns - ------- - - """ - self._additional_info.update(kwargs) - - def log( - self, key: str, value: Union[Dict, List, Tuple, str, int, float, bool] - ) -> None: - f""" - Writes value to list of values and save the current time for key - - Parameters - ---------- - key: str - value: - the value must of of a type that is json serializable. - Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. - - Returns - ------- - - """ - self.__log(key, value, datetime.now().strftime("%d-%m-%y %H:%M:%S.%f")) - - def __log(self, key, value, time): - if not self.is_of_valid_type(value): - valid_types = self._pretty_valid_types() - raise ValueError( - f"value {type(value)} is not of valid type or a recursive composition of valid types ({valid_types})" - ) - self.current_step[key]["times"].append(time) - self.current_step[key]["values"].append(value) - - def log_dict(self, data: Dict) -> None: - """ - Alternative to log if more the one value should be logged at once. - - Parameters - ---------- - data: dict - a dict with key-value so that each value is a valid value for log - - Returns - ------- - """ - time = datetime.now().strftime("%d-%m-%y %H:%M:%S.%f") - for key, value in data.items(): - self.__log(key, value, time) - - @staticmethod - def __space_dict(key: str, value, space_info): - if isinstance(value, np.ndarray) and len(value.shape) == 0: - value = value.item() - - if isinstance(value, Number): - if space_info is None: - data = {key: value} - else: - if len(space_info) != 1: - raise ValueError( - f"Space info must match length (expect 1 != got{len(space_info)}" - ) - - data = {f"{key}_{space_info[0]}": value} - - elif isinstance(value, np.ndarray): - if space_info is not None and len(space_info) != len(value): - raise ValueError( - f"Space info must match length (expect {len(value)} != got{len(space_info)}" - ) - key_suffix = ( - enumerate(value) if space_info is None else zip(space_info, value) - ) - data = {f"{key}_{suffix}": x for suffix, x in key_suffix} - - elif isinstance(value, dict): - key_suffix = ( - value.items() if space_info is None else zip(space_info, value.values()) - ) - dicts = ( - ModuleLogger.__space_dict(f"{key}_{sub_key}", sub_value, None) - for sub_key, sub_value in key_suffix - ) - data = dict(ChainMap(*dicts)) - else: - raise ValueError("Space does not seem be supported") - - return data - - def log_space(self, key, value, space_info=None): - """ - Special for logging gym.spaces. - - Currently three types are supported: - * Numbers: e.g. samples from Discrete - * Fixed length arrays like MultiDiscrete or Box - * Dict: assuming each key has fixed length array - - Parameters - ---------- - key: - see log - value: - see log - space_info: - a list of column names. The length of this list must equal the resulting number of columns. - - Returns - ------- - - """ - data = self.__space_dict(key, value, space_info) - self.log_dict(data) - - -class Logger(AbstractLogger): - """ - A logger that manages the creation of the module loggers. - - To get a ModuleLogger for you module (e.g. wrapper) call module_logger = Logger(...).add_module("my_wrapper"). - From now on module_logger.log(...) or logger.log(..., module="my_wrapper") can be used to log. - - The logger module takes care of updating information like episode and step in the subloggers. To indicate to the loggers - the end of the episode or the next_step simple call logger.next_episode() or logger.next_step(). - """ - - def __init__( - self, - experiment_name: str, - output_path: Path, - step_write_frequency: int = None, - episode_write_frequency: int = 1, - ) -> None: - """ - - Parameters - ---------- - experiment_name: str - Name of the folder to store the result in - output_path: pathlib.Path - Path under which the experiment folder is created - step_write_frequency: int - number of steps after which the loggers writes to file. - If None only the data is only written to file if write is called, if triggered by episode_write_frequency - or on close - episode_write_frequency: int - see step_write_frequency - """ - super(Logger, self).__init__( - experiment_name, output_path, step_write_frequency, episode_write_frequency - ) - self.env: AbstractEnv = None - self.module_logger: Dict[str, ModuleLogger] = dict() - - def set_env(self, env: AbstractEnv) -> None: - super().set_env(env) - for _, module_logger in self.module_logger.items(): - module_logger.set_env(env) - - def close(self): - """ - Makes sure, that all remaining entries (from all sublogger) are written to files and the files are closed. - - Returns - ------- - - """ - for _, module_logger in self.module_logger.items(): - module_logger.close() - - def __del__(self): - self.close() - - def next_step(self): - """ - Call at the end of the step. - Updates the internal state of all subloggers and dumps the information of the last step into a json - - Returns - ------- - - """ - for _, module_logger in self.module_logger.items(): - module_logger.next_step() - - def next_episode(self): - """ - Call at the end of episode. - - See next_step - Returns - ------- - - """ - for _, module_logger in self.module_logger.items(): - module_logger.next_episode() - - def reset_episode(self): - for _, module_logger in self.module_logger.items(): - module_logger.reset_episode() - - def write(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ - for _, module_logger in self.module_logger.items(): - module_logger.write() - - def add_module(self, module: Union[str, type]) -> ModuleLogger: - """ - Creates a sub-logger. For more details see class level documentation - Parameters - ---------- - module: str or type - The module name or Wrapper-Type to create a sub-logger for - Returns - ------- - ModuleLogger - """ - if isinstance(module, str): - pass - elif isinstance(module, type): - module = module.__name__ - else: - module = module.__class__ - - if module in self.module_logger: - raise ValueError(f"Module {module} already registered") - else: - self.module_logger[module] = ModuleLogger( - self.output_path, - self.experiment_name, - module, - self.step_write_frequency, - self.episode_write_frequency, - ) - if self.env is not None: - self.module_logger[module].set_env(self.env) - - return self.module_logger[module] - - def add_agent(self, agent: AbstractDACBenchAgent): - """ - Writes information about the agent - Parameters - ---------- - agent: AbstractDACBenchAgent - - Returns - ------- - """ - agent_config = {"type": str(agent.__class__)} - with open(self.log_dir / "agent.json", "w") as f: - json.dump(agent_config, f) - - def add_benchmark(self, benchmark: AbstractBenchmark) -> None: - """ - Writes the config to the experiment path - Parameters - ---------- - benchmark - - Returns - ------- - - """ - benchmark.save_config(self.log_dir / "benchmark.json") - - def set_additional_info(self, **kwargs): - for _, module_logger in self.module_logger.items(): - module_logger.set_additional_info(**kwargs) - - def log(self, key, value, module): - if module not in self.module_logger: - raise ValueError(f"Module {module} not registered yet") - self.module_logger.log(key, value) - - def log_space(self, key, value, module, space_info=None): - if module not in self.module_logger: - raise ValueError(f"Module {module} not registered yet") - self.module_logger.log_space(key, value, space_info) - - def log_dict(self, data, module): - if module not in self.module_logger: - raise ValueError(f"Module {module} not registered yet") - self.module_logger.log_space(data) diff --git a/build/lib/dacbench/plotting.py b/build/lib/dacbench/plotting.py deleted file mode 100644 index 031685e42..000000000 --- a/build/lib/dacbench/plotting.py +++ /dev/null @@ -1,557 +0,0 @@ -from typing import List, Tuple - -import numpy as np -import seaborn as sns -import pandas as pd - -sns.set_style("darkgrid") - - -def space_sep_upper(column_name: str) -> str: - """ - Separates strings at underscores into headings. - Used to generate labels from logging names. - - Parameters - ---------- - column_name : str - - Returns - ------- - str - """ - if column_name is None: - return None - return column_name.title().replace("_", " ") - - -def generate_global_step( - data: pd.DataFrame, - x_column: str = "global_step", - x_label_columns: str = ["episode", "step"], -) -> Tuple[pd.DataFrame, str, List[str]]: - """ - Add a global_step column which enumerate all step over all episodes. - - Returns the altered data, a data frame containing mapping between global_step, x_column and x_label_columns. - - Often used in combination with add_multi_level_ticks. - - Parameters - ---------- - data: - x_column: str - the name of the global_step (default 'global_step') - x_label_columns: [str, ...] - the name and hierarchical order of the columns (default ['episode', 'step'] - - Returns - ------- - (data, plot_index, x_column, x_label_columns) - """ - plot_index = ( - data.groupby(x_label_columns) - .count() - .reset_index()[x_label_columns] - .sort_values(x_label_columns) - ) - plot_index[x_column] = np.arange(len(plot_index)) - plot_index.set_index(x_column) - data = data.merge(plot_index, on=x_label_columns) - return data, plot_index, x_column, x_label_columns - - -def add_multi_level_ticks( - grid: sns.FacetGrid, plot_index: pd.DataFrame, x_column: str, x_label_columns: str -) -> None: - """ - Expects a FacedGrid with global_step (x_column) as x-axis and replaces the tick labels to match format episode:step - - E.g. Run with 3 episodes, each of 10 steps. This results in 30 global steps. - The resulting tick labels could be ['0', '4', '9', '14', '19', '24', '29']. - After applying this method they will look like ['0:0', '0:4', '1:0', '1:4', '2:0', '2:4', '3:0', '3:4'] - - Parameters - ---------- - grid: sns.FacesGrid - - plot_index: pd.DataFrame - The mapping between current tick labels (global step values) and new tick labels joined by ':'. - usually the result from generate_global_step - x_column: str - column label to use for looking up tick values - x_label_columns: [str, ...] - columns labels of columns to use for new labels (joined by ':' - - Returns - ------- - - """ - for ax in grid.axes.flat: - ticks = ax.get_xticks() - sub_set = plot_index[plot_index[x_column].isin(ticks)] - new_labels = ( - sub_set.loc[tick][x_label_columns].tolist() - if tick in sub_set.index - else (None, None) - for tick in ticks - ) - new_labels = [ - f"{epoch}:{step}" if epoch is not None else "" for epoch, step in new_labels - ] - ax.set_xticklabels(new_labels, minor=False) - - -def plot( - plot_function, - settings: dict, - title: str = None, - x_label: str = None, - y_label: str = None, - **kwargs, -) -> sns.FacetGrid: - """ - Helper function that: create a FacetGrid - 1. Updates settings with kwargs (overwrites values) - 2. Plots using plot_function(**settings) - 3. Set x and y labels of not provided the columns names will converted to pretty strings using space_sep_upper - 4. Sets title (some times has to be readjusted afterwards especially in case of large plots e.g. multiple rows/cols) - - Parameters - ---------- - plot_function: - function to generate the FacedGrid. E.g. sns.catplot or sns.catplot - settings: dict - a dicts containing all needed default settings. - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - - """ - settings.update(kwargs.items()) # 1. - grid = plot_function(**settings) # 2. - - # 3. - x_label = space_sep_upper(grid._x_var) if x_label is None else x_label - y_label = space_sep_upper(grid._y_var) if y_label is None else y_label - grid.set_xlabels(x_label) - grid.set_ylabels(y_label) - - # 4. - grid.tight_layout() - if title is not None: - grid.fig.suptitle(title, y=0.97) # rule of thumb. Has to be improved in future - grid.fig.subplots_adjust(top=0.9) - - return grid - - -def plot_performance( - data, title=None, x_label=None, y_label=None, **kwargs -) -> sns.FacetGrid: - """ - Create a line plot of the performance over episodes. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to examples/plotting/performance_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - settings = { - "data": data, - "x": "episode", - "y": "overall_performance", - "kind": "line", - } - grid = plot(sns.relplot, settings, title, x_label, y_label, **kwargs) - - return grid - - -def plot_performance_per_instance( - data, title=None, x_label=None, y_label=None, **args -) -> sns.FacetGrid: - """ - Create a bar plot of the mean performance per instance ordered by the performance. - - Per default the mean performance seeds is shown if you want to change - this specify a property to map seed to e.g. col='seed'. - For more details see: https://seaborn.pydata.org/generated/seaborn.catplot.html - - For examples refer to examples/plotting/performance_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - # order the columns by mean instance - order = data.groupby("instance").mean().sort_values("overall_performance").index - settings = { - "data": data, - "x": "instance", - "y": "overall_performance", - "order": order, - "kind": "bar", - } - grid = plot(sns.catplot, settings, title, x_label, y_label, **args) - # todo: should probably not always be set like this (multi row/col) - grid.set_titles("Mean Performance per Instance") - return grid - - -def plot_step_time( - data, - show_global_step=False, - interval=1, - title=None, - x_label=None, - y_label=None, - **args, -) -> sns.FacetGrid: - """ - Create a line plot showing the measured time per step. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to examples/plotting/time_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - show_global_step: bool - If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) - interval: int - Interval in number of steps to average over. (default = 1) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - multi_level_x_label = "Epoch:Step" - data, plot_index, x_column, x_label_columns = generate_global_step(data) - if interval > 1: - data["groups"] = data[x_column] // interval - data = data.groupby("groups").agg({x_column: "min", "step_duration": "mean"}) - y_label = ( - f"Mean per duration per {interval} steps" if y_label is None else y_label - ) - - settings = { - "data": data, - "x": x_column, - "y": "step_duration", - "kind": "line", - } - if x_label is None and not show_global_step: - x_label = multi_level_x_label - - grid = plot(sns.relplot, settings, title, x_label, y_label, **args) - if not show_global_step: - add_multi_level_ticks(grid, plot_index, x_column, x_label_columns) - - return grid - - -def plot_episode_time( - data, title=None, x_label=None, y_label=None, **kargs -) -> sns.FacetGrid: - """ - Create a line plot showing the measured time per episode. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to examples/plotting/time_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - settings = { - "data": data, - "x": "episode", - "y": "episode_duration", - "kind": "line", - } - - grid = plot(sns.relplot, settings, title, x_label, y_label, **kargs) - - return grid - - -def plot_action( - data, - show_global_step=False, - interval=1, - title=None, - x_label=None, - y_label=None, - **kargs, -): - """ - Create a line plot showing actions over time. - - Please be aware that action spaces can be quite large and the plots can become quite messy (and take some time) - if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the - plot method. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to examples/plotting/action_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - show_global_step: bool - If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) - interval: int - Interval in number of steps to average over. (default = 1) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - - return plot_space( - data, "action", show_global_step, interval, title, x_label, y_label, **kargs - ) - - -def plot_state( - data, - show_global_step=False, - interval=1, - title=None, - x_label=None, - y_label=None, - **kargs, -): - """ - Create a line plot showing state over time. - - Please be aware that state can be quite large and the plots can become quite messy (and take some time) - if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the - plot method. Especially for dict state spaces. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to examples/plotting/state_plotting.py - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - show_global_step: bool - If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) - interval: int - Interval in number of steps to average over. (default = 1) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - return plot_space( - data, "state", show_global_step, interval, title, x_label, y_label, **kargs - ) - - -def plot_space( - data, - space_column_name, - show_global_step, - interval=1, - title=None, - x_label=None, - y_label=None, - **args, -) -> sns.FacetGrid: - """ - Create a line plot showing sapce over time. - - Please be aware that spaces can be quite large and the plots can become quite messy (and take some time) - if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the - plot method. Especially for dict spaces. - - Per default the mean performance and and one stddev over all instances and seeds is shown if you want to change - this specify a property to map those attributes to e.g hue='seed' or/and col='instance'. - For more details see: https://seaborn.pydata.org/generated/seaborn.relplot.html - - For examples refer to - examples/plotting/state_plotting.py or - examples/plotting/action_plotting.py - - - Parameters - ---------- - data: pd.DataFrame - Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) - show_global_step: bool - If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) - interval: int - Interval in number of steps to average over. (default = 1) - title: str - Title of the plot (optional) - x_label: str - Label of the x-axis (optional) - y_label: str - Label of the y-axis (optional) - kwargs: - Keyword arguments to overwrite default settings. - - Returns - ------- - sns.FacedGrid - """ - # first find columns with prefix space_column_name - space_entries = list( - filter(lambda col: col.startswith(space_column_name), data.columns) - ) - number_of_space_entries = len(space_entries) - y_label_name = space_column_name - - if number_of_space_entries > 1: - # if we have more than one space dims we reshape the dataframe in order to be able to control the plots behavior - # per dimension - data = pd.wide_to_long( - data, - stubnames=[space_column_name], - sep="_", - i=["episode", "step", "instance"] - + (["seed"] if "seed" in data.columns else []), - j="i", - suffix=".*", - ).reset_index() - elif number_of_space_entries == 1 and space_column_name not in data.columns: - # Of there is only one dimension but the name is odd - space_column_name, *_ = space_entries - - data, plot_index, x_column, x_label_columns = generate_global_step(data) - - # perform averaging over intervals - if interval > 1: - data["interval"] = data[x_column] // interval - group_columns = list( - data.columns.drop(x_label_columns + [x_column, space_column_name]) - ) - data = data.groupby(group_columns).agg( - {x_column: "min", space_column_name: "mean"} - ) - y_label = ( - f"Mean {y_label_name} per {interval} steps" if y_label is None else y_label - ) - data = data.reset_index() - - settings = { - "data": data, - "x": x_column, - "y": space_column_name, - "kind": "line", - } - - # we want the different dims in different plots / columns - # todo: refactor - if number_of_space_entries > 1: - settings["col"] = "i" - if number_of_space_entries > 3: - settings["col_wrap"] = 3 - - if "instance" in data.columns: - settings["hue"] = "instance" - - if x_label is None: - x_label = None if show_global_step else "Epoch:Step" - - if y_label is None: - y_label = y_label_name - - grid = plot(sns.relplot, settings, title, x_label, y_label, **args) - if not show_global_step: - add_multi_level_ticks(grid, plot_index, x_column, x_label_columns) - - return grid diff --git a/build/lib/dacbench/run_baselines.py b/build/lib/dacbench/run_baselines.py deleted file mode 100644 index 2e598eabb..000000000 --- a/build/lib/dacbench/run_baselines.py +++ /dev/null @@ -1,248 +0,0 @@ -import argparse -import itertools -import sys -from pathlib import Path - -import numpy as np - -from dacbench import benchmarks -from dacbench.agents import StaticAgent, GenericAgent, DynamicRandomAgent -from dacbench.envs.policies import OPTIMAL_POLICIES, NON_OPTIMAL_POLICIES -from dacbench.logger import Logger -from dacbench.runner import run_benchmark -from dacbench.wrappers import PerformanceTrackingWrapper - -modea_actions = [ - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(2), - np.arange(3), - np.arange(3), -] -DISCRETE_ACTIONS = { - "SigmoidBenchmark": np.arange(int(np.prod((5, 10)))), - "LubyBenchmark": np.arange(6), - "FastDownwardBenchmark": [0, 1], - "CMAESBenchmark": [np.around(a, decimals=1) for a in np.linspace(0.2, 10, num=50)], - "ModeaBenchmark": list(itertools.product(*modea_actions)), - "SGDBenchmark": [np.around(a, decimals=1) for a in np.linspace(0, 10, num=50)], -} - - -def run_random(results_path, benchmark_name, num_episodes, seeds, fixed): - bench = getattr(benchmarks, benchmark_name)() - for s in seeds: - if fixed > 1: - experiment_name = f"random_fixed{fixed}_{s}" - else: - experiment_name = f"random_{s}" - logger = Logger( - experiment_name=experiment_name, output_path=results_path / benchmark_name - ) - env = bench.get_benchmark(seed=s) - env = PerformanceTrackingWrapper( - env, logger=logger.add_module(PerformanceTrackingWrapper) - ) - agent = DynamicRandomAgent(env, fixed) - - logger.add_agent(agent) - logger.add_benchmark(bench) - logger.set_env(env) - - run_benchmark(env, agent, num_episodes, logger) - - logger.close() - - -def run_static(results_path, benchmark_name, action, num_episodes, seeds=np.arange(10)): - bench = getattr(benchmarks, benchmark_name)() - for s in seeds: - logger = Logger( - experiment_name=f"static_{action}_{s}", - output_path=results_path / benchmark_name, - ) - env = bench.get_benchmark(seed=s) - env = PerformanceTrackingWrapper( - env, logger=logger.add_module(PerformanceTrackingWrapper) - ) - agent = StaticAgent(env, action) - - logger.add_agent(agent) - logger.add_benchmark(bench) - logger.set_env(env) - logger.set_additional_info(action=action) - - run_benchmark(env, agent, num_episodes, logger) - - logger.close() - - -def run_optimal(results_path, benchmark_name, num_episodes, seeds): - if benchmark_name not in OPTIMAL_POLICIES: - print("No optimal policy found for this benchmark") - return - policy = OPTIMAL_POLICIES[benchmark_name] - run_policy(results_path, benchmark_name, num_episodes, policy, seeds) - - -def run_dynamic_policy(results_path, benchmark_name, num_episodes, seeds=np.arange(10)): - if benchmark_name not in NON_OPTIMAL_POLICIES: - print("No dynamic policy found for this benchmark") - policy = NON_OPTIMAL_POLICIES[benchmark_name] - run_policy(results_path, benchmark_name, num_episodes, policy, seeds) - - -def run_policy(results_path, benchmark_name, num_episodes, policy, seeds=np.arange(10)): - bench = getattr(benchmarks, benchmark_name)() - - for s in seeds: - if benchmark_name == "CMAESBenchmark": - experiment_name = f"csa_{s}" - else: - experiment_name = f"optimal_{s}" - logger = Logger( - experiment_name=experiment_name, output_path=results_path / benchmark_name - ) - - env = bench.get_benchmark(seed=s) - env = PerformanceTrackingWrapper( - env, logger=logger.add_module(PerformanceTrackingWrapper) - ) - agent = GenericAgent(env, policy) - - logger.add_agent(agent) - logger.add_benchmark(bench) - logger.set_env(env) - - run_benchmark(env, agent, num_episodes, logger) - - logger.close() - - -def main(args): - parser = argparse.ArgumentParser( - description="Run simple baselines for DAC benchmarks", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument("--outdir", type=str, default="output", help="Output directory") - parser.add_argument( - "--benchmarks", - nargs="+", - type=str, - choices=benchmarks.__all__, - default=None, - help="Benchmarks to run baselines for, if not provides all benchmarks are run.", - ) - parser.add_argument( - "--num_episodes", - type=int, - default=10, - help="Number of episodes to evaluate policy on", - ) - parser.add_argument( - "--random", - action="store_true", - help="Run random policy. Use '--fixed_random' to fix the " - "random action for a number of steps", - ) - parser.add_argument("--static", action="store_true", help="Run static policy") - - parser.add_argument( - "--optimal", - action="store_true", - help=f"Run optimal policy. Only available for {', '.join(OPTIMAL_POLICIES.keys())}", - ) - parser.add_argument( - "--dyna_baseline", - action="store_true", - help=f"Run dynamic baseline. Only available for {', '.join(NON_OPTIMAL_POLICIES.keys())}", - ) - - shortened_possible_actions = { - benchmark: ", ".join( - ( - map(str, actions) - if len(actions) < 4 - else map(str, [*actions[:3], "...", actions[-1]]) - ) - ) - for benchmark, actions in DISCRETE_ACTIONS.items() - } - - possible_actions = ", ".join( - [ - f"{benchmark} : {actions}" - for benchmark, actions in shortened_possible_actions.items() - ] - ) - parser.add_argument( - "--actions", - nargs="+", - type=float, - default=None, - help="Action(s) for static policy. Make sure, that the actions correspond to the benchmarks. Available action " - f"are {possible_actions}", - ) - parser.add_argument( - "--seeds", - nargs="+", - type=int, - default=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - help="Seeds for evaluation", - ) - parser.add_argument( - "--fixed_random", - type=int, - default=0, - help="Fixes random actions for n steps", - ) - args = parser.parse_args(args) - - if args.benchmarks is None: - benchs = benchmarks.__all__ - else: - benchs = args.benchmarks - - args.outdir = Path(args.outdir) - - if args.random: - for b in benchs: - run_random(args.outdir, b, args.num_episodes, args.seeds, args.fixed_random) - - if args.static: - for b in benchs: - - if args.actions is None: - actions = DISCRETE_ACTIONS[b] - else: - actions = args.actions - if b == "FastDownwardBenchmark": - actions = [int(a) for a in actions] - for a in actions: - run_static(args.outdir, b, a, args.num_episodes, args.seeds) - - if args.optimal: - for b in benchs: - if b not in OPTIMAL_POLICIES: - print("Option not available!") - break - - run_optimal(args.outdir, b, args.num_episodes, args.seeds) - - if args.dyna_baseline: - for b in benchs: - if b not in NON_OPTIMAL_POLICIES: - print("Option not available!") - break - - run_dynamic_policy(args.outdir, b, args.num_episodes, args.seeds) - - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/build/lib/dacbench/runner.py b/build/lib/dacbench/runner.py deleted file mode 100644 index 058d00d6b..000000000 --- a/build/lib/dacbench/runner.py +++ /dev/null @@ -1,94 +0,0 @@ -from dacbench import benchmarks -from dacbench.wrappers import PerformanceTrackingWrapper -from dacbench.logger import Logger -import seaborn as sb -from pathlib import Path - -sb.set_style("darkgrid") -current_palette = list(sb.color_palette()) - - -def run_benchmark(env, agent, num_episodes, logger=None): - """ - Run single benchmark env for a given number of episodes with a given agent - - Parameters - ------- - env : gym.Env - Benchmark environment - agent - Any agent implementing the methods act, train and end_episode (see AbstractDACBenchAgent below) - num_episodes : int - Number of episodes to run - logger : dacbench.logger.Logger: logger to use for logging. Not closed automatically like env - """ - if logger is not None: - logger.reset_episode() - logger.set_env(env) - - for _ in range(num_episodes): - state = env.reset() - done = False - reward = 0 - while not done: - action = agent.act(state, reward) - next_state, reward, done, _ = env.step(action) - agent.train(next_state, reward) - state = next_state - if logger is not None: - logger.next_step() - agent.end_episode(state, reward) - - if logger is not None: - logger.next_episode() - env.close() - - -def run_dacbench(results_path, agent_method, num_episodes, bench=None, seeds=None): - """ - Run all benchmarks for 10 seeds for a given number of episodes with a given agent and save result - - Parameters - ------- - bench - results_path : str - Path to where results should be saved - agent_method : function - Method that takes an env as input and returns an agent - num_episodes : int - Number of episodes to run for each benchmark - seeds : list[int] - List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. - """ - - if bench is None: - bench = map(benchmarks.__dict__.get, benchmarks.__all__) - else: - bench = [getattr(benchmarks, b) for b in bench] - - seeds = seeds if seeds is not None else range(10) - for b in bench: - print(f"Evaluating {b.__name__}") - for i in seeds: - print(f"Seed {i}/10") - bench = b() - try: - env = bench.get_benchmark(seed=i) - except: - continue - - logger = Logger( - experiment_name=f"seed_{i}", - output_path=Path(results_path) / f"{b.__name__}", - ) - perf_logger = logger.add_module(PerformanceTrackingWrapper) - logger.add_benchmark(bench) - logger.set_env(env) - - env = PerformanceTrackingWrapper(env, logger=perf_logger) - agent = agent_method(env) - logger.add_agent(agent) - - run_benchmark(env, agent, num_episodes, logger) - - logger.close() diff --git a/build/lib/dacbench/wrappers/__init__.py b/build/lib/dacbench/wrappers/__init__.py deleted file mode 100644 index 34d37d966..000000000 --- a/build/lib/dacbench/wrappers/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from dacbench.wrappers.action_tracking_wrapper import ActionFrequencyWrapper -from dacbench.wrappers.episode_time_tracker import EpisodeTimeWrapper -from dacbench.wrappers.instance_sampling_wrapper import InstanceSamplingWrapper -from dacbench.wrappers.policy_progress_wrapper import PolicyProgressWrapper -from dacbench.wrappers.reward_noise_wrapper import RewardNoiseWrapper -from dacbench.wrappers.state_tracking_wrapper import StateTrackingWrapper -from dacbench.wrappers.performance_tracking_wrapper import PerformanceTrackingWrapper -from dacbench.wrappers.observation_wrapper import ObservationWrapper - -__all__ = [ - "ActionFrequencyWrapper", - "EpisodeTimeWrapper", - "InstanceSamplingWrapper", - "PolicyProgressWrapper", - "RewardNoiseWrapper", - "StateTrackingWrapper", - "PerformanceTrackingWrapper", - "PolicyProgressWrapper", - "ObservationWrapper", -] diff --git a/build/lib/dacbench/wrappers/action_tracking_wrapper.py b/build/lib/dacbench/wrappers/action_tracking_wrapper.py deleted file mode 100644 index 9963a58d0..000000000 --- a/build/lib/dacbench/wrappers/action_tracking_wrapper.py +++ /dev/null @@ -1,259 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -import seaborn as sb -from gymnasium import Wrapper -from gymnasium import spaces -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas - -sb.set_style("darkgrid") -current_palette = list(sb.color_palette()) - - -class ActionFrequencyWrapper(Wrapper): - """ - Wrapper to action frequency. - Includes interval mode that returns frequencies in lists of len(interval) instead of one long list. - """ - - def __init__(self, env, action_interval=None, logger=None): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - action_interval : int - If not none, mean in given intervals is tracked, too - logger: logger.ModuleLogger - """ - super(ActionFrequencyWrapper, self).__init__(env) - self.action_interval = action_interval - self.overall_actions = [] - if self.action_interval: - self.action_intervals = [] - self.current_actions = [] - self.action_space_type = type(self.env.action_space) - self.logger = logger - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in [ - "action_interval", - "overall_actions", - "action_intervals", - "current_actions", - "env", - "get_actions", - "step", - "render_action_tracking", - "logger", - ]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in [ - "action_interval", - "overall_actions", - "action_intervals", - "current_actions", - "env", - "get_actions", - "step", - "render_action_tracking", - "logger", - ]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and record state - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - self.overall_actions.append(action) - if self.logger is not None: - self.logger.log_space("action", action) - - if self.action_interval: - if len(self.current_actions) < self.action_interval: - self.current_actions.append(action) - else: - self.action_intervals.append(self.current_actions) - self.current_actions = [action] - return state, reward, terminated, truncated, info - - def get_actions(self): - """ - Get state progression - - Returns - ------- - np.array or np.array, np.array - all states or all states and interval sorted states - - """ - if self.action_interval: - complete_intervals = self.action_intervals + [self.current_actions] - return self.overall_actions, complete_intervals - - else: - return self.overall_actions - - def render_action_tracking(self): - """ - Render action progression - - Returns - ------- - np.array - RBG data of action tracking - - """ - - def plot_single(ax=None, index=None, title=None, x=False, y=False): - if ax is None: - plt.xlabel("Step") - plt.ylabel("Action value") - elif x and y: - ax.set_ylabel("Action value") - ax.set_xlabel("Step") - elif x: - ax.set_xlabel("Step") - elif y: - ax.set_ylabel("Action value") - - if index is not None: - ys = [state[index] for state in self.overall_actions] - else: - ys = self.overall_actions - - if ax is None: - p = plt.plot( - np.arange(len(self.overall_actions)), - ys, - label="Step actions", - color="g", - ) - else: - p = ax.plot( - np.arange(len(self.overall_actions)), - ys, - label="Step actions", - color="g", - ) - p2 = None - if self.action_interval: - if index is not None: - y_ints = [] - for interval in self.action_intervals: - y_ints.append([state[index] for state in interval]) - else: - y_ints = self.action_intervals - if ax is None: - p2 = plt.plot( - np.arange(len(self.action_intervals)) * self.action_interval, - [np.mean(interval) for interval in y_ints], - label="Mean interval action", - color="orange", - ) - plt.legend(loc="upper left") - else: - p2 = ax.plot( - np.arange(len(self.action_intervals)) * self.action_interval, - [np.mean(interval) for interval in y_ints], - label="Mean interval action", - color="orange", - ) - ax.legend(loc="upper left") - return p, p2 - - if self.action_space_type == spaces.Discrete: - figure = plt.figure(figsize=(12, 6)) - canvas = FigureCanvas(figure) - p, p2 = plot_single() - canvas.draw() - elif self.action_space_type == spaces.Dict: - raise NotImplementedError - - elif self.action_space_type == spaces.Tuple: - raise NotImplementedError - - elif ( - self.action_space_type == spaces.MultiDiscrete - or self.action_space_type == spaces.MultiBinary - or self.action_space_type == spaces.Box - ): - if self.action_space_type == spaces.MultiDiscrete: - action_size = len(self.env.action_space.nvec) - elif self.action_space_type == spaces.MultiBinary: - action_size = self.env.action_space.n - else: - action_size = len(self.env.action_space.high) - - if action_size == 1: - figure = plt.figure(figsize=(12, 6)) - canvas = FigureCanvas(figure) - p, p2 = plot_single() - elif action_size < 5: - dim = 1 - figure, axarr = plt.subplots(action_size) - else: - dim = action_size % 4 - figure, axarr = plt.subplots(action_size % 4, action_size // dim) - figure.suptitle("State over time") - canvas = FigureCanvas(figure) - for i in range(action_size): - if action_size == 1: - continue - - x = False - if i % dim == dim - 1: - x = True - if action_size < 5: - p, p2 = plot_single(axarr[i], i, y=True, x=x) - else: - y = i % action_size // dim == 0 - p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) - canvas.draw() - width, height = figure.get_size_inches() * figure.get_dpi() - img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( - int(height), int(width), 3 - ) - return img diff --git a/build/lib/dacbench/wrappers/episode_time_tracker.py b/build/lib/dacbench/wrappers/episode_time_tracker.py deleted file mode 100644 index bab927cee..000000000 --- a/build/lib/dacbench/wrappers/episode_time_tracker.py +++ /dev/null @@ -1,243 +0,0 @@ -from gymnasium import Wrapper -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas -import time -import seaborn as sb - -sb.set_style("darkgrid") -current_palette = list(sb.color_palette()) - - -class EpisodeTimeWrapper(Wrapper): - """ - Wrapper to track time spent per episode. - Includes interval mode that returns times in lists of len(interval) instead of one long list. - """ - - def __init__(self, env, time_interval=None, logger=None): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - time_interval : int - If not none, mean in given intervals is tracked, too - logger : dacbench.logger.ModuleLogger - """ - super(EpisodeTimeWrapper, self).__init__(env) - self.time_interval = time_interval - self.all_steps = [] - if self.time_interval: - self.step_intervals = [] - self.current_step_interval = [] - self.overall_times = [] - self.episode = [] - if self.time_interval: - self.time_intervals = [] - self.current_times = [] - - self.logger = logger - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in [ - "time_interval", - "overall_times", - "time_intervals", - "current_times", - "env", - "get_times", - "step", - "render_step_time", - "render_episode_time", - "reset", - "episode", - "all_steps", - "current_step_interval", - "step_intervals", - "logger", - ]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in [ - "time_interval", - "overall_times", - "time_intervals", - "current_times", - "env", - "get_times", - "step", - "render_step_time", - "render_episode_time", - "reset", - "episode", - "all_steps", - "current_step_interval", - "step_intervals", - "logger", - ]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and record time - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, metainfo - """ - start = time.time() - state, reward, terminated, truncated, info = self.env.step(action) - stop = time.time() - duration = stop - start - self.episode.append(duration) - self.all_steps.append(duration) - - if self.logger is not None: - self.logger.log("step_duration", duration) - - if self.time_interval: - if len(self.current_step_interval) < self.time_interval: - self.current_step_interval.append(duration) - else: - self.step_intervals.append(self.current_step_interval) - self.current_step_interval = [duration] - if terminated or truncated: - self.overall_times.append(self.episode) - if self.logger is not None: - self.logger.log("episode_duration", sum(self.episode)) - - if self.time_interval: - if len(self.current_times) < self.time_interval: - self.current_times.append(self.episode) - else: - self.time_intervals.append(self.current_times) - self.current_times = [] - self.episode = [] - return state, reward, terminated, truncated, info - - def get_times(self): - """ - Get times - - Returns - ------- - np.array or np.array, np.array - all times or all times and interval sorted times - - """ - if self.time_interval: - complete_intervals = self.time_intervals + [self.current_times] - complete_step_intervals = self.step_intervals + [self.current_step_interval] - return ( - self.overall_times, - self.all_steps, - complete_intervals, - complete_step_intervals, - ) - - else: - return np.array(self.overall_times), np.array(self.all_steps) - - def render_step_time(self): - """Render step times""" - figure = plt.figure(figsize=(12, 6)) - canvas = FigureCanvas(figure) - plt.title("Time per Step") - plt.xlabel("Step") - plt.ylabel("Time (s)") - - plt.plot( - np.arange(len(self.all_steps)), self.all_steps, label="Step time", color="g" - ) - if self.time_interval: - interval_means = [np.mean(interval) for interval in self.step_intervals] + [ - np.mean(self.current_step_interval) - ] - plt.plot( - np.arange(len(self.step_intervals) + 2) * self.time_interval, - [interval_means[0]] + interval_means, - label="Mean interval time", - color="orange", - ) - plt.legend(loc="upper right") - canvas.draw() - width, height = figure.get_size_inches() * figure.get_dpi() - img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( - int(height), int(width), 3 - ) - # plt.close(figure) - return img - - def render_episode_time(self): - """Render episode times""" - figure = plt.figure(figsize=(12, 6)) - canvas = FigureCanvas(figure) - plt.title("Time per Episode") - plt.xlabel("Episode") - plt.ylabel("Time (s)") - - plt.plot( - np.arange(len(self.overall_times)), - [sum(episode) for episode in self.overall_times], - label="Episode time", - color="g", - ) - if self.time_interval: - interval_sums = [] - for interval in self.time_intervals: - ep_times = [] - for episode in interval: - ep_times.append(sum(episode)) - interval_sums.append(np.mean(ep_times)) - interval_sums += [np.mean([sum(episode) for episode in self.current_times])] - plt.plot( - np.arange(len(self.time_intervals) + 2) * self.time_interval, - [interval_sums[0]] + interval_sums, - label="Mean interval time", - color="orange", - ) - plt.legend(loc="upper right") - canvas.draw() - width, height = figure.get_size_inches() * figure.get_dpi() - img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( - int(height), int(width), 3 - ) - return img diff --git a/build/lib/dacbench/wrappers/instance_sampling_wrapper.py b/build/lib/dacbench/wrappers/instance_sampling_wrapper.py deleted file mode 100644 index 72a66f707..000000000 --- a/build/lib/dacbench/wrappers/instance_sampling_wrapper.py +++ /dev/null @@ -1,112 +0,0 @@ -from gym import Wrapper -import numpy as np -from scipy.stats import norm - - -class InstanceSamplingWrapper(Wrapper): - """ - Wrapper to sample a new instance at a given time point. - Instances can either be sampled using a given method or a distribution infered from a given list of instances. - """ - - def __init__(self, env, sampling_function=None, instances=None, reset_interval=0): - """ - Initialize wrapper - Either sampling_function or instances must be given - - Parameters - ------- - env : gym.Env - Environment to wrap - sampling_function : function - Function to sample instances from - instances : list - List of instances to infer distribution from - """ - super(InstanceSamplingWrapper, self).__init__(env) - if sampling_function: - self.sampling_function = sampling_function - elif instances: - self.sampling_function = self.fit_dist(instances) - else: - raise Exception("No distribution to sample from given") - self.reset_interval = reset_interval - self.reset_tracker = 0 - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in ["sampling_function", "env", "fit_dist", "reset"]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in ["sampling_function", "env", "fit_dist", "reset"]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def reset(self): - """ - Reset environment and use sampled instance for training - - Returns - ------- - np.array - state - """ - if self.reset_tracker >= self.reset_interval: - instance = self.sampling_function() - self.env.use_next_instance(instance=instance) - return self.env.reset() - - def fit_dist(self, instances): - """ - Approximate instance distribution in given instance set - - Parameters - ---------- - instances : List - instance set - - Returns - --------- - method - sampling method for new instances - """ - dists = [] - for i in range(len(instances[0])): - component = [instances[k][i] for k in instances.keys()] - dist = norm.fit(component) - dists.append(dist) - - def sample(): - instance = [] - for d in dists: - instance.append(np.random.normal(d[0], d[1])) - return instance - - return sample diff --git a/build/lib/dacbench/wrappers/observation_wrapper.py b/build/lib/dacbench/wrappers/observation_wrapper.py deleted file mode 100644 index 57d8e27fe..000000000 --- a/build/lib/dacbench/wrappers/observation_wrapper.py +++ /dev/null @@ -1,106 +0,0 @@ -from collections.abc import Iterable - -from gym import Wrapper, spaces -import numpy as np - - -class ObservationWrapper(Wrapper): - """ - Wrapper covert observations spaces to spaces.Box for convenience - Currently only supports Dict -> Box - """ - - def __init__(self, env): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - compute_optimal : function - Function to compute optimal policy - """ - super(ObservationWrapper, self).__init__(env) - obs_sample = self.flatten(self.env.observation_space.sample()) - size = len(obs_sample) - self.observation_space = spaces.Box( - low=-np.inf * np.ones(size), high=np.inf * np.ones(size) - ) - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in ["observation_space", "step", "env", "flatten", "reset"]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in ["observation_space", "step", "env", "flatten", "reset"]: - return object.__getattribute__(self, name) - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and record distance - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - state = self.flatten(state) - return state, reward, terminated, truncated, info - - def reset(self): - """ - Execute environment step and record distance - - Returns - ------- - np.array, dict - state, info - """ - state, info = self.env.reset() - state = self.flatten(state) - return state, info - - def flatten(self, state_dict): - keys = sorted(list(state_dict.keys())) - values = [] - for k in keys: - if isinstance(state_dict[k], np.ndarray): - for s in state_dict[k]: - values.append(s) - else: - values.append(state_dict[k]) - return np.array(values).astype(np.float32) diff --git a/build/lib/dacbench/wrappers/performance_tracking_wrapper.py b/build/lib/dacbench/wrappers/performance_tracking_wrapper.py deleted file mode 100644 index 187e22e85..000000000 --- a/build/lib/dacbench/wrappers/performance_tracking_wrapper.py +++ /dev/null @@ -1,204 +0,0 @@ -from collections import defaultdict - -from gym import Wrapper -import matplotlib.pyplot as plt -import numpy as np -import seaborn as sb - -sb.set_style("darkgrid") -current_palette = list(sb.color_palette()) - - -class PerformanceTrackingWrapper(Wrapper): - """ - Wrapper to track episode performance. - Includes interval mode that returns performance in lists of len(interval) instead of one long list. - """ - - def __init__( - self, - env, - performance_interval=None, - track_instance_performance=True, - logger=None, - ): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - performance_interval : int - If not none, mean in given intervals is tracked, too - track_instance_performance : bool - Indicates whether to track per-instance performance - logger : dacbench.logger.ModuleLogger - """ - super(PerformanceTrackingWrapper, self).__init__(env) - self.performance_interval = performance_interval - self.overall_performance = [] - self.episode_performance = 0 - if self.performance_interval: - self.performance_intervals = [] - self.current_performance = [] - self.track_instances = track_instance_performance - if self.track_instances: - self.instance_performances = defaultdict(lambda: []) - - self.logger = logger - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in [ - "performance_interval", - "track_instances", - "overall_performance", - "performance_intervals", - "current_performance", - "env", - "get_performance", - "step", - "instance_performances", - "episode_performance", - "render_performance", - "render_instance_performance", - "logger", - ]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in [ - "performance_interval", - "track_instances", - "overall_performance", - "performance_intervals", - "current_performance", - "env", - "get_performance", - "step", - "instance_performances", - "episode_performance", - "render_performance", - "render_instance_performance", - "logger", - ]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and record performance - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - self.episode_performance += reward - - if terminated or truncated: - self.overall_performance.append(self.episode_performance) - if self.logger is not None: - self.logger.log( - "overall_performance", - self.episode_performance, - ) - - if self.performance_interval: - if len(self.current_performance) < self.performance_interval: - self.current_performance.append(self.episode_performance) - else: - self.performance_intervals.append(self.current_performance) - self.current_performance = [self.episode_performance] - if self.track_instances: - key = "".join(str(e) for e in self.env.instance) - self.instance_performances[key].append(self.episode_performance) - self.episode_performance = 0 - return state, reward, terminated, truncated, info - - def get_performance(self): - """ - Get state performance - - Returns - ------- - np.array or np.array, np.array or np.array, dict or np.array, np.arry, dict - all states or all states and interval sorted states - - """ - if self.performance_interval and self.track_instances: - complete_intervals = self.performance_intervals + [self.current_performance] - return ( - self.overall_performance, - complete_intervals, - self.instance_performances, - ) - - elif self.performance_interval: - complete_intervals = self.performance_intervals + [self.current_performance] - return self.overall_performance, complete_intervals - - elif self.track_instances: - return self.overall_performance, self.instance_performances - - else: - return self.overall_performance - - def render_performance(self): - """ Plot performance """ - plt.figure(figsize=(12, 6)) - plt.plot( - np.arange(len(self.overall_performance) // 2), - self.overall_performance[1::2], - ) - plt.title("Mean Performance per episode") - plt.xlabel("Episode") - plt.ylabel("Reward") - plt.show() - - def render_instance_performance(self): - """ Plot mean performance for each instance """ - plt.figure(figsize=(12, 6)) - plt.title("Mean Performance per Instance") - plt.ylabel("Mean reward") - plt.xlabel("Instance") - ax = plt.subplot(111) - for k, i in zip( - self.instance_performances.keys(), - np.arange(len(self.instance_performances.keys())), - ): - ax.bar(str(i), np.mean(self.instance_performances[k])) - plt.show() diff --git a/build/lib/dacbench/wrappers/policy_progress_wrapper.py b/build/lib/dacbench/wrappers/policy_progress_wrapper.py deleted file mode 100644 index e8fcb6773..000000000 --- a/build/lib/dacbench/wrappers/policy_progress_wrapper.py +++ /dev/null @@ -1,107 +0,0 @@ -from gym import Wrapper -import matplotlib.pyplot as plt -import numpy as np - - -class PolicyProgressWrapper(Wrapper): - """ - Wrapper to track progress towards optimal policy. - Can only be used if a way to obtain the optimal policy given an instance can be obtained - """ - - def __init__(self, env, compute_optimal): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - compute_optimal : function - Function to compute optimal policy - """ - super(PolicyProgressWrapper, self).__init__(env) - self.compute_optimal = compute_optimal - self.episode = [] - self.policy_progress = [] - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in [ - "compute_optimal", - "env", - "episode", - "policy_progress", - "render_policy_progress", - ]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in [ - "step", - "compute_optimal", - "env", - "episode", - "policy_progress", - "render_policy_progress", - ]: - return object.__getattribute__(self, name) - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and record distance - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - self.episode.append(action) - if terminated or truncated: - optimal = self.compute_optimal(self.env.instance) - self.policy_progress.append( - np.linalg.norm(np.array(optimal) - np.array(self.episode)) - ) - self.episode = [] - return state, reward,terminated, truncated, info - - def render_policy_progress(self): - """ Plot progress """ - plt.figure(figsize=(12, 6)) - plt.plot(np.arange(len(self.policy_progress)), self.policy_progress) - plt.title("Policy progress over time") - plt.xlabel("Episode") - plt.ylabel("Distance to optimal policy") - plt.show() diff --git a/build/lib/dacbench/wrappers/reward_noise_wrapper.py b/build/lib/dacbench/wrappers/reward_noise_wrapper.py deleted file mode 100644 index 779482800..000000000 --- a/build/lib/dacbench/wrappers/reward_noise_wrapper.py +++ /dev/null @@ -1,119 +0,0 @@ -from gym import Wrapper -import numpy as np - - -class RewardNoiseWrapper(Wrapper): - """ - Wrapper to add noise to the reward signal. - Noise can be sampled from a custom distribution or any distribution in numpy's random module - """ - - def __init__( - self, env, noise_function=None, noise_dist="standard_normal", dist_args=None - ): - """ - Initialize wrapper - Either noise_function or noise_dist and dist_args need to be given - - Parameters - ------- - env : gym.Env - Environment to wrap - noise_function : function - Function to sample noise from - noise_dist : str - Name of distribution to sample noise from - dist_args : list - Arguments for noise distribution - """ - super(RewardNoiseWrapper, self).__init__(env) - - if noise_function: - self.noise_function = noise_function - elif noise_dist: - self.noise_function = self.add_noise(noise_dist, dist_args) - else: - raise Exception("No distribution to sample noise from given") - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in ["noise_function", "env", "add_noise", "step"]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in ["noise_function", "env", "add_noise", "step"]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def step(self, action): - """ - Execute environment step and add noise - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, bool, dict - state, reward, terminated, truncated, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - reward += self.noise_function() - reward = max(self.env.reward_range[0], min(self.env.reward_range[1], reward)) - return state, reward, terminated, truncated, info - - def add_noise(self, dist, args): - """ - Make noise function from distribution name and arguments - - Parameters - ---------- - dist : str - Name of distribution - args : list - List of distribution arguments - - Returns - ------- - function - Noise sampling function - """ - rng = np.random.default_rng() - function = getattr(rng, dist) - - def sample_noise(): - if args: - return function(*args) - - else: - return function() - - return sample_noise diff --git a/build/lib/dacbench/wrappers/state_tracking_wrapper.py b/build/lib/dacbench/wrappers/state_tracking_wrapper.py deleted file mode 100644 index 31199c83f..000000000 --- a/build/lib/dacbench/wrappers/state_tracking_wrapper.py +++ /dev/null @@ -1,289 +0,0 @@ -from gymnasium import spaces -from gymnasium import Wrapper -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas -import seaborn as sb - -sb.set_style("darkgrid") -current_palette = list(sb.color_palette()) - - -class StateTrackingWrapper(Wrapper): - """ - Wrapper to track state changed over time - Includes interval mode that returns states in lists of len(interval) instead of one long list. - """ - - def __init__(self, env, state_interval=None, logger=None): - """ - Initialize wrapper - - Parameters - ------- - env : gym.Env - Environment to wrap - state_interval : int - If not none, mean in given intervals is tracked, too - logger : dacbench.logger.ModuleLogger - """ - super(StateTrackingWrapper, self).__init__(env) - self.state_interval = state_interval - self.overall_states = [] - if self.state_interval: - self.state_intervals = [] - self.current_states = [] - self.episode_states = None - self.state_type = type(env.observation_space) - self.logger = logger - if self.logger is not None: - benchmark_info = getattr(env, "benchmark_info", None) - self.state_description = ( - benchmark_info.get("state_description", None) - if benchmark_info is not None - else None - ) - - def __setattr__(self, name, value): - """ - Set attribute in wrapper if available and in env if not - - Parameters - ---------- - name : str - Attribute to set - value - Value to set attribute to - """ - if name in [ - "state_interval", - "overall_states", - "state_intervals", - "current_states", - "state_type", - "env", - "episode_states", - "get_states", - "step", - "reset", - "render_state_tracking", - "logger", - ]: - object.__setattr__(self, name, value) - else: - setattr(self.env, name, value) - - def __getattribute__(self, name): - """ - Get attribute value of wrapper if available and of env if not - - Parameters - ---------- - name : str - Attribute to get - - Returns - ------- - value - Value of given name - """ - if name in [ - "state_interval", - "overall_states", - "state_intervals", - "current_states", - "state_type", - "env", - "episode_states", - "get_states", - "step", - "reset", - "render_state_tracking", - "logger", - ]: - return object.__getattribute__(self, name) - - else: - return getattr(self.env, name) - - def reset(self): - """ - Reset environment and record starting state - - Returns - ------- - np.array, {} - state, info - """ - state, info = self.env.reset() - self.overall_states.append(state) - if self.state_interval: - if len(self.current_states) < self.state_interval: - self.current_states.append(state) - else: - self.state_intervals.append(self.current_states) - self.current_states = [state] - return state, info - - def step(self, action): - """ - Execute environment step and record state - - Parameters - ---------- - action : int - action to execute - - Returns - ------- - np.array, float, bool, dict - state, reward, done, metainfo - """ - state, reward, terminated, truncated, info = self.env.step(action) - self.overall_states.append(state) - if self.logger is not None: - self.logger.log_space("state", state, self.state_description) - if self.state_interval: - if len(self.current_states) < self.state_interval: - self.current_states.append(state) - else: - self.state_intervals.append(self.current_states) - self.current_states = [state] - return state, reward, terminated, truncated, info - - def get_states(self): - """ - Get state progression - - Returns - ------- - np.array or np.array, np.array - all states or all states and interval sorted states - - """ - if self.state_interval: - complete_intervals = self.state_intervals + [self.current_states] - return self.overall_states, complete_intervals - - else: - return self.overall_states - - def render_state_tracking(self): - """ - Render state progression - - Returns - ------- - np.array - RBG data of state tracking - """ - - def plot_single(ax=None, index=None, title=None, x=False, y=False): - if ax is None: - plt.xlabel("Episode") - plt.ylabel("State") - elif x and y: - ax.set_ylabel("State") - ax.set_xlabel("Episode") - elif x: - ax.set_xlabel("Episode") - elif y: - ax.set_ylabel("State") - - if index is not None: - ys = [state[index] for state in self.overall_states] - else: - ys = self.overall_states - - if ax is None: - p = plt.plot( - np.arange(len(self.overall_states)), - ys, - label="Episode state", - color="g", - ) - else: - p = ax.plot( - np.arange(len(self.overall_states)), - ys, - label="Episode state", - color="g", - ) - p2 = None - if self.state_interval: - if index is not None: - y_ints = [] - for interval in self.state_intervals: - y_ints.append([state[index] for state in interval]) - else: - y_ints = self.state_intervals - if ax is None: - p2 = plt.plot( - np.arange(len(self.state_intervals)), - [np.mean(interval) for interval in y_ints], - label="Mean interval state", - color="orange", - ) - plt.legend(loc="upper left") - else: - p2 = ax.plot( - np.arange(len(self.state_intervals)) * self.state_interval, - [np.mean(interval) for interval in y_ints], - label="Mean interval state", - color="orange", - ) - ax.legend(loc="upper left") - return p, p2 - - if self.state_type == spaces.Discrete: - figure = plt.figure(figsize=(20, 20)) - canvas = FigureCanvas(figure) - p, p2 = plot_single() - canvas.draw() - elif self.state_type == spaces.Dict: - raise NotImplementedError - - elif self.state_type == spaces.Tuple: - raise NotImplementedError - - elif ( - self.state_type == spaces.MultiDiscrete - or self.state_type == spaces.MultiBinary - or self.state_type == spaces.Box - ): - if self.state_type == spaces.MultiDiscrete: - state_length = len(self.env.observation_space.nvec) - elif self.state_type == spaces.MultiBinary: - state_length = self.env.observation_space.n - else: - state_length = len(self.env.observation_space.high) - if state_length == 1: - figure = plt.figure(figsize=(20, 20)) - canvas = FigureCanvas(figure) - p, p2 = plot_single() - elif state_length < 5: - dim = 1 - figure, axarr = plt.subplots(state_length) - else: - dim = state_length % 4 - figure, axarr = plt.subplots(state_length % 4, state_length // dim) - figure.suptitle("State over time") - canvas = FigureCanvas(figure) - for i in range(state_length): - if state_length == 1: - continue - - x = False - if i % dim == dim - 1: - x = True - if state_length < 5: - p, p2 = plot_single(axarr[i], i, y=True, x=x) - else: - y = i % state_length // dim == 0 - p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) - canvas.draw() - width, height = figure.get_size_inches() * figure.get_dpi() - img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( - int(height), int(width), 3 - ) - return img From 7828c50608d84eef61df84baf62dc1d18f6974f4 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:37:31 +0100 Subject: [PATCH 06/44] Delete run_ppo.sh --- run_ppo.sh | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 run_ppo.sh diff --git a/run_ppo.sh b/run_ppo.sh deleted file mode 100644 index 752c7ecd7..000000000 --- a/run_ppo.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# -#SBATCH --partition=cpu_cluster -#SBATCH --job-name=dacbenchlines -#SBATCH --time=72:00:00 -#SBATCH --mem-per-cpu=8000M - -python train_ppo.py --outdir ppo_baselines --benchmarks $1 From 86ffc3f54383c695df3f4fdf1398f586058af913 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:37:52 +0100 Subject: [PATCH 07/44] Delete run.py --- run.py | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 run.py diff --git a/run.py b/run.py deleted file mode 100644 index e1f5149a3..000000000 --- a/run.py +++ /dev/null @@ -1,28 +0,0 @@ -from pathlib import Path - -from dacbench.agents import RandomAgent -from dacbench.logger import Logger -from dacbench.runner import run_benchmark -from dacbench.benchmarks.modcma_benchmark import ModCMABenchmark -from dacbench.wrappers import ActionFrequencyWrapper - - - -if __name__ == "__main__": - bench = ModCMABenchmark() - env = bench.get_environment() - - # Make logger object - logger = Logger( - experiment_name=type(bench).__name__, output_path=Path("../plotting/data") - ) - logger.set_env(env) - logger.add_benchmark(bench) - - # Wrap environment to track action frequency - env = ActionFrequencyWrapper(env, logger=logger.add_module(ActionFrequencyWrapper)) - - # Run random agent for 5 episodes and log actions to file - agent = RandomAgent(env) - run_benchmark(env, agent, 5, logger=logger) - \ No newline at end of file From 9524114d2d58f742ea50ff051af64a610665b5ed Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:38:13 +0100 Subject: [PATCH 08/44] Fix python version for docs --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a461c66ff..686486a6c 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,7 +10,7 @@ formats: all # Explicitly set the version of Python and its requirements python: - version: 3.6 + version: 3.10 install: - method: pip path: . From eda7247ede367d16449d23890c4a03ce32cb95ac Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:53:28 +0100 Subject: [PATCH 09/44] github workflows --- .github/workflows/docs.yml | 71 ++++++++++++++++++++++++++++++++ .github/workflows/pre_commit.yml | 43 +++++++++++++++++++ .github/workflows/pytest.yml | 24 +++++++++++ docs/Makefile | 42 ++++++++++++------- docs/conf.py | 56 ++++++++----------------- docs/make.bat | 35 ---------------- 6 files changed, 181 insertions(+), 90 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/pre_commit.yml create mode 100644 .github/workflows/pytest.yml delete mode 100644 docs/make.bat diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..45f6726d2 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,71 @@ +name: docs + +on: + # Manual trigger option in github + # This won't push to github pages where docs are hosted due + # to the gaurded if statement in those steps + workflow_dispatch: + + # Trigger on push to these branches + push: + branches: + - main + - gymnasium_migration + + # Trigger on a open/push to a PR targeting one of these branches + pull_request: + branches: + - main + +env: + name: DACBench + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install dependencies + id: install + run: | + pip install ".[dev,all,docs]" + + - name: Make docs + run: | + make clean + make docs + + - name: Pull latest gh-pages + if: (contains(github.ref, 'gymnasium_migration') || contains(github.ref, 'main')) && github.event_name == 'push' + run: | + cd .. + git clone https://github.com/${{ github.repository }}.git --branch gh-pages --single-branch gh-pages + + - name: Copy new docs into gh-pages + if: (contains(github.ref, 'gymnasium_migration') || contains(github.ref, 'main')) && github.event_name == 'push' + run: | + branch_name=${GITHUB_REF##*/} + cd ../gh-pages + rm -rf $branch_name + cp -r ../${{ env.name }}/docs/build/html $branch_name + + + - name: Push to gh-pages + if: (contains(github.ref, 'gymnasium_migration') || contains(github.ref, 'main')) && github.event_name == 'push' + run: | + last_commit=$(git log --pretty=format:"%an: %s") + cd ../gh-pages + branch_name=${GITHUB_REF##*/} + git add $branch_name/ + git config --global user.name 'Github Actions' + git config --global user.email 'not@mail.com' + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + git commit -am "$last_commit" + git push diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml new file mode 100644 index 000000000..7d78d63b7 --- /dev/null +++ b/.github/workflows/pre_commit.yml @@ -0,0 +1,43 @@ +name: pre-commit + +on: + # Manually triggerable in github + workflow_dispatch: + + # When a push occurs on either of these branches + push: + branches-ignore: + - '**' + # branches: + # - main + # - development + + # When a push occurs on a PR that targets these branches + pull_request: + branches-ignore: + - '**' + # branches: + # - main + # - development + +jobs: + run-all-files: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Setup Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: 3.10 + + - name: Install pre-commit + run: | + pip install pre-commit + pre-commit install + - name: Run pre-commit + run: | + pre-commit run --all-files diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 000000000..6d8a55f30 --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,24 @@ +name: tests +on: [ push ] +jobs: + pytest: + name: PyTest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Add conda to system path + run: | + # $CONDA is an environment variable pointing to the root of the miniconda directory + echo $CONDA/bin >> $GITHUB_PATH + + - name: Setup Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: 3.10 + + - name: Install dependencies + run: | + make install-dev + + - name: Run pytest + run: pytest tests diff --git a/docs/Makefile b/docs/Makefile index d4bb2cbb9..d0d8f6e2b 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,20 +1,30 @@ -# Minimal makefile for Sphinx documentation -# +SPHINXBUILD = sphinx-build +BUILDDIR = build +SPHINXOPTS = +ALLSPHINXOPTS = $(SPHINXOPTS) . -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build +.PHONY: clean buildapi linkcheck html docs html-noexamples -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +clean: + rm -rf $(BUILDDIR)/* + rm -rf api + rm -rf examples -.PHONY: help Makefile +linkcheck: + SPHINX_GALLERY_PLOT=False $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +html-noexamples: + SPHINX_GALLERY_PLOT=False $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +docs: html linkcheck -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 0e183b88e..d8c5d1045 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,6 +10,8 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # +import automl_sphinx_theme +from dacbench import __version__ as version import os import sys @@ -17,48 +19,24 @@ # -- Project information ----------------------------------------------------- -project = "DACBench" +name = "DACBench" copyright = "2021, Theresa Eimer, Maximilian Reimer" author = "Theresa Eimer, Maximilian Reimer" # The full version, including alpha/beta/rc tags release = "01.02.2021" - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - "sphinx_rtd_theme", - "sphinx.ext.autodoc", - "sphinx.ext.coverage", - "sphinxcontrib.napoleon", - "autoapi.extension", -] -napoleon_google_docstring = False - -autoapi_dirs = ["../dacbench"] -autoapi_ignore = ["*/rl-plan*"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "sphinx_rtd_theme" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +options = { + "copyright": copyright, + "author": author, + "version": version, + "versions": { + f"v{version}": "#", + }, + "name": name, + "html_theme_options": { + "github_url": "https://github.com/automl/DACBench", + "twitter_url": "https://twitter.com/automl_org?lang=de", + }, +} +automl_sphinx_theme.set_options(globals(), options) \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 2119f5109..000000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd From aefb5f01aa9c674640e74958f3a06d79cc0821ae Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:55:41 +0100 Subject: [PATCH 10/44] updated dependencies --- setup.cfg | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/setup.cfg b/setup.cfg index 3d2d91722..1713f6643 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,17 +61,7 @@ example = stable-baselines3 jupyter docs = - sphinxcontrib-napoleon - sphinx-rtd-theme - sphinx-autoapi - docutils - cma==3.3.0 - modcma==0.0.2.8.4 - IOHexperimenter==0.2.9.2 - scikit-learn==1.2.2 - torchvision==0.14.1 - torch==1.13.1 - backpack-for-pytorch==1.5.2 + automl-sphinx-theme all= gymnasium==0.27.1 numpy==1.24.2 @@ -86,7 +76,7 @@ all= torch==1.13.1 backpack-for-pytorch==1.5.2 modcma==0.0.2.8.4 - IOHexperimenter==0.2.9.2 + IOHexperimenter==0.2.9 Pyro4==4.82 #Benchmarks From 09c53a70c742326599426b30db786ca3f5e721a8 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:57:47 +0100 Subject: [PATCH 11/44] consolidate tests --- .github/workflows/pytest.yml | 67 ++++++++++++++++++++------ .github/workflows/run-python-tests.yml | 59 ----------------------- 2 files changed, 51 insertions(+), 75 deletions(-) delete mode 100644 .github/workflows/run-python-tests.yml diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 6d8a55f30..2a4b45aad 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,24 +1,59 @@ name: tests -on: [ push ] +on: + push: + branches: + - main + - gymnasium_migration + pull_request: + branches: + - main + jobs: - pytest: - name: PyTest + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Add conda to system path - run: | - # $CONDA is an environment variable pointing to the root of the miniconda directory - echo $CONDA/bin >> $GITHUB_PATH - - - name: Setup Python 3.10 - uses: actions/setup-python@v2 with: - python-version: 3.10 - + submodules: recursive + - name: Cache MNIST + id: cache-mnist + uses: actions/cache@v2 + with: + path: ./data/MNIST + key: mnist + - name: Cache Fast-downward build + id: cache-fast-downward-build + uses: actions/cache@v2 + with: + path: ./dacbench/envs/rl-plan/fast-downward + key: fast-downward-build + - name: Install Python 3 + uses: actions/setup-python@v1 + with: + python-version: 3.1 - name: Install dependencies run: | - make install-dev - - - name: Run pytest - run: pytest tests + python -m pip install --upgrade pip + pip install -e.[dev,example,all] + - name: Build fast-downward + run: ./dacbench/envs/rl-plan/fast-downward/build.py + - name: Run tests with pytest + run: coverage run -m pytest --html=test-report.html + - name: Run coverage + run: | + coverage report + coverage html + - name: Archive code coverage results + uses: actions/upload-artifact@v2 + if: ${{ always() }} + with: + name: code-coverage-report + path: coverage_report + - name: Archive test report + uses: actions/upload-artifact@v2 + if: ${{ always() }} + with: + name: test-report + path: | + test-report.html + assets diff --git a/.github/workflows/run-python-tests.yml b/.github/workflows/run-python-tests.yml deleted file mode 100644 index c43e53d4a..000000000 --- a/.github/workflows/run-python-tests.yml +++ /dev/null @@ -1,59 +0,0 @@ - -name: Run Python Tests -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Cache MNIST - id: cache-mnist - uses: actions/cache@v2 - with: - path: ./data/MNIST - key: mnist - - name: Cache Fast-downward build - id: cache-fast-downward-build - uses: actions/cache@v2 - with: - path: ./dacbench/envs/rl-plan/fast-downward - key: fast-downward-build - - name: Install Python 3 - uses: actions/setup-python@v1 - with: - python-version: 3.6 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -e.[dev,example,all] - - name: Build fast-downward - run: ./dacbench/envs/rl-plan/fast-downward/build.py - - name: Run tests with pytest - run: coverage run -m pytest --html=test-report.html - - name: Run coverage - run: | - coverage report - coverage html - - name: Archive code coverage results - uses: actions/upload-artifact@v2 - if: ${{ always() }} - with: - name: code-coverage-report - path: coverage_report - - name: Archive test report - uses: actions/upload-artifact@v2 - if: ${{ always() }} - with: - name: test-report - path: | - test-report.html - assets From c6494b359fab3bc082c0deabf32e2e9303390806 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 16:58:42 +0100 Subject: [PATCH 12/44] MAINT --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 1713f6643..462ac8124 100644 --- a/setup.cfg +++ b/setup.cfg @@ -76,7 +76,7 @@ all= torch==1.13.1 backpack-for-pytorch==1.5.2 modcma==0.0.2.8.4 - IOHexperimenter==0.2.9 + IOHexperimenter==0.2.9.2 Pyro4==4.82 #Benchmarks From b0f6cafcd4f621828287f7812768720f13c3f517 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:03:32 +0100 Subject: [PATCH 13/44] version experiment --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 462ac8124..dbf53d01c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -76,7 +76,7 @@ all= torch==1.13.1 backpack-for-pytorch==1.5.2 modcma==0.0.2.8.4 - IOHexperimenter==0.2.9.2 + IOHexperimenter Pyro4==4.82 #Benchmarks From ff69db0c5b6cc7e0a4a918dc730aa0a1838b2109 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:05:57 +0100 Subject: [PATCH 14/44] version typo --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 2a4b45aad..b358c8a93 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -30,7 +30,7 @@ jobs: - name: Install Python 3 uses: actions/setup-python@v1 with: - python-version: 3.1 + python-version: 3.10 - name: Install dependencies run: | python -m pip install --upgrade pip From c77cd9286f7406bdbd0a5772df22cf310578db6f Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:08:13 +0100 Subject: [PATCH 15/44] Update pytest.yml --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index b358c8a93..9e1197a03 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -28,7 +28,7 @@ jobs: path: ./dacbench/envs/rl-plan/fast-downward key: fast-downward-build - name: Install Python 3 - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: 3.10 - name: Install dependencies From 4b4174c5c9dd4cbec9b5c896ea5e72a0cf4271e7 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:09:41 +0100 Subject: [PATCH 16/44] Update pytest.yml --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 9e1197a03..16509aad4 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -30,7 +30,7 @@ jobs: - name: Install Python 3 uses: actions/setup-python@v4 with: - python-version: 3.10 + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip From 41b28bf70d2399658d3a6df1da4d063247813638 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:17:18 +0100 Subject: [PATCH 17/44] Update pytest.yml --- .github/workflows/pytest.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 16509aad4..b61efbbda 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -31,6 +31,10 @@ jobs: uses: actions/setup-python@v4 with: python-version: '3.10' + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v1.13 + with: + cmake-version: '3.10.2' - name: Install dependencies run: | python -m pip install --upgrade pip From 61264ece3f89108e37c822468503b2ee5a07dff8 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 23 Mar 2023 17:20:22 +0100 Subject: [PATCH 18/44] docs corrected --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5cd960663..7001e9154 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,8 @@ .PHONY: help install-dev check format pre-commit clean build clean-doc clean-build test doc publish +DOCDIR := docs + help: @echo "Makefile DACBench" @echo "* install-dev to install all dev requirements and install pre-commit" @@ -87,8 +89,8 @@ clean: clean-doc clean-build build: $(PYTHON) setup.py sdist -doc: - $(MAKE) -C ${DOCDIR} all +docs: + $(MAKE) -C ${DOCDIR} docs @echo @echo "View docs at:" @echo ${INDEX_HTML} From b9069a774168613ebb8afc6cf017615f7fa622f7 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 11:53:12 +0100 Subject: [PATCH 19/44] Some bugfixes --- CHANGELOG.md | 36 +++++++++++++++ dacbench/abstract_env.py | 44 +++++++------------ dacbench/benchmarks/sigmoid_benchmark.py | 7 +-- dacbench/envs/policies/optimal_sigmoid.py | 12 +++-- dacbench/envs/sigmoid.py | 12 ++--- dacbench/run_baselines.py | 2 +- dacbench/wrappers/__init__.py | 2 + dacbench/wrappers/policy_progress_wrapper.py | 2 +- tests/agents/test_dynamic_random_agent.py | 17 +++++-- tests/envs/test_geometric.py | 2 +- tests/envs/test_sigmoid.py | 4 +- tests/test_multi_agent_interface.py | 13 +++--- .../wrappers/test_action_tracking_wrapper.py | 4 +- .../wrappers/test_policy_progress_wrapper.py | 9 ++-- 14 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..e92342505 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,36 @@ +# 0.2.0 + +### Interface Update +The main change in this version is going from OpenAI's gym to the newer gymnasium version. The outward change is slight, but this interface is now **incompatible with version 0.1.0**. +To adapt to this version, you'll mainly have to replace instances of 'done' for termination with two variables: 'terminated' indication algorithm termination and 'truncated' indicating a timeout. +Combined they're equal to the old 'done'. + +### Multi-Agent / Round Robin Control Option +We added more options for controlling several hyperparameters at once. Using the PettingZoo API, users can now select which hyperparameters to control and use a typical Multi-Agent RL interface to do it. +This should provide more freedom in how to solve the problem of scaling up to multiple hyperparameters. + +### Package Versions +We updated all our dependencies for this release. Please note that this will likely influence benchmark behaviour, so **do not** directly compare performance of version 0.2.0 with 0.1.0! + +### Benchmark Changes +The OneLL benchmark is not the Theory benchmark with a similar goal and setup, but a different base problem. +For versioning reasons, we removed ModEA, the same problem should be covered by ModCMA. +We also add a toy benchmark for higher dimensional spaces, the Geometric Benchmark. + +### Switches Docs to GitHub.io +The documentation is now hosted on GitHub.io instead of Read the Docs for versioning reasons. The old version should still be accessible, however. + + +# 0.1.0 +### Added Benchmarks +New benchmarks include the ModCMA IOHExperimenter version of ModEA, the OneLL EA benchmark and a toy version of controlling SGD. + +### Singularity Containers +For added reproducibility, we provide Singularity recipes for each benchmark. This way they can be run in containers. + +## ConfigSpace Integration +Search Spaces can now be defined via ConfigSpace and are then automatically converted to gym spaces. +This should make it easier to recover whcih actions correspond to which hyperparameters. + +# 0.0.1 +Initial Version \ No newline at end of file diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index 431263d54..f6025c249 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -304,23 +304,6 @@ def set_instance(self, instance): """ self.instance = instance - def seed_action_space(self, seed=None): - """ - Seeds the action space. - Parameters - ---------- - seed : int, default None - if None self.initial_seed is be used - - Returns - ------- - - """ - if seed is None: - seed = self.initial_seed - - self.action_space.seed(seed) - def seed(self, seed=None, seed_action_space=False): """ Set rng seed @@ -341,7 +324,7 @@ def seed(self, seed=None, seed_action_space=False): # uses the uncorrelated seed from seeding but makes sure that no randomness is introduces. if seed_action_space: - self.seed_action_space() + self.action_space.seed(seed) return [seed] @@ -398,11 +381,11 @@ def __init__(self, config): self.multi_agent = config.multi_agent if self.multi_agent: - space_class = type(self.env.action_space) + space_class = type(self.action_space) if space_class == gym.spaces.Box: - num_hps = len(self.env.action_space.low) + num_hps = len(self.action_space.low) elif space_class == gym.spaces.MultiDiscrete: - num_hps = len(self.env.action_space.nvec) + num_hps = len(self.action_space.nvec) else: print( "The MultiAgent environment currently only supports action spaces of types Box and MultiDiscrete" @@ -410,7 +393,7 @@ def __init__(self, config): raise TypeError self.possible_agents = np.arange(num_hps) self.hp_names = [] - if 'config_space' self.config.keys(): + if 'config_space' in self.config.keys(): self.hp_names = self.config['config_space'].get_hyperparameter_names() self.max_num_agent = len(self.possible_agents) self.env_step = self.step @@ -426,22 +409,25 @@ def __init__(self, config): self.info = None # TODO: this should be set to a reasonable default, ideally # Else playing with less than the full number of agents will be really hard - self.action = self.env.action_space.sample() + if 'default_action' in self.config.keys(): + self.action = self.config.default_action + else: + self.action = self.action_space.sample() self.observation_spaces = {} for a in self.possible_agents: - self.observation_spaces[a] = self.env.observation_space + self.observation_spaces[a] = self.observation_space - space_class = type(self.env.action_space) + space_class = type(self.action_space) if space_class == gym.spaces.Box: - lowers = self.env.action_space.low - uppers = self.env.action_space.high + lowers = self.action_space.low + uppers = self.action_space.high else: - num_options = [len(n) for n in self.env.action_space.nvec] + num_options = [n for n in self.action_space.nvec] self.action_spaces = {} for a in self.possible_agents: if space_class == gym.spaces.Box: - subspace = gym.spaces.Box(low=[lowers[a]], high=[uppers[a]]) + subspace = gym.spaces.Box(low=np.array([lowers[a]]), high=np.array([uppers[a]])) else: subspace = gym.spaces.Discrete(num_options[a]) self.action_spaces[a] = subspace diff --git a/dacbench/benchmarks/sigmoid_benchmark.py b/dacbench/benchmarks/sigmoid_benchmark.py index 21342816a..5d7434944 100644 --- a/dacbench/benchmarks/sigmoid_benchmark.py +++ b/dacbench/benchmarks/sigmoid_benchmark.py @@ -33,7 +33,7 @@ { "config_space": DEFAULT_CFG_SPACE, "action_space_class": "MultiDiscrete", - "action_space_args": list(int(ACTION_VALUES)), + "action_space_args": [ACTION_VALUES], "observation_space_class": "Box", "observation_space_type": np.float32, "observation_space_args": [ @@ -46,6 +46,7 @@ "slope_multiplier": 2.0, "seed": 0, "multi_agent": False, + "default_action": [0, 0], "instance_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_train.csv", "test_set_path": "../instance_sets/sigmoid/sigmoid_2D3M_test.csv", "benchmark_info": INFO, @@ -131,8 +132,8 @@ def set_action_values(self, values): values: list A list of possible actions per dimension """ - self.config.action_values = values - self.config.action_space_args = list(int(values)) + del self.config['config_space'] + self.config.action_space_args = [values] self.config.observation_space_args = [ np.array([-np.inf for _ in range(1 + len(values) * 3)]), np.array([np.inf for _ in range(1 + len(values) * 3)]), diff --git a/dacbench/envs/policies/optimal_sigmoid.py b/dacbench/envs/policies/optimal_sigmoid.py index d7d6e8859..461a473ba 100644 --- a/dacbench/envs/policies/optimal_sigmoid.py +++ b/dacbench/envs/policies/optimal_sigmoid.py @@ -12,14 +12,12 @@ def get_optimum(env, state): for slope, shift in zip(env.shifts, env.slopes) ] action = [] - for i in range(len(env.action_vals)): + for i in range(len(env.action_space.nvec)): best_action = None dist = 100 - for a in range(env.action_vals[i] + 1): - if np.abs(sigmoids[i] - a / (env.action_vals[i] - 1)) < dist: - dist = np.abs(sigmoids[i] - a / (env.action_vals[i])) + for a in range(env.action_space.nvec[i] + 1): + if np.abs(sigmoids[i] - a / (env.action_space.nvec[i])) < dist: + dist = np.abs(sigmoids[i] - a / (env.action_space.nvec[i]+1)) best_action = a action.append(best_action) - for k in env.action_mapper.keys(): - if env.action_mapper[k] == tuple(action): - return k + return action diff --git a/dacbench/envs/sigmoid.py b/dacbench/envs/sigmoid.py index 875b9b98d..eeaede31f 100644 --- a/dacbench/envs/sigmoid.py +++ b/dacbench/envs/sigmoid.py @@ -38,7 +38,7 @@ def __init__(self, config) -> None: self.slope_multiplier = config["slope_multiplier"] self.n_actions = len(self.action_space.nvec) self._prev_state = None - self.action = None + self.last_action = None if "reward_function" in config.keys(): self.get_reward = config["reward_function"] @@ -65,7 +65,7 @@ def step(self, action: int): state, reward, terminated, truncated, info """ self.done = super(SigmoidEnv, self).step_() - self.action = action + self.last_action = action next_state = self.get_state(self) self._prev_state = next_state return next_state, self.get_reward(self), False, self.done, {} @@ -89,7 +89,7 @@ def get_default_reward(self, _): r = [ 1 - np.abs(self._sig(self.c_step, slope, shift) - (act / (max_act - 1))) for slope, shift, act, max_act in zip( - self.slopes, self.shifts, self.action, self.action_vals + self.slopes, self.shifts, self.last_action, self.action_space.nvec ) ] r = np.prod(r) @@ -105,7 +105,7 @@ def get_default_state(self, _): if self.c_step == 0: next_state += [-1 for _ in range(self.n_actions)] else: - next_state += self.action + next_state = np.array(list(next_state) + list(self.last_action)) return np.array(next_state) def close(self) -> bool: @@ -180,7 +180,7 @@ def step(self, action: int): np.array, float, bool, dict state, reward, done, info """ - self.action = action + self.last_action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along # the x-axis instead of always advancing + 1 r = self.get_reward(self) @@ -230,7 +230,7 @@ def step(self, action: np.ndarray): np.array, float, bool, dict state, reward, done, info """ - self.action = action + self.last_action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along # the x-axis instead of always advancing + 1 r = self.get_reward(self) diff --git a/dacbench/run_baselines.py b/dacbench/run_baselines.py index 2e598eabb..a4971b88e 100644 --- a/dacbench/run_baselines.py +++ b/dacbench/run_baselines.py @@ -26,7 +26,7 @@ np.arange(3), ] DISCRETE_ACTIONS = { - "SigmoidBenchmark": np.arange(int(np.prod((5, 10)))), + "SigmoidBenchmark": list(itertools.product(*[np.arange(val) for val in (5, 10)])), "LubyBenchmark": np.arange(6), "FastDownwardBenchmark": [0, 1], "CMAESBenchmark": [np.around(a, decimals=1) for a in np.linspace(0.2, 10, num=50)], diff --git a/dacbench/wrappers/__init__.py b/dacbench/wrappers/__init__.py index 34d37d966..a44014f61 100644 --- a/dacbench/wrappers/__init__.py +++ b/dacbench/wrappers/__init__.py @@ -6,6 +6,7 @@ from dacbench.wrappers.state_tracking_wrapper import StateTrackingWrapper from dacbench.wrappers.performance_tracking_wrapper import PerformanceTrackingWrapper from dacbench.wrappers.observation_wrapper import ObservationWrapper +from dacbench.wrappers.multidiscrete_action_wrapper import MultiDiscreteActionWrapper __all__ = [ "ActionFrequencyWrapper", @@ -17,4 +18,5 @@ "PerformanceTrackingWrapper", "PolicyProgressWrapper", "ObservationWrapper", + "MultiDiscreteActionWrapper" ] diff --git a/dacbench/wrappers/policy_progress_wrapper.py b/dacbench/wrappers/policy_progress_wrapper.py index e8fcb6773..f0aaf4a17 100644 --- a/dacbench/wrappers/policy_progress_wrapper.py +++ b/dacbench/wrappers/policy_progress_wrapper.py @@ -95,7 +95,7 @@ def step(self, action): np.linalg.norm(np.array(optimal) - np.array(self.episode)) ) self.episode = [] - return state, reward,terminated, truncated, info + return state, reward, terminated, truncated, info def render_policy_progress(self): """ Plot progress """ diff --git a/tests/agents/test_dynamic_random_agent.py b/tests/agents/test_dynamic_random_agent.py index ce6f4c3b4..b7cad781f 100644 --- a/tests/agents/test_dynamic_random_agent.py +++ b/tests/agents/test_dynamic_random_agent.py @@ -2,14 +2,15 @@ from dacbench.agents import DynamicRandomAgent from dacbench.benchmarks import SigmoidBenchmark +from dacbench.wrappers import MultiDiscreteActionWrapper import numpy as np class MyTestCase(unittest.TestCase): def get_agent(self, switching_interval): env = SigmoidBenchmark().get_benchmark() - env.seed_action_space() - + env = MultiDiscreteActionWrapper(env) + env.action_space.seed(0) agent = DynamicRandomAgent(env, switching_interval=switching_interval) return agent, env @@ -20,7 +21,6 @@ def test_init(self): def test_deterministic(self): switching_interval = 2 agent, env = self.get_agent(switching_interval) - env.seed_action_space(0) state, _ = env.reset() reward = 0 @@ -30,7 +30,16 @@ def test_deterministic(self): state, reward, *_ = env.step(action) actions.append(action) - assert actions == [42, 42, 42, 42, 31, 31] + agent, env = self.get_agent(switching_interval) + state, _ = env.reset() + reward = 0 + actions2 = [] + for _ in range(6): + action = agent.act(state, reward) + state, reward, *_ = env.step(action) + actions2.append(action) + + assert actions == actions2 def test_switing_interval(self): switching_interval = 3 diff --git a/tests/envs/test_geometric.py b/tests/envs/test_geometric.py index af3580e97..38e0e7771 100644 --- a/tests/envs/test_geometric.py +++ b/tests/envs/test_geometric.py @@ -82,7 +82,7 @@ def test_reset(self): def test_step(self): env = self.make_env(DEFAULTS_STATIC) env.reset() - state, reward, terminated, truncated, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step(env.action_space.sample()) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[0] == 9) diff --git a/tests/envs/test_sigmoid.py b/tests/envs/test_sigmoid.py index 52cae6678..49e058a28 100644 --- a/tests/envs/test_sigmoid.py +++ b/tests/envs/test_sigmoid.py @@ -30,7 +30,7 @@ def test_setup(self): ) self.assertTrue(env.n_actions == len(SIGMOID_DEFAULTS["action_values"])) self.assertTrue(env.slope_multiplier == SIGMOID_DEFAULTS["slope_multiplier"]) - self.assertTrue(env.action_vals == SIGMOID_DEFAULTS["action_values"]) + self.assertTrue((env.action_space.nvec+1 == SIGMOID_DEFAULTS["action_values"]).all()) def test_reset(self): env = self.make_env() @@ -46,7 +46,7 @@ def test_reset(self): def test_step(self): env = self.make_env() env.reset() - state, reward, terminated, truncated, meta = env.step(1) + state, reward, terminated, truncated, meta = env.step([1, 1]) self.assertTrue(reward >= env.reward_range[0]) self.assertTrue(reward <= env.reward_range[1]) self.assertTrue(state[0] == 9) diff --git a/tests/test_multi_agent_interface.py b/tests/test_multi_agent_interface.py index 528ff9121..2bb04c7c5 100644 --- a/tests/test_multi_agent_interface.py +++ b/tests/test_multi_agent_interface.py @@ -1,4 +1,5 @@ import unittest +import numpy as np from dacbench.benchmarks import SigmoidBenchmark, ToySGDBenchmark, ModCMABenchmark from dacbench.envs import SigmoidEnv, ToySGDEnv @@ -32,7 +33,7 @@ def test_last(self): state, reward, terminated, truncated, info = env.last() self.assertFalse(state is None) self.assertTrue(reward is None) - self.assertTrue(info is None) + self.assertFalse(info is None) self.assertFalse(terminated) self.assertFalse(truncated) env.register_agent(max(env.possible_agents)) @@ -45,6 +46,7 @@ def test_agent_registration(self): bench = SigmoidBenchmark() bench.config["multi_agent"] = True env = bench.get_environment() + env.reset() state, _, _, _, _ = env.last() env.register_agent(0) env.register_agent(max(env.possible_agents)) @@ -54,13 +56,14 @@ def test_agent_registration(self): self.assertTrue(env.current_agent==0) env.step(0) state2, _, _, _, _ = env.last() - self.assertEqual(state, state2) + self.assertTrue(np.array_equal(state, state2)) self.assertTrue(env.current_agent==max(env.possible_agents)) + env.step(1) state3, _, _, _, _ = env.last() - self.assertNotEqual(state, state3) + self.assertFalse(np.array_equal(state, state3)) env.remove_agent(0) self.assertTrue(len(env.agents)==1) self.assertFalse(0 in env.agents) - env.register_agent('value_dim_2') + env.register_agent('value_dim_0') self.assertTrue(len(env.agents)==2) - self.assertTrue(1 in env.agents) \ No newline at end of file + self.assertTrue(0 in env.agents) \ No newline at end of file diff --git a/tests/wrappers/test_action_tracking_wrapper.py b/tests/wrappers/test_action_tracking_wrapper.py index 37790be80..d3037e1ed 100644 --- a/tests/wrappers/test_action_tracking_wrapper.py +++ b/tests/wrappers/test_action_tracking_wrapper.py @@ -34,7 +34,7 @@ def test_logging_multi_discrete(self): bench = ModCMABenchmark() bench.set_seed(seed) env = bench.get_environment() - env.seed_action_space(seed) + env.action_space.seed(seed) action_logger = logger.add_module(ActionFrequencyWrapper) wrapped = ActionFrequencyWrapper(env, logger=action_logger) action = env.action_space.sample() @@ -89,7 +89,7 @@ def test_logging_discrete(self): bench = LubyBenchmark() bench.set_seed(seed) env = bench.get_environment() - env.seed_action_space(seed) + env.action_space.seed(seed) action_logger = logger.add_module(ActionFrequencyWrapper) wrapped = ActionFrequencyWrapper(env, logger=action_logger) diff --git a/tests/wrappers/test_policy_progress_wrapper.py b/tests/wrappers/test_policy_progress_wrapper.py index 6637247d0..bb5fe18ec 100644 --- a/tests/wrappers/test_policy_progress_wrapper.py +++ b/tests/wrappers/test_policy_progress_wrapper.py @@ -13,7 +13,7 @@ def _sig(x, scaling, inflection): def compute_optimal_sigmoid(instance): sig_values = [_sig(i, instance[1], instance[0]) for i in range(10)] optimal = [np.around(x) for x in sig_values] - return optimal + return [optimal] class TestPolicyProgressWrapper(unittest.TestCase): @@ -34,10 +34,11 @@ def test_step(self): wrapped = PolicyProgressWrapper(env, compute_optimal_sigmoid) wrapped.reset() - _, _, terminated, truncated, _ = wrapped.step(1) + action = env.action_space.sample() + _, _, terminated, truncated, _ = wrapped.step(action) self.assertTrue(len(wrapped.episode) == 1) while not (terminated or truncated): - _, _, terminated, truncated, _ = wrapped.step(1) + _, _, terminated, truncated, _ = wrapped.step(action) self.assertTrue(len(wrapped.episode) == 0) self.assertTrue(len(wrapped.policy_progress) == 1) @@ -51,6 +52,6 @@ def test_render(self, mock_plt): terminated, truncated = False, False env.reset() while not (terminated or truncated): - _, _, terminated, truncated, _ = env.step(1) + _, _, terminated, truncated, _ = env.step(env.action_space.sample()) env.render_policy_progress() self.assertTrue(mock_plt.show.called) From afef3a6b631f86f497bed5d04e379c26aa66bc7f Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 12:11:10 +0100 Subject: [PATCH 20/44] formating --- .github/workflows/docs.yml | 2 +- Makefile | 14 +- dacbench/__init__.py | 2 +- dacbench/abstract_agent.py | 2 +- dacbench/abstract_benchmark.py | 29 +- dacbench/abstract_env.py | 39 ++- dacbench/agents/__init__.py | 2 +- dacbench/argument_parsing.py | 32 ++- dacbench/benchmarks/__init__.py | 10 +- dacbench/benchmarks/cma_benchmark.py | 23 +- .../benchmarks/fast_downward_benchmark.py | 18 +- dacbench/benchmarks/geometric_benchmark.py | 16 +- dacbench/benchmarks/luby_benchmark.py | 26 +- dacbench/benchmarks/modcma_benchmark.py | 54 ++-- dacbench/benchmarks/sgd_benchmark.py | 7 +- dacbench/benchmarks/sigmoid_benchmark.py | 21 +- dacbench/benchmarks/theory_benchmark.py | 12 +- dacbench/benchmarks/toysgd_benchmark.py | 7 +- .../reward_functions.py | 2 +- dacbench/container/container_utils.py | 139 +++++---- dacbench/container/remote_env.py | 34 ++- dacbench/container/remote_runner.py | 161 +++++++---- dacbench/envs/__init__.py | 16 +- dacbench/envs/cma_es.py | 18 +- dacbench/envs/cma_step_size.py | 2 +- dacbench/envs/fast_downward.py | 6 +- dacbench/envs/geometric.py | 12 +- dacbench/envs/luby.py | 4 +- dacbench/envs/modcma.py | 2 +- dacbench/envs/policies/__init__.py | 3 +- dacbench/envs/policies/optimal_luby.py | 2 +- dacbench/envs/policies/optimal_sigmoid.py | 4 +- dacbench/envs/policies/sgd_ca.py | 1 + dacbench/envs/sgd.py | 264 ++++++++++++------ dacbench/envs/sigmoid.py | 4 +- dacbench/envs/theory.py | 33 ++- dacbench/envs/toysgd.py | 8 +- .../geometric/SampleGeometricInstances.py | 7 +- dacbench/logger.py | 7 +- dacbench/plotting.py | 2 +- dacbench/run_baselines.py | 5 +- dacbench/runner.py | 8 +- dacbench/wrappers/__init__.py | 10 +- dacbench/wrappers/action_tracking_wrapper.py | 4 +- dacbench/wrappers/episode_time_tracker.py | 10 +- .../wrappers/instance_sampling_wrapper.py | 2 +- .../wrappers/multidiscrete_action_wrapper.py | 7 +- dacbench/wrappers/observation_wrapper.py | 2 +- .../wrappers/performance_tracking_wrapper.py | 6 +- dacbench/wrappers/policy_progress_wrapper.py | 4 +- dacbench/wrappers/reward_noise_wrapper.py | 2 +- dacbench/wrappers/state_tracking_wrapper.py | 12 +- docs/conf.py | 12 + docs/index.rst | 4 +- docs/source/benchmark_docs/theory.rst | 4 +- docs/source/benchmarks.rst | 2 + docs/source/contrib.rst | 2 +- tests/agents/test_dynamic_random_agent.py | 5 +- tests/benchmarks/test_cma_benchmark.py | 2 +- tests/benchmarks/test_fd_benchmark.py | 5 +- tests/benchmarks/test_luby_benchmark.py | 3 +- tests/benchmarks/test_sgd_benchmark.py | 2 +- tests/benchmarks/test_sigmoid_benchmark.py | 2 +- tests/container/test_container_utils.py | 21 +- tests/envs/test_cma.py | 4 +- tests/envs/test_deterministic.py | 4 +- tests/envs/test_fd.py | 1 + tests/envs/test_geometric.py | 1 + tests/envs/test_luby.py | 3 +- tests/envs/test_modcma.py | 6 +- tests/envs/test_sgd.py | 13 +- tests/envs/test_sigmoid.py | 7 +- tests/envs/test_theory_env.py | 3 +- tests/test_abstract_benchmark.py | 28 +- tests/test_abstract_env.py | 4 +- tests/test_logger.py | 5 +- tests/test_multi_agent_interface.py | 20 +- tests/test_run_baselines.py | 16 +- tests/test_runner.py | 20 +- .../wrappers/test_action_tracking_wrapper.py | 38 ++- .../test_instance_sampling_wrapper.py | 4 +- tests/wrappers/test_observation_wrapper.py | 1 + .../test_performance_tracking_wrapper.py | 1 + .../wrappers/test_policy_progress_wrapper.py | 1 + tests/wrappers/test_reward_noise_wrapper.py | 1 - tests/wrappers/test_state_tracking_wrapper.py | 5 +- 86 files changed, 831 insertions(+), 538 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 45f6726d2..9a79af429 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -40,7 +40,7 @@ jobs: - name: Make docs run: | make clean - make docs + make doc - name: Pull latest gh-pages if: (contains(github.ref, 'gymnasium_migration') || contains(github.ref, 'main')) && github.event_name == 'push' diff --git a/Makefile b/Makefile index 7001e9154..31d244342 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,6 @@ .PHONY: help install-dev check format pre-commit clean build clean-doc clean-build test doc publish -DOCDIR := docs - help: @echo "Makefile DACBench" @echo "* install-dev to install all dev requirements and install pre-commit" @@ -26,7 +24,7 @@ PYTEST ?= python -m pytest CTAGS ?= ctags PIP ?= python -m pip MAKE ?= make -BLACK ?= black +BLACK ?= python -m black ISORT ?= isort PYDOCSTYLE ?= pydocstyle MYPY ?= mypy @@ -35,7 +33,7 @@ FLAKE8 ?= flake8 DIR := ${CURDIR} DIST := ${CURDIR}/dist -DOCDIR := ${DIR}/docs +DOCDIR := ${CURDIR}/docs INDEX_HTML := file://${DOCDIR}/html/build/index.html install-dev: @@ -46,7 +44,7 @@ check-black: $(BLACK) dacbench tests --check || : check-isort: - $(ISORT) dacbench tests --check || : + $(ISORT) -rc dacbench tests --check || : check-pydocstyle: $(PYDOCSTYLE) dacbench || : @@ -68,7 +66,7 @@ format-black: $(BLACK) dacbench tests format-isort: - $(ISORT) dacbench tests + $(ISORT) -rc dacbench tests format: format-black format-isort @@ -89,7 +87,7 @@ clean: clean-doc clean-build build: $(PYTHON) setup.py sdist -docs: +doc: $(MAKE) -C ${DOCDIR} docs @echo @echo "View docs at:" @@ -106,4 +104,4 @@ publish: clean-build build @echo "pip install --index-url https://test.pypi.org/simple/ dacbench" @echo @echo "Once you have decided it works, publish to actual pypi with" - @echo "python -m twine upload dist/*" \ No newline at end of file + @echo "python -m twine upload dist/*" diff --git a/dacbench/__init__.py b/dacbench/__init__.py index 31d9d5c01..dbf51adec 100644 --- a/dacbench/__init__.py +++ b/dacbench/__init__.py @@ -2,7 +2,7 @@ __version__ = "0.2.0" __contact__ = "automl.org" -from dacbench.abstract_env import AbstractEnv, AbstractMADACEnv from dacbench.abstract_benchmark import AbstractBenchmark +from dacbench.abstract_env import AbstractEnv, AbstractMADACEnv __all__ = ["AbstractEnv", "AbstractMADACEnv", "AbstractBenchmark"] diff --git a/dacbench/abstract_agent.py b/dacbench/abstract_agent.py index 58016ca13..79c2cf755 100644 --- a/dacbench/abstract_agent.py +++ b/dacbench/abstract_agent.py @@ -1,5 +1,5 @@ class AbstractDACBenchAgent: - """ Abstract class to implement for use with the runner function """ + """Abstract class to implement for use with the runner function""" def __init__(self, env): """ diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index 0639c3365..0610278a7 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -1,12 +1,11 @@ import json +from functools import partial from types import FunctionType import numpy as np -from gymnasium import spaces -from functools import partial -from dacbench import wrappers -# from dacbench import ModuleLogger +from dacbench import wrappers +from gymnasium import spaces class AbstractBenchmark: @@ -140,7 +139,6 @@ def process_configspace(self, configuration_space): forbiddens = [] for hyperparameter in configuration_space.get_hyperparameters(): - if isinstance(hyperparameter, Constant): hyperparameters.append(_build_constant(hyperparameter)) elif isinstance(hyperparameter, UnParametrizedHyperparameter): @@ -161,7 +159,11 @@ def process_configspace(self, configuration_space): hyperparameters.append(_build_ordinal(hyperparameter)) else: raise TypeError( - "Unknown type: %s (%s)" % (type(hyperparameter), hyperparameter,) + "Unknown type: %s (%s)" + % ( + type(hyperparameter), + hyperparameter, + ) ) for condition in configuration_space.get_conditions(): @@ -199,17 +201,25 @@ def from_json(cls, json_config): for hyperparameter in config.config_space["hyperparameters"]: configuration_space.add_hyperparameter( - _construct_hyperparameter(hyperparameter,) + _construct_hyperparameter( + hyperparameter, + ) ) for condition in config.config_space["conditions"]: configuration_space.add_condition( - _construct_condition(condition, configuration_space,) + _construct_condition( + condition, + configuration_space, + ) ) for forbidden in config.config_space["forbiddens"]: configuration_space.add_forbidden_clause( - _construct_forbidden(forbidden, configuration_space,) + _construct_forbidden( + forbidden, + configuration_space, + ) ) config.config_space = configuration_space @@ -221,6 +231,7 @@ def to_json(self): print(k) print(conf[k]) from copy import deepcopy + del_conf = deepcopy(conf)[k] json.dumps(del_conf) return json.dumps(conf) diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index f6025c249..ce53603bd 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -1,8 +1,9 @@ import random +import numpy as np + import gymnasium as gym from gymnasium.utils import seeding -import numpy as np class AbstractEnv(gym.Env): @@ -136,9 +137,9 @@ def __init__(self, config): except TypeError: print("Tuple and Dict action spaces are currently not supported") raise TypeError - + # seeding the environment after initialising action space - self.seed(config.get("seed", None), config.get("seed_action_space", False)) + self.seed(config.get("seed", None), config.get("seed_action_space", False)) def step_(self): """ @@ -161,7 +162,7 @@ def reset_(self, seed=0, options={}, instance=None, instance_id=None, scheme=Non Will either use round robin, random or no progression scheme """ if seed is not None: - self.seed(seed, self.config.get("seed_action_space", False)) + self.seed(seed, self.config.get("seed_action_space", False)) self.c_step = 0 if scheme is None: scheme = self.instance_updates @@ -377,9 +378,9 @@ def __init__(self, config): """ super(AbstractMADACEnv, self).__init__(config) self.multi_agent = False - if 'multi_agent' in config.keys(): + if "multi_agent" in config.keys(): self.multi_agent = config.multi_agent - + if self.multi_agent: space_class = type(self.action_space) if space_class == gym.spaces.Box: @@ -393,8 +394,8 @@ def __init__(self, config): raise TypeError self.possible_agents = np.arange(num_hps) self.hp_names = [] - if 'config_space' in self.config.keys(): - self.hp_names = self.config['config_space'].get_hyperparameter_names() + if "config_space" in self.config.keys(): + self.hp_names = self.config["config_space"].get_hyperparameter_names() self.max_num_agent = len(self.possible_agents) self.env_step = self.step self.env_reset = self.reset @@ -409,7 +410,7 @@ def __init__(self, config): self.info = None # TODO: this should be set to a reasonable default, ideally # Else playing with less than the full number of agents will be really hard - if 'default_action' in self.config.keys(): + if "default_action" in self.config.keys(): self.action = self.config.default_action else: self.action = self.action_space.sample() @@ -427,7 +428,9 @@ def __init__(self, config): self.action_spaces = {} for a in self.possible_agents: if space_class == gym.spaces.Box: - subspace = gym.spaces.Box(low=np.array([lowers[a]]), high=np.array([uppers[a]])) + subspace = gym.spaces.Box( + low=np.array([lowers[a]]), high=np.array([uppers[a]]) + ) else: subspace = gym.spaces.Discrete(num_options[a]) self.action_spaces[a] = subspace @@ -436,13 +439,25 @@ def multi_agent_reset(self, seed: int = None): self.observation, self.info = self.env_reset(seed) def last(self): - return self.observation, self.reward, self.termination, self.truncation, self.info + return ( + self.observation, + self.reward, + self.termination, + self.truncation, + self.info, + ) def multi_agent_step(self, action): self.action[self.current_agent] = action self.current_agent = self.agents.index(self.current_agent) + 1 if self.current_agent >= len(self.agents): - self.observation, self.reward, self.termination, self.truncation, self.info = self.env_step(self.action) + ( + self.observation, + self.reward, + self.termination, + self.truncation, + self.info, + ) = self.env_step(self.action) self.current_agent = self.agents[0] def register_agent(self, agent_id): diff --git a/dacbench/agents/__init__.py b/dacbench/agents/__init__.py index caabeed61..8211fc619 100644 --- a/dacbench/agents/__init__.py +++ b/dacbench/agents/__init__.py @@ -1,5 +1,5 @@ +from dacbench.agents.dynamic_random_agent import DynamicRandomAgent from dacbench.agents.generic_agent import GenericAgent from dacbench.agents.simple_agents import RandomAgent, StaticAgent -from dacbench.agents.dynamic_random_agent import DynamicRandomAgent __all__ = ["StaticAgent", "RandomAgent", "GenericAgent", "DynamicRandomAgent"] diff --git a/dacbench/argument_parsing.py b/dacbench/argument_parsing.py index c1a1e7c9c..0d492fa51 100644 --- a/dacbench/argument_parsing.py +++ b/dacbench/argument_parsing.py @@ -9,8 +9,8 @@ class PathType(object): Adapted from: https://stackoverflow.com/questions/11415570/directory-path-types-with-argparse """ - def __init__(self, exists=True, type='file', dash_ok=True): - ''' + def __init__(self, exists=True, type="file", dash_ok=True): + """ Parameters ---------- @@ -24,24 +24,26 @@ def __init__(self, exists=True, type='file', dash_ok=True): None: don't care dash_ok: whether to allow "-" as stdin/stdout - ''' + """ assert exists in (True, False, None) - assert type in ('file', 'dir', 'symlink', 'socket', None) or hasattr(type, '__call__') + assert type in ("file", "dir", "symlink", "socket", None) or hasattr( + type, "__call__" + ) self._exists = exists self._type = type self._dash_ok = dash_ok def __call__(self, string: str): - if string == '-': + if string == "-": # the special argument "-" means sys.std{in,out} - if self._type == 'dir': - raise err('standard input/output (-) not allowed as directory path') - elif self._type == 'symlink': - raise err('standard input/output (-) not allowed as symlink path') + if self._type == "dir": + raise err("standard input/output (-) not allowed as directory path") + elif self._type == "symlink": + raise err("standard input/output (-) not allowed as symlink path") elif not self._dash_ok: - raise err('standard input/output (-) not allowed') + raise err("standard input/output (-) not allowed") path = Path(string) @@ -49,15 +51,17 @@ def __call__(self, string: str): if self._exists is None: pass elif not self._exists == path.exists(): - negate = '' if self._exists else 'not' - positive = '' if not self._exists else 'not' - raise err(f"{self._type.capitalize()} should {negate} exist but does {positive}") + negate = "" if self._exists else "not" + positive = "" if not self._exists else "not" + raise err( + f"{self._type.capitalize()} should {negate} exist but does {positive}" + ) # type if self._type is None: pass elif isinstance(self._type, str): - check = getattr(path, f'is_{self._type}') + check = getattr(path, f"is_{self._type}") if not check(): raise err(f"Path is not {self._type}") elif isinstance(self._type, callable): diff --git a/dacbench/benchmarks/__init__.py b/dacbench/benchmarks/__init__.py index 4938c4e58..ebaaef8e8 100644 --- a/dacbench/benchmarks/__init__.py +++ b/dacbench/benchmarks/__init__.py @@ -1,10 +1,12 @@ # flake8: noqa: F401 +import importlib +import warnings + +from dacbench.benchmarks.fast_downward_benchmark import FastDownwardBenchmark +from dacbench.benchmarks.geometric_benchmark import GeometricBenchmark from dacbench.benchmarks.luby_benchmark import LubyBenchmark from dacbench.benchmarks.sigmoid_benchmark import SigmoidBenchmark from dacbench.benchmarks.toysgd_benchmark import ToySGDBenchmark -from dacbench.benchmarks.geometric_benchmark import GeometricBenchmark - -from dacbench.benchmarks.fast_downward_benchmark import FastDownwardBenchmark __all__ = [ "LubyBenchmark", @@ -14,8 +16,6 @@ "FastDownwardBenchmark", ] -import importlib -import warnings cma_spec = importlib.util.find_spec("cma") found = cma_spec is not None diff --git a/dacbench/benchmarks/cma_benchmark.py b/dacbench/benchmarks/cma_benchmark.py index a22e393ee..8830c433e 100644 --- a/dacbench/benchmarks/cma_benchmark.py +++ b/dacbench/benchmarks/cma_benchmark.py @@ -1,17 +1,19 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import CMAESEnv -from gymnasium import spaces -import numpy as np -import os import csv +import os + import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import CMAESEnv +from gymnasium import spaces HISTORY_LENGTH = 40 INPUT_DIM = 10 DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -STEP_SIZE = CSH.UniformFloatHyperparameter(name='Step_size', lower=0, upper=10) +STEP_SIZE = CSH.UniformFloatHyperparameter(name="Step_size", lower=0, upper=10) DEFAULT_CFG_SPACE.add_hyperparameter(STEP_SIZE) INFO = { @@ -53,7 +55,7 @@ ), } ], - "reward_range": (-(10 ** 9), 0), + "reward_range": (-(10**9), 0), "cutoff": 1e6, "hist_length": HISTORY_LENGTH, "popsize": 10, @@ -99,8 +101,11 @@ def get_environment(self): if "instance_set" not in self.config.keys(): self.read_instance_set() - #Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + # Read test set if path is specified + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): self.read_instance_set(test=True) env = CMAESEnv(self.config) diff --git a/dacbench/benchmarks/fast_downward_benchmark.py b/dacbench/benchmarks/fast_downward_benchmark.py index 3d526450d..1e02890d3 100644 --- a/dacbench/benchmarks/fast_downward_benchmark.py +++ b/dacbench/benchmarks/fast_downward_benchmark.py @@ -1,10 +1,11 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import FastDownwardEnv - -import numpy as np import os + import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import FastDownwardEnv HEURISTICS = [ "tiebreaking([pdb(pattern=manual_pattern([0,1])),weight(g(),-1)])", @@ -12,7 +13,7 @@ ] DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -HEURISTIC = CSH.CategoricalHyperparameter(name='heuristic', choices=["toy1", "toy2"]) +HEURISTIC = CSH.CategoricalHyperparameter(name="heuristic", choices=["toy1", "toy2"]) DEFAULT_CFG_SPACE.add_hyperparameter(HEURISTIC) INFO = { @@ -36,7 +37,7 @@ FD_DEFAULTS = objdict( { "heuristics": HEURISTICS, - "config_space": DEFAULT_CFG_SPACE, + "config_space": DEFAULT_CFG_SPACE, "observation_space_class": "Box", "observation_space_type": np.float32, "observation_space_args": [ @@ -102,7 +103,10 @@ def get_environment(self): self.read_instance_set() # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): self.read_instance_set(test=True) env = FastDownwardEnv(self.config) diff --git a/dacbench/benchmarks/geometric_benchmark.py b/dacbench/benchmarks/geometric_benchmark.py index 470fa4f1f..0bd83bf45 100644 --- a/dacbench/benchmarks/geometric_benchmark.py +++ b/dacbench/benchmarks/geometric_benchmark.py @@ -1,12 +1,12 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import GeometricEnv - -import numpy as np -import os import csv +import os import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import GeometricEnv FILE_PATH = os.path.dirname(__file__) ACTION_VALUES = (5, 10) @@ -17,7 +17,10 @@ "identifier": "Geometric", "name": "High Dimensional Geometric Curve Approximation. Curves are geometrical orthogonal.", "reward": "Overall Euclidean Distance between Point on Curve and Action Vector for all Dimensions", - "state_description": ["Remaining Budget", "Dimensions",], + "state_description": [ + "Remaining Budget", + "Dimensions", + ], } GEOMETRIC_DEFAULTS = objdict( @@ -134,7 +137,6 @@ def read_instance_set(self): path = os.path.join(FILE_PATH, self.config.instance_set_path) self.config["instance_set"] = {} with open(path, "r") as fh: - known_ids = [] reader = csv.DictReader(fh) diff --git a/dacbench/benchmarks/luby_benchmark.py b/dacbench/benchmarks/luby_benchmark.py index b209fc103..73a064344 100644 --- a/dacbench/benchmarks/luby_benchmark.py +++ b/dacbench/benchmarks/luby_benchmark.py @@ -1,19 +1,22 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import LubyEnv, luby_gen -from dacbench.wrappers import RewardNoiseWrapper - -import numpy as np -import os import csv +import os + import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np -MAX_STEPS = 2 ** 6 +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import LubyEnv, luby_gen +from dacbench.wrappers import RewardNoiseWrapper + +MAX_STEPS = 2**6 LUBY_SEQUENCE = np.log2([next(luby_gen(i)) for i in range(1, 2 * MAX_STEPS + 2)]) HISTORY_LENGTH = 5 DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -SEQ = CSH.UniformIntegerHyperparameter(name='sequence_element', lower=0, upper=np.log2(MAX_STEPS)) +SEQ = CSH.UniformIntegerHyperparameter( + name="sequence_element", lower=0, upper=np.log2(MAX_STEPS) +) DEFAULT_CFG_SPACE.add_hyperparameter(SEQ) INFO = { @@ -42,7 +45,7 @@ "reward_range": (-1, 0), "cutoff": MAX_STEPS, "hist_length": HISTORY_LENGTH, - "min_steps": 2 ** 3, + "min_steps": 2**3, "seed": 0, "instance_set_path": "../instance_sets/luby/luby_default.csv", "benchmark_info": INFO, @@ -85,7 +88,10 @@ def get_environment(self): self.read_instance_set() # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): self.read_instance_set(test=True) env = LubyEnv(self.config) diff --git a/dacbench/benchmarks/modcma_benchmark.py b/dacbench/benchmarks/modcma_benchmark.py index 9e3da38a8..b2a4eb9ab 100644 --- a/dacbench/benchmarks/modcma_benchmark.py +++ b/dacbench/benchmarks/modcma_benchmark.py @@ -1,27 +1,42 @@ -import os import itertools +import os +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH import numpy as np from modcma import Parameters from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import ModCMAEnv, CMAStepSizeEnv - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH +from dacbench.envs import CMAStepSizeEnv, ModCMAEnv DEFAULT_CFG_SPACE = CS.ConfigurationSpace() -ACTIVE = CSH.CategoricalHyperparameter(name='0_active', choices=[True, False]) -ELITIST = CSH.CategoricalHyperparameter(name='1_elitist', choices=[True, False]) -ORTHOGONAL = CSH.CategoricalHyperparameter(name='2_orthogonal', choices=[True, False]) -SEQUENTIAL = CSH.CategoricalHyperparameter(name='3_sequential', choices=[True, False]) -THRESHOLD_CONVERGENCE = CSH.CategoricalHyperparameter(name='4_threshold_convergence', choices=[True, False]) -STEP_SIZE_ADAPTION = CSH.CategoricalHyperparameter(name='5_step_size_adaption', choices=["csa", "tpa", "msr", "xnes", "m-xnes", "lp-xnes", "psr"]) -MIRRORED = CSH.CategoricalHyperparameter(name='6_mirrored', choices=["None", "mirrored", "mirrored pairwise"]) -BASE_SAMPLER = CSH.CategoricalHyperparameter(name='7_base_sampler', choices=["gaussian", "sobol", "halton"]) -WEIGHTS_OPTION = CSH.CategoricalHyperparameter(name='8_weights_option', choices=["default", "equal", "1/2^lambda"]) -LOCAL_RESTART = CSH.CategoricalHyperparameter(name='90_local_restart', choices=["None", "IPOP", "BIPOP"]) -BOUND_CORRECTION = CSH.CategoricalHyperparameter(name='91_bound_correction', choices=["None", "saturate", "unif_resample", "COTN", "toroidal", "mirror"]) +ACTIVE = CSH.CategoricalHyperparameter(name="0_active", choices=[True, False]) +ELITIST = CSH.CategoricalHyperparameter(name="1_elitist", choices=[True, False]) +ORTHOGONAL = CSH.CategoricalHyperparameter(name="2_orthogonal", choices=[True, False]) +SEQUENTIAL = CSH.CategoricalHyperparameter(name="3_sequential", choices=[True, False]) +THRESHOLD_CONVERGENCE = CSH.CategoricalHyperparameter( + name="4_threshold_convergence", choices=[True, False] +) +STEP_SIZE_ADAPTION = CSH.CategoricalHyperparameter( + name="5_step_size_adaption", + choices=["csa", "tpa", "msr", "xnes", "m-xnes", "lp-xnes", "psr"], +) +MIRRORED = CSH.CategoricalHyperparameter( + name="6_mirrored", choices=["None", "mirrored", "mirrored pairwise"] +) +BASE_SAMPLER = CSH.CategoricalHyperparameter( + name="7_base_sampler", choices=["gaussian", "sobol", "halton"] +) +WEIGHTS_OPTION = CSH.CategoricalHyperparameter( + name="8_weights_option", choices=["default", "equal", "1/2^lambda"] +) +LOCAL_RESTART = CSH.CategoricalHyperparameter( + name="90_local_restart", choices=["None", "IPOP", "BIPOP"] +) +BOUND_CORRECTION = CSH.CategoricalHyperparameter( + name="91_bound_correction", + choices=["None", "saturate", "unif_resample", "COTN", "toroidal", "mirror"], +) DEFAULT_CFG_SPACE.add_hyperparameter(ACTIVE) DEFAULT_CFG_SPACE.add_hyperparameter(ELITIST) @@ -66,7 +81,7 @@ "observation_space_class": "Box", "observation_space_args": [-np.inf * np.ones(5), np.inf * np.ones(5)], "observation_space_type": np.float32, - "reward_range": (-(10 ** 12), 0), + "reward_range": (-(10**12), 0), "budget": 100, "cutoff": 1e6, "seed": 0, @@ -95,7 +110,10 @@ def get_environment(self): self.read_instance_set() # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): self.read_instance_set(test=True) if self.step_size: diff --git a/dacbench/benchmarks/sgd_benchmark.py b/dacbench/benchmarks/sgd_benchmark.py index 1122ae9a1..1f27c8025 100755 --- a/dacbench/benchmarks/sgd_benchmark.py +++ b/dacbench/benchmarks/sgd_benchmark.py @@ -1,16 +1,15 @@ import csv import os +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH import numpy as np -from gymnasium import spaces from torch.nn import NLLLoss from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import SGDEnv from dacbench.envs.sgd import Reward - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH +from gymnasium import spaces DEFAULT_CFG_SPACE = CS.ConfigurationSpace() LR = CSH.UniformIntegerHyperparameter(name="learning_rate", lower=0, upper=10) diff --git a/dacbench/benchmarks/sigmoid_benchmark.py b/dacbench/benchmarks/sigmoid_benchmark.py index 5d7434944..67626b000 100644 --- a/dacbench/benchmarks/sigmoid_benchmark.py +++ b/dacbench/benchmarks/sigmoid_benchmark.py @@ -1,17 +1,19 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import SigmoidEnv, ContinuousSigmoidEnv, ContinuousStateSigmoidEnv - -import numpy as np -import os import csv +import os + import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np + +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs import (ContinuousSigmoidEnv, ContinuousStateSigmoidEnv, + SigmoidEnv) ACTION_VALUES = (5, 10) DEFAULT_CFG_SPACE = CS.ConfigurationSpace() for i, d in enumerate(ACTION_VALUES): - X = CSH.UniformIntegerHyperparameter(name=f'value_dim_{i}', lower=0, upper=d-1) + X = CSH.UniformIntegerHyperparameter(name=f"value_dim_{i}", lower=0, upper=d - 1) DEFAULT_CFG_SPACE.add_hyperparameter(X) INFO = { @@ -90,7 +92,10 @@ def get_environment(self): self.read_instance_set() # Read test set if path is specified - if "test_set" not in self.config.keys() and "test_set_path" in self.config.keys(): + if ( + "test_set" not in self.config.keys() + and "test_set_path" in self.config.keys() + ): self.read_instance_set(test=True) if ( @@ -132,7 +137,7 @@ def set_action_values(self, values): values: list A list of possible actions per dimension """ - del self.config['config_space'] + del self.config["config_space"] self.config.action_space_args = [values] self.config.observation_space_args = [ np.array([-np.inf for _ in range(1 + len(values) * 3)]), diff --git a/dacbench/benchmarks/theory_benchmark.py b/dacbench/benchmarks/theory_benchmark.py index 2f48b031b..ed9da60de 100644 --- a/dacbench/benchmarks/theory_benchmark.py +++ b/dacbench/benchmarks/theory_benchmark.py @@ -1,13 +1,13 @@ -from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv - -import numpy as np import os -import pandas as pd -import gymnasium as gym import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import numpy as np +import pandas as pd + +import gymnasium as gym +from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.envs.theory import RLSEnv, RLSEnvDiscrete INFO = { "identifier": "Theory", diff --git a/dacbench/benchmarks/toysgd_benchmark.py b/dacbench/benchmarks/toysgd_benchmark.py index b19dcc010..7c49df090 100644 --- a/dacbench/benchmarks/toysgd_benchmark.py +++ b/dacbench/benchmarks/toysgd_benchmark.py @@ -1,14 +1,13 @@ import os +import ConfigSpace as CS +import ConfigSpace.hyperparameters as CSH import numpy as np import pandas as pd -from gymnasium import spaces from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import ToySGDEnv - -import ConfigSpace as CS -import ConfigSpace.hyperparameters as CSH +from gymnasium import spaces DEFAULT_CFG_SPACE = CS.ConfigurationSpace() LR = CSH.UniformFloatHyperparameter(name="0_log_learning_rate", lower=-10, upper=0) diff --git a/dacbench/challenge_benchmarks/reward_quality_challenge/reward_functions.py b/dacbench/challenge_benchmarks/reward_quality_challenge/reward_functions.py index 594784626..4455e656f 100644 --- a/dacbench/challenge_benchmarks/reward_quality_challenge/reward_functions.py +++ b/dacbench/challenge_benchmarks/reward_quality_challenge/reward_functions.py @@ -18,7 +18,7 @@ def easy_sigmoid(self): action_diffs = self.action - action r = 0 for i in range(len(action_diffs)): - r += 10 ** i * action_diffs[i] + r += 10**i * action_diffs[i] r = max(self.reward_range[0], min(self.reward_range[1], r)) return r diff --git a/dacbench/container/container_utils.py b/dacbench/container/container_utils.py index 923e0d8e5..4da87ad00 100644 --- a/dacbench/container/container_utils.py +++ b/dacbench/container/container_utils.py @@ -3,14 +3,15 @@ import os import socket import time -from typing import Any, Union, Tuple, List, Dict +from typing import Any, Dict, List, Tuple, Union -import gymnasium as gym import numpy as np +import gymnasium as gym + class Encoder(json.JSONEncoder): - """ Json Encoder to save tuple and or numpy arrays | numpy floats / integer. + """Json Encoder to save tuple and or numpy arrays | numpy floats / integer. Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py Serializing tuple/numpy array may not work. We need to annotate those types, to reconstruct them correctly. """ @@ -19,19 +20,19 @@ class Encoder(json.JSONEncoder): def hint(item): # Annotate the different item types if isinstance(item, tuple): - return {'__type__': 'tuple', '__items__': [Encoder.hint(e) for e in item]} + return {"__type__": "tuple", "__items__": [Encoder.hint(e) for e in item]} if isinstance(item, np.ndarray): - return {'__type__': 'np.ndarray', '__items__': item.tolist()} + return {"__type__": "np.ndarray", "__items__": item.tolist()} if isinstance(item, np.floating): - return {'__type__': 'np.float', '__items__': float(item)} + return {"__type__": "np.float", "__items__": float(item)} if isinstance(item, np.integer): - return {'__type__': 'np.int32', '__items__': item.tolist()} + return {"__type__": "np.int32", "__items__": item.tolist()} if isinstance(item, enum.Enum): return str(item) if isinstance(item, gym.Space): return Encoder.encode_space(item) if isinstance(item, np.dtype): - return {'__type__': 'np.dtype', '__items__': str(item)} + return {"__type__": "np.dtype", "__items__": str(item)} # If it is a container data structure, go also through the items. if isinstance(item, list): @@ -39,76 +40,111 @@ def hint(item): if isinstance(item, dict): return {key: Encoder.hint(value) for key, value in item.items()} return item + # pylint: disable=arguments-differ def encode(self, obj): return super(Encoder, self).encode(Encoder.hint(obj)) @staticmethod - def encode_space(space_obj : gym.Space): - properties = [( - '__type__', - '.'.join([space_obj.__class__.__module__, space_obj.__class__.__name__] - ) - )] - - if isinstance(space_obj, (gym.spaces.Box, gym.spaces.Discrete, gym.spaces.MultiDiscrete, gym.spaces.MultiBinary)): + def encode_space(space_obj: gym.Space): + properties = [ + ( + "__type__", + ".".join( + [space_obj.__class__.__module__, space_obj.__class__.__name__] + ), + ) + ] + + if isinstance( + space_obj, + ( + gym.spaces.Box, + gym.spaces.Discrete, + gym.spaces.MultiDiscrete, + gym.spaces.MultiBinary, + ), + ): # by default assume all constrcutor arguments are stored under the same name # for box we need to drop shape, since either shape or a array for low and height is required __init__ = space_obj.__init__.__func__.__code__ local_vars = __init__.co_varnames # drop self and non-args (self, arg1, arg2, ..., local_var1, local_var2, ...) - arguments = local_vars[1:__init__.co_argcount] - attributes_to_serialize = list(filter(lambda att: att not in ['shape', 'seed'], arguments)) + arguments = local_vars[1 : __init__.co_argcount] + attributes_to_serialize = list( + filter(lambda att: att not in ["shape", "seed"], arguments) + ) for attribute in attributes_to_serialize: if hasattr(space_obj, attribute): - properties.append((attribute, Encoder.hint(getattr(space_obj, attribute)))) + properties.append( + (attribute, Encoder.hint(getattr(space_obj, attribute))) + ) elif isinstance(space_obj, gym.spaces.Tuple): - properties.append(('spaces', [Encoder.encode_space(space) for space in space_obj.spaces])) + properties.append( + ("spaces", [Encoder.encode_space(space) for space in space_obj.spaces]) + ) elif isinstance(space_obj, gym.spaces.Dict): - properties.append(('spaces', {name:Encoder.encode_space(space) for name, space in space_obj.spaces.items()})) + properties.append( + ( + "spaces", + { + name: Encoder.encode_space(space) + for name, space in space_obj.spaces.items() + }, + ) + ) else: - raise NotImplemented(f"Serialisation for type {properties['__type__']} not implemented") + raise NotImplemented( + f"Serialisation for type {properties['__type__']} not implemented" + ) return dict(properties) + class Decoder(json.JSONDecoder): """ Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py """ + def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) - def object_hook(self, obj: Any) -> Union[Union[tuple, np.ndarray, float, float, int], Any]: - if '__type__' in obj: - __type = obj['__type__'] - if __type == 'tuple': - return tuple(obj['__items__']) - if __type == 'np.ndarray': - return np.array(obj['__items__']) - if __type == 'np.float': - return np.float(obj['__items__']) - if __type == 'np.int32': - return np.int32(obj['__items__']) - if __type == 'np.dtype': - return np.dtype(obj['__items__']) - if __type.startswith('gymnasium.spaces.'): + def object_hook( + self, obj: Any + ) -> Union[Union[tuple, np.ndarray, float, float, int], Any]: + if "__type__" in obj: + __type = obj["__type__"] + if __type == "tuple": + return tuple(obj["__items__"]) + if __type == "np.ndarray": + return np.array(obj["__items__"]) + if __type == "np.float": + return np.float(obj["__items__"]) + if __type == "np.int32": + return np.int32(obj["__items__"]) + if __type == "np.dtype": + return np.dtype(obj["__items__"]) + if __type.startswith("gymnasium.spaces."): return self.decode_space(obj) return obj - def decode_space(self, space_dict: Dict) -> gym.Space: - __type = space_dict['__type__'] - __class = getattr(gym.spaces, __type.split('.')[-1]) + __type = space_dict["__type__"] + __class = getattr(gym.spaces, __type.split(".")[-1]) - args = {name:value for name, value in space_dict.items() if name not in ['__type__', 'shape']} + args = { + name: value + for name, value in space_dict.items() + if name not in ["__type__", "shape"] + } # temporally remove subspace since constructor reseeds them - if issubclass(__class,(gym.spaces.Tuple, gym.spaces.Dict)): - spaces = args['spaces'] - args['spaces'] = type(args['spaces'])() + if issubclass(__class, (gym.spaces.Tuple, gym.spaces.Dict)): + spaces = args["spaces"] + args["spaces"] = type(args["spaces"])() space_object = __class(**args) @@ -118,7 +154,7 @@ def decode_space(self, space_dict: Dict) -> gym.Space: if isinstance(space_object, gym.spaces.Tuple): space_object.spaces = tuple(space_object.spaces) - + print(space_object) return space_object @@ -134,10 +170,13 @@ def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: start = time.time() while not os.path.exists(path): if time.time() - start > timeout: - raise TimeoutError(f"Timeout ({timeout}s) waiting for UNIX socket {path} to be created") + raise TimeoutError( + f"Timeout ({timeout}s) waiting for UNIX socket {path} to be created" + ) time.sleep(0.1) -def wait_for_port(port, host='localhost', timeout=5.0): + +def wait_for_port(port, host="localhost", timeout=5.0): """ Taken from https://gist.github.com/butla/2d9a4c0f35ea47b7452156c96a4e7b12 Wait until a port starts accepting TCP connections. @@ -163,7 +202,7 @@ def wait_for_port(port, host='localhost', timeout=5.0): except OSError as ex: time.sleep(0.01) if time.perf_counter() - start_time >= timeout: - raise TimeoutError('Waited too long for the port {} on host {} to start accepting ' - 'connections.'.format(port, host)) from ex - - + raise TimeoutError( + "Waited too long for the port {} on host {} to start accepting " + "connections.".format(port, host) + ) from ex diff --git a/dacbench/container/remote_env.py b/dacbench/container/remote_env.py index 60381d44f..b1b6876c1 100644 --- a/dacbench/container/remote_env.py +++ b/dacbench/container/remote_env.py @@ -1,19 +1,31 @@ import json from numbers import Number +from typing import Dict, List, Tuple, Union -from typing import Dict, Union, List, Tuple - -import Pyro4 import numpy as np - +import Pyro4 from dacbench.abstract_env import AbstractEnv -from dacbench.container.container_utils import Encoder, Decoder +from dacbench.container.container_utils import Decoder, Encoder NumpyTypes = Union[np.ndarray, np.int, np.float, np.random.RandomState] DefaultJsonable = Union[ - bool, None, Dict[str, 'DefaultJsonable'], List['DefaultJsonable'], Tuple['DefaultJsonable'], str, float, int] -Jsonable = Union[List['Jsonable'], Dict[str, 'Jsonable'], Tuple['Jsonable'], DefaultJsonable, NumpyTypes] + bool, + None, + Dict[str, "DefaultJsonable"], + List["DefaultJsonable"], + Tuple["DefaultJsonable"], + str, + float, + int, +] +Jsonable = Union[ + List["Jsonable"], + Dict[str, "Jsonable"], + Tuple["Jsonable"], + DefaultJsonable, + NumpyTypes, +] def json_encode(obj: Jsonable) -> str: @@ -26,7 +38,6 @@ def json_decode(json_str: str) -> Jsonable: @Pyro4.expose class RemoteEnvironmentServer: - def __init__(self, env): self.__env: AbstractEnv = env @@ -52,14 +63,13 @@ def action_space(self): return json_encode(self.__env.action_space) - class RemoteEnvironmentClient: - def __init__(self, env: RemoteEnvironmentServer): self.__env = env - def step(self, action: Union[Dict[str, np.ndarray], np.ndarray]) \ - -> Tuple[Union[Dict[str, np.ndarray], np.ndarray], Number, bool, dict]: + def step( + self, action: Union[Dict[str, np.ndarray], np.ndarray] + ) -> Tuple[Union[Dict[str, np.ndarray], np.ndarray], Number, bool, dict]: action = json_encode(action) json_str = self.__env.step(action) diff --git a/dacbench/container/remote_runner.py b/dacbench/container/remote_runner.py index 1be5919df..613ba0f59 100644 --- a/dacbench/container/remote_runner.py +++ b/dacbench/container/remote_runner.py @@ -8,7 +8,7 @@ import subprocess import sys from pathlib import Path -from typing import Tuple, Optional, Union +from typing import Optional, Tuple, Union from uuid import uuid1 import Pyro4 @@ -18,16 +18,17 @@ from dacbench.abstract_benchmark import AbstractBenchmark from dacbench.argument_parsing import PathType from dacbench.container.container_utils import wait_for_unixsocket -from dacbench.container.remote_env import RemoteEnvironmentServer, RemoteEnvironmentClient +from dacbench.container.remote_env import (RemoteEnvironmentClient, + RemoteEnvironmentServer) # Needed in order to combine event loops of name_server and daemon Pyro4.config.SERVERTYPE = "multiplex" # Read in the verbosity level from the environment variable -log_level_str = os.environ.get('DACBENCH_DEBUG', 'false') +log_level_str = os.environ.get("DACBENCH_DEBUG", "false") LOG_LEVEL = logging.INFO -LOG_LEVEL = logging.DEBUG if log_level_str == 'true' else logging.INFO +LOG_LEVEL = logging.DEBUG if log_level_str == "true" else logging.INFO root = logging.getLogger() root.setLevel(level=LOG_LEVEL) @@ -43,7 +44,7 @@ # Number of tries to connect to server MAX_TRIES = 5 -SOCKET_PATH = Path('/tmp/dacbench/sockets') +SOCKET_PATH = Path("/tmp/dacbench/sockets") @Pyro4.expose @@ -70,49 +71,57 @@ def get_environment(self) -> str: class RemoteRunner: FACTORY_NAME: str = "RemoteRunnerServerFactory" - def __init__(self, benchmark: AbstractBenchmark, container_name: str = None, container_source: Optional[str] = None, - container_tag: str = 'latest', env_str: Optional[str] = '', bind_str: Optional[str] = '', - gpu: Optional[bool] = False, socket_id=None): + def __init__( + self, + benchmark: AbstractBenchmark, + container_name: str = None, + container_source: Optional[str] = None, + container_tag: str = "latest", + env_str: Optional[str] = "", + bind_str: Optional[str] = "", + gpu: Optional[bool] = False, + socket_id=None, + ): """ - Parameters: - ---------------- - - benchmark: AbstractBenchmark - The benchmark to run - container_source : Optional[str] - Path to the container. Either local path or url to a hosting - platform, e.g. singularity hub. - container_tag : str - Singularity containers are specified by an address as well as a container tag. We use the tag as a version - number. By default the tag is set to `latest`, which then pulls the latest container from the container - source. The tag-versioning allows the users to rerun an experiment, which was performed with an older - container version. Take a look in the container_source to find the right tag to use. - bind_str : Optional[str] - Defaults to ''. You can bind further directories into the container. - This string have the form src[:dest[:opts]]. - For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html - env_str : Optional[str] - Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some - environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. - For more information, see - https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview - gpu : bool - If True, the container has access to the local cuda-drivers. - (Not tested) - socket_id : Optional[str] - Setting up the container is done in two steps: - 1) Start the benchmark on a random generated socket id. - 2) Create a proxy connection to the container via this socket id. - - When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is - stored in the class attribute Benchmark.socket_id - - When a `socket_id` is given, instead of creating a new container, connect only to the container that is - reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. + Parameters: + ---------------- + + benchmark: AbstractBenchmark + The benchmark to run + container_source : Optional[str] + Path to the container. Either local path or url to a hosting + platform, e.g. singularity hub. + container_tag : str + Singularity containers are specified by an address as well as a container tag. We use the tag as a version + number. By default the tag is set to `latest`, which then pulls the latest container from the container + source. The tag-versioning allows the users to rerun an experiment, which was performed with an older + container version. Take a look in the container_source to find the right tag to use. + bind_str : Optional[str] + Defaults to ''. You can bind further directories into the container. + This string have the form src[:dest[:opts]]. + For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html + env_str : Optional[str] + Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some + environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. + For more information, see + https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview + gpu : bool + If True, the container has access to the local cuda-drivers. + (Not tested) + socket_id : Optional[str] + Setting up the container is done in two steps: + 1) Start the benchmark on a random generated socket id. + 2) Create a proxy connection to the container via this socket id. + + When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is + stored in the class attribute Benchmark.socket_id + + When a `socket_id` is given, instead of creating a new container, connect only to the container that is + reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. """ - logger.info(f'Logging level: {logger.level}') + logger.info(f"Logging level: {logger.level}") # connect to already running server if a socket_id is given. In this case, skip the init of # the benchmark self.__proxy_only = socket_id is not None @@ -121,8 +130,12 @@ def __init__(self, benchmark: AbstractBenchmark, container_name: str = None, con if not self.__proxy_only: self.__socket_id = self.id_generator() # todo for now only work with given container source (local) - self.load_benchmark(benchmark=benchmark, container_name=container_name, - container_source=container_source, container_tag=container_tag,) + self.load_benchmark( + benchmark=benchmark, + container_name=container_name, + container_source=container_source, + container_tag=container_tag, + ) self.__start_server(env_str=env_str, bind_str=bind_str, gpu=gpu) else: self.__socket_id = socket_id @@ -135,12 +148,12 @@ def socket(self) -> Path: @staticmethod def id_generator() -> str: - """ Helper function: Creates unique socket ids for the benchmark server """ + """Helper function: Creates unique socket ids for the benchmark server""" return str(uuid1()) @staticmethod def socket_from_id(socket_id: str) -> Path: - return Path(SOCKET_PATH) / f'{socket_id}.unixsock' + return Path(SOCKET_PATH) / f"{socket_id}.unixsock" def __start_server(self, env_str, bind_str, gpu): """ @@ -156,7 +169,7 @@ def __start_server(self, env_str, bind_str, gpu): True if the container should use gpu, False otherwise """ # start container - logger.debug(f'Starting server on {self.socket}') + logger.debug(f"Starting server on {self.socket}") # todo add mechanism to to retry if failing self.daemon_process = subprocess.Popen( @@ -166,7 +179,7 @@ def __start_server(self, env_str, bind_str, gpu): "-e", str(self.container_source), "-u", - str(self.socket) + str(self.socket), ] ) @@ -224,12 +237,22 @@ def close(self): def __del__(self): self.close() - def load_benchmark(self, benchmark : AbstractBenchmark, container_name : str, container_source : Union[str, Path], container_tag : str): + def load_benchmark( + self, + benchmark: AbstractBenchmark, + container_name: str, + container_source: Union[str, Path], + container_tag: str, + ): # see for implementation guideline hpobench hpobench/container/client_abstract_benchmark.py # in the end self.container_source should contain the path to the file to run logger.warning("Only container source is used") - container_source = container_source if isinstance(container_source, Path) else Path(container_source) + container_source = ( + container_source + if isinstance(container_source, Path) + else Path(container_source) + ) self.container_source = container_source @@ -248,24 +271,40 @@ def __call__(self): return self.create() -if __name__ == '__main__': +if __name__ == "__main__": # todo refactor move to RemoverRunnerServer - parser = argparse.ArgumentParser(description='Runs the benchmark remote server inside a container') - - parser.add_argument('--unixsocket', '-u', type=PathType(exists=False, type='socket'), required=False, default=None, - dest='socket', - help="The path to a exiting socket to run the name server on. If none a new socket unixsocket is created.") + parser = argparse.ArgumentParser( + description="Runs the benchmark remote server inside a container" + ) + + parser.add_argument( + "--unixsocket", + "-u", + type=PathType(exists=False, type="socket"), + required=False, + default=None, + dest="socket", + help="The path to a exiting socket to run the name server on. If none a new socket unixsocket is created.", + ) args = parser.parse_args() daemon_socket = RemoteRunner.socket_from_id(RemoteRunner.id_generator()) - ns_socket = args.socket if args.socket else RemoteRunner.socket_from_id(RemoteRunner.id_generator()) + ns_socket = ( + args.socket + if args.socket + else RemoteRunner.socket_from_id(RemoteRunner.id_generator()) + ) print(ns_socket) daemon_socket.parent.mkdir(parents=True, exist_ok=True) ns_socket.parent.mkdir(parents=True, exist_ok=True) - print(f'Starting Pyro4 Nameserver on {ns_socket} and Pyro4 Daemon on {daemon_socket}') - name_server_uir, name_server_daemon, _ = Pyro4.naming.startNS(unixsocket=str(ns_socket)) + print( + f"Starting Pyro4 Nameserver on {ns_socket} and Pyro4 Daemon on {daemon_socket}" + ) + name_server_uir, name_server_daemon, _ = Pyro4.naming.startNS( + unixsocket=str(ns_socket) + ) daemon = Pyro4.Daemon(unixsocket=str(daemon_socket)) daemon.combine(name_server_daemon) factory = RemoteRunnerServerFactory(daemon) diff --git a/dacbench/envs/__init__.py b/dacbench/envs/__init__.py index 91c598942..432a5b343 100644 --- a/dacbench/envs/__init__.py +++ b/dacbench/envs/__init__.py @@ -1,13 +1,13 @@ # flake8: noqa: F401 -from dacbench.envs.luby import LubyEnv, luby_gen -from dacbench.envs.sigmoid import ( - SigmoidEnv, - ContinuousSigmoidEnv, - ContinuousStateSigmoidEnv, -) +import importlib +import warnings + from dacbench.envs.fast_downward import FastDownwardEnv -from dacbench.envs.toysgd import ToySGDEnv from dacbench.envs.geometric import GeometricEnv +from dacbench.envs.luby import LubyEnv, luby_gen +from dacbench.envs.sigmoid import (ContinuousSigmoidEnv, + ContinuousStateSigmoidEnv, SigmoidEnv) +from dacbench.envs.toysgd import ToySGDEnv __all__ = [ "LubyEnv", @@ -19,8 +19,6 @@ ] -import importlib -import warnings cma_spec = importlib.util.find_spec("cma") found = cma_spec is not None diff --git a/dacbench/envs/cma_es.py b/dacbench/envs/cma_es.py index 8b0c9f7fc..4f8a86cba 100644 --- a/dacbench/envs/cma_es.py +++ b/dacbench/envs/cma_es.py @@ -5,18 +5,20 @@ Original author: Gresa Shala """ -import numpy as np -from collections import deque -from cma.evolution_strategy import CMAEvolutionStrategy -from cma import bbobbenchmarks as bn +import resource +import sys import threading import warnings +from collections import deque + +import numpy as np +from cma import bbobbenchmarks as bn +from cma.evolution_strategy import CMAEvolutionStrategy + from dacbench import AbstractEnv -import resource -import sys -resource.setrlimit(resource.RLIMIT_STACK, (2 ** 35, -1)) -sys.setrecursionlimit(10 ** 9) +resource.setrlimit(resource.RLIMIT_STACK, (2**35, -1)) +sys.setrecursionlimit(10**9) warnings.filterwarnings("ignore") diff --git a/dacbench/envs/cma_step_size.py b/dacbench/envs/cma_step_size.py index 44000e834..cbb84639a 100644 --- a/dacbench/envs/cma_step_size.py +++ b/dacbench/envs/cma_step_size.py @@ -1,6 +1,6 @@ import numpy as np -from modcma import ModularCMAES, Parameters from IOHexperimenter import IOH_function +from modcma import ModularCMAES, Parameters from dacbench import AbstractEnv diff --git a/dacbench/envs/fast_downward.py b/dacbench/envs/fast_downward.py index 4113cd375..aff958d35 100644 --- a/dacbench/envs/fast_downward.py +++ b/dacbench/envs/fast_downward.py @@ -5,16 +5,18 @@ Original environment authors: David Speck, André Biedenkapp """ +import os import socket +import subprocess import time import typing from copy import deepcopy from enum import Enum from os import remove from os.path import join as joinpath -import subprocess -import os + import numpy as np + from dacbench import AbstractEnv diff --git a/dacbench/envs/geometric.py b/dacbench/envs/geometric.py index 5620a7c99..5157c4f88 100644 --- a/dacbench/envs/geometric.py +++ b/dacbench/envs/geometric.py @@ -3,19 +3,20 @@ Original environment authors: Rasmus von Glahn """ import bisect -import os import itertools import math -from typing import List, Dict, Tuple +import os +from typing import Dict, List, Tuple -from mpl_toolkits import mplot3d -from matplotlib import pyplot as plt import numpy as np import seaborn as sns +from matplotlib import pyplot as plt +from mpl_toolkits import mplot3d + +from dacbench import AbstractEnv sns.set_theme(style="darkgrid") -from dacbench import AbstractEnv class GeometricEnv(AbstractEnv): @@ -502,7 +503,6 @@ def calculate_norm_values(self, instance_set: Dict): instance_values = self.get_coordinates() for dim, function_values in enumerate(instance_values): - if abs(min(function_values)) > max(function_values): norm_factor = abs(min(function_values)) else: diff --git a/dacbench/envs/luby.py b/dacbench/envs/luby.py index 6e9ae3125..b7568203c 100644 --- a/dacbench/envs/luby.py +++ b/dacbench/envs/luby.py @@ -6,11 +6,11 @@ """ from typing import List + import numpy as np from dacbench import AbstractEnv - # Instance IDEA 1: shift luby seq -> feat is sum of skipped action values # Instance IDEA 2: "Wiggle" luby i.e. luby(t + N(0, 0.1)) -> feat is sampled value @@ -169,7 +169,7 @@ def render(self, mode: str = "human") -> None: def luby_gen(i): - """ Generator for the Luby Sequence """ + """Generator for the Luby Sequence""" for k in range(1, 33): if i == ((1 << k) - 1): yield 1 << (k - 1) diff --git a/dacbench/envs/modcma.py b/dacbench/envs/modcma.py index a3cd02573..02c8a8fde 100644 --- a/dacbench/envs/modcma.py +++ b/dacbench/envs/modcma.py @@ -1,6 +1,6 @@ import numpy as np -from modcma import ModularCMAES, Parameters from IOHexperimenter import IOH_function +from modcma import ModularCMAES, Parameters from dacbench import AbstractMADACEnv diff --git a/dacbench/envs/policies/__init__.py b/dacbench/envs/policies/__init__.py index 6a1f123cf..50e62adf0 100644 --- a/dacbench/envs/policies/__init__.py +++ b/dacbench/envs/policies/__init__.py @@ -1,7 +1,8 @@ from dacbench.envs.policies.csa_cma import csa from dacbench.envs.policies.optimal_fd import get_optimum as optimal_fd from dacbench.envs.policies.optimal_luby import get_optimum as optimal_luby -from dacbench.envs.policies.optimal_sigmoid import get_optimum as optimal_sigmoid +from dacbench.envs.policies.optimal_sigmoid import \ + get_optimum as optimal_sigmoid OPTIMAL_POLICIES = { "LubyBenchmark": optimal_luby, diff --git a/dacbench/envs/policies/optimal_luby.py b/dacbench/envs/policies/optimal_luby.py index 5e602b8d4..def7f25f2 100644 --- a/dacbench/envs/policies/optimal_luby.py +++ b/dacbench/envs/policies/optimal_luby.py @@ -1,5 +1,5 @@ def luby_gen(i): - """ Generator for the Luby Sequence """ + """Generator for the Luby Sequence""" for k in range(1, 33): if i == ((1 << k) - 1): yield 1 << (k - 1) diff --git a/dacbench/envs/policies/optimal_sigmoid.py b/dacbench/envs/policies/optimal_sigmoid.py index 461a473ba..6c86610dd 100644 --- a/dacbench/envs/policies/optimal_sigmoid.py +++ b/dacbench/envs/policies/optimal_sigmoid.py @@ -2,7 +2,7 @@ def sig(x, scaling, inflection): - """ Simple sigmoid function """ + """Simple sigmoid function""" return 1 / (1 + np.exp(-scaling * (x - inflection))) @@ -17,7 +17,7 @@ def get_optimum(env, state): dist = 100 for a in range(env.action_space.nvec[i] + 1): if np.abs(sigmoids[i] - a / (env.action_space.nvec[i])) < dist: - dist = np.abs(sigmoids[i] - a / (env.action_space.nvec[i]+1)) + dist = np.abs(sigmoids[i] - a / (env.action_space.nvec[i] + 1)) best_action = a action.append(best_action) return action diff --git a/dacbench/envs/policies/sgd_ca.py b/dacbench/envs/policies/sgd_ca.py index 03b256a8b..763c4de77 100644 --- a/dacbench/envs/policies/sgd_ca.py +++ b/dacbench/envs/policies/sgd_ca.py @@ -1,4 +1,5 @@ import math + from dacbench.abstract_agent import AbstractDACBenchAgent diff --git a/dacbench/envs/sgd.py b/dacbench/envs/sgd.py index 479034a70..ea981ad4d 100644 --- a/dacbench/envs/sgd.py +++ b/dacbench/envs/sgd.py @@ -1,9 +1,10 @@ +import json import math import numbers +import random import warnings -import json -from functools import reduce from enum import IntEnum, auto +from functools import reduce import numpy as np import torch @@ -11,8 +12,8 @@ from backpack.extensions import BatchGrad from numpy import float32 from torchvision import datasets, transforms + from dacbench import AbstractEnv -import random warnings.filterwarnings("ignore") @@ -21,6 +22,7 @@ def reward_range(frange): def wrapper(f): f.frange = frange return f + return wrapper @@ -36,8 +38,8 @@ class Reward(IntEnum): FullTraining = auto() def __call__(self, f): - if hasattr(self, 'func'): - raise ValueError('Can not assign the same reward to a different function!') + if hasattr(self, "func"): + raise ValueError("Can not assign the same reward to a different function!") self.func = f return f @@ -75,9 +77,9 @@ def __init__(self, config): try: self.reward_type = getattr(Reward, config.reward_type) except AttributeError: - raise ValueError(f'{config.reward_type} is not a valid reward type!') + raise ValueError(f"{config.reward_type} is not a valid reward type!") else: - raise ValueError(f'Type {type(config.reward_type)} is not valid!') + raise ValueError(f"Type {type(config.reward_type)} is not valid!") self.use_cuda = not self.no_cuda and torch.cuda.is_available() self.device = torch.device("cuda" if self.use_cuda else "cpu") @@ -175,11 +177,11 @@ def __init__(self, config): 1, device=self.device, requires_grad=False ) - if self.optimizer_name=="adam": + if self.optimizer_name == "adam": self.get_optimizer_direction = self.get_adam_direction - elif self.optimizer_name=="rmsprop": + elif self.optimizer_name == "rmsprop": self.get_optimizer_direction = self.get_rmsprop_direction - elif self.optimizer_name=="momentum": + elif self.optimizer_name == "momentum": self.get_optimizer_direction = self.get_momentum_direction else: raise NotImplementedError @@ -222,12 +224,17 @@ def get_log_validation_reward(self): @reward_range([-(10**9), (10**9)]) @Reward.LogDiffTraining def get_log_diff_training_reward(self): - return -(torch.log(self.current_training_loss) - torch.log(self.prev_training_loss)).item() + return -( + torch.log(self.current_training_loss) - torch.log(self.prev_training_loss) + ).item() @reward_range([-(10**9), (10**9)]) @Reward.LogDiffValidation def get_log_diff_validation_reward(self): - return -(torch.log(self.current_validation_loss) - torch.log(self.prev_validation_loss)).item() + return -( + torch.log(self.current_validation_loss) + - torch.log(self.prev_validation_loss) + ).item() @reward_range([-(10**9), (10**9)]) @Reward.DiffTraining @@ -393,30 +400,39 @@ def init_weights(m): if self.cd_paper_reconstruction: self.model.apply(init_weights) - train_dataloader_args = {"batch_size": self.batch_size, "drop_last": True, - 'shuffle': self.dataloader_shuffle} - validation_dataloader_args = {"batch_size": self.validation_batch_size, - "drop_last": True, 'shuffle': False} # SA: shuffling empty data loader causes exception + train_dataloader_args = { + "batch_size": self.batch_size, + "drop_last": True, + "shuffle": self.dataloader_shuffle, + } + validation_dataloader_args = { + "batch_size": self.validation_batch_size, + "drop_last": True, + "shuffle": False, + } # SA: shuffling empty data loader causes exception if self.use_cuda: param = {"num_workers": 1, "pin_memory": True} train_dataloader_args.update(param) validation_dataloader_args.update(param) if dataset == "MNIST": - transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize((0.1307,), (0.3081,)) - ]) + transform = transforms.Compose( + [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] + ) train_dataset = datasets.MNIST( "../data", train=True, download=True, transform=transform ) # self.test_dataset = datasets.MNIST('../data', train=False, transform=transform) elif dataset == "CIFAR": - transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), - ]) + transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize( + (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) + ), + ] + ) train_dataset = datasets.CIFAR10( "../data", train=True, download=True, transform=transform @@ -559,45 +575,61 @@ def get_default_state(self, _): self.gradients = self._get_gradients() self.gradients = self.gradients.clip(*self.clip_grad) - self.firstOrderMomentum, self.secondOrderMomentum, self.sgdMomentum = self._get_momentum(self.gradients) - - if 'predictiveChangeVarDiscountedAverage' in self.on_features or 'predictiveChangeVarUncertainty' in self.on_features: - predictiveChangeVarDiscountedAverage, predictiveChangeVarUncertainty = \ - self._get_predictive_change_features(self.current_lr) - - if 'lossVarDiscountedAverage' in self.on_features or 'lossVarUncertainty' in self.on_features: + ( + self.firstOrderMomentum, + self.secondOrderMomentum, + self.sgdMomentum, + ) = self._get_momentum(self.gradients) + + if ( + "predictiveChangeVarDiscountedAverage" in self.on_features + or "predictiveChangeVarUncertainty" in self.on_features + ): + ( + predictiveChangeVarDiscountedAverage, + predictiveChangeVarUncertainty, + ) = self._get_predictive_change_features(self.current_lr) + + if ( + "lossVarDiscountedAverage" in self.on_features + or "lossVarUncertainty" in self.on_features + ): lossVarDiscountedAverage, lossVarUncertainty = self._get_loss_features() - if 'alignment' in self.on_features: + if "alignment" in self.on_features: alignment = self._get_alignment() state = {} - if 'predictiveChangeVarDiscountedAverage' in self.on_features: - state["predictiveChangeVarDiscountedAverage"] = predictiveChangeVarDiscountedAverage.item() - if 'predictiveChangeVarUncertainty' in self.on_features: - state["predictiveChangeVarUncertainty"] = predictiveChangeVarUncertainty.item() - if 'lossVarDiscountedAverage' in self.on_features: + if "predictiveChangeVarDiscountedAverage" in self.on_features: + state[ + "predictiveChangeVarDiscountedAverage" + ] = predictiveChangeVarDiscountedAverage.item() + if "predictiveChangeVarUncertainty" in self.on_features: + state[ + "predictiveChangeVarUncertainty" + ] = predictiveChangeVarUncertainty.item() + if "lossVarDiscountedAverage" in self.on_features: state["lossVarDiscountedAverage"] = lossVarDiscountedAverage.item() - if 'lossVarUncertainty' in self.on_features: + if "lossVarUncertainty" in self.on_features: state["lossVarUncertainty"] = lossVarUncertainty.item() - if 'currentLR' in self.on_features: + if "currentLR" in self.on_features: state["currentLR"] = self.current_lr.item() - if 'trainingLoss' in self.on_features: + if "trainingLoss" in self.on_features: if self.crashed: state["trainingLoss"] = 0.0 else: state["trainingLoss"] = self.current_training_loss.item() - if 'validationLoss' in self.on_features: + if "validationLoss" in self.on_features: if self.crashed: state["validationLoss"] = 0.0 else: state["validationLoss"] = self.current_validation_loss.item() - if 'step' in self.on_features: + if "step" in self.on_features: state["step"] = self.step_count.item() - if 'alignment' in self.on_features: + if "alignment" in self.on_features: state["alignment"] = alignment.item() - if 'crashed' in self.on_features: + if "crashed" in self.on_features: state["crashed"] = self.crashed return state @@ -629,7 +661,9 @@ def train_network(self): self._train_batch_() def _get_full_training_loss(self, loader): - for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): + for target_param, param in zip( + self.val_model.parameters(), self.model.parameters() + ): target_param.data.copy_(param.data) loss = torch.zeros(1, device=self.device, requires_grad=False) with torch.no_grad(): @@ -659,7 +693,9 @@ def _get_validation_loss_(self): return validation_loss def _get_validation_loss(self): - for target_param, param in zip(self.val_model.parameters(), self.model.parameters()): + for target_param, param in zip( + self.val_model.parameters(), self.model.parameters() + ): target_param.data.copy_(param.data) try: validation_loss = self._get_validation_loss_() @@ -684,15 +720,17 @@ def _get_momentum(self, gradients): self.t += 1 self.m = self.beta1 * self.m + (1 - self.beta1) * gradients self.v = self.beta2 * self.v + (1 - self.beta2) * torch.square(gradients) - bias_corrected_m = self.m / (1 - self.beta1 ** self.t) - bias_corrected_v = self.v / (1 - self.beta2 ** self.t) + bias_corrected_m = self.m / (1 - self.beta1**self.t) + bias_corrected_v = self.v / (1 - self.beta2**self.t) self.sgd_momentum_v = self.sgd_rho * self.sgd_momentum_v + gradients return bias_corrected_m, bias_corrected_v, self.sgd_momentum_v def get_adam_direction(self): - return self.firstOrderMomentum / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) + return self.firstOrderMomentum / ( + torch.sqrt(self.secondOrderMomentum) + self.epsilon + ) def get_rmsprop_direction(self): return self.gradients / (torch.sqrt(self.secondOrderMomentum) + self.epsilon) @@ -703,7 +741,11 @@ def get_momentum_direction(self): def _get_loss_features(self): if self.crashed: return torch.tensor(0.0), torch.tensor(0.0) - bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 + bias_correction = ( + (1 - self.discount_factor ** (self.c_step + 1)) + if self.cd_bias_correction + else 1 + ) with torch.no_grad(): loss_var = torch.log(torch.var(self.loss_batch)) self.lossVarDiscountedAverage = ( @@ -713,15 +755,22 @@ def _get_loss_features(self): self.lossVarUncertainty = ( self.discount_factor * self.lossVarUncertainty + (1 - self.discount_factor) - * (loss_var - self.lossVarDiscountedAverage/bias_correction) ** 2 + * (loss_var - self.lossVarDiscountedAverage / bias_correction) ** 2 ) - return self.lossVarDiscountedAverage/bias_correction, self.lossVarUncertainty/bias_correction + return ( + self.lossVarDiscountedAverage / bias_correction, + self.lossVarUncertainty / bias_correction, + ) def _get_predictive_change_features(self, lr): if self.crashed: return torch.tensor(0.0), torch.tensor(0.0) - bias_correction = (1 - self.discount_factor ** (self.c_step+1)) if self.cd_bias_correction else 1 + bias_correction = ( + (1 - self.discount_factor ** (self.c_step + 1)) + if self.cd_bias_correction + else 1 + ) batch_gradients = [] for i, (name, param) in enumerate(self.model.named_parameters()): grad_batch = param.grad_batch.reshape( @@ -744,50 +793,56 @@ def _get_predictive_change_features(self, lr): self.predictiveChangeVarUncertainty = ( self.discount_factor * self.predictiveChangeVarUncertainty + (1 - self.discount_factor) - * (predictive_change - self.predictiveChangeVarDiscountedAverage/bias_correction) ** 2 + * ( + predictive_change + - self.predictiveChangeVarDiscountedAverage / bias_correction + ) + ** 2 ) return ( - self.predictiveChangeVarDiscountedAverage/bias_correction, - self.predictiveChangeVarUncertainty/bias_correction, + self.predictiveChangeVarDiscountedAverage / bias_correction, + self.predictiveChangeVarUncertainty / bias_correction, ) def _get_alignment(self): if self.crashed: return torch.tensor(0.0) - alignment = torch.mean(torch.sign(torch.mul(self.prev_direction, self.current_direction))) + alignment = torch.mean( + torch.sign(torch.mul(self.prev_direction, self.current_direction)) + ) alignment = torch.unsqueeze(alignment, dim=0) self.prev_direction = self.current_direction return alignment - def generate_instance_file(self, file_name, mode='test', n=100): - header = ['ID', 'dataset', 'architecture', 'seed', 'steps'] + def generate_instance_file(self, file_name, mode="test", n=100): + header = ["ID", "dataset", "architecture", "seed", "steps"] # dataset name, architecture, dataset size, sample dimension, number of max pool layers, hidden layers, test architecture convolutional layers architectures = [ - ('MNIST', - 'Conv2d(1, {0}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({0}, {1}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-Flatten-Linear({3}, 10)-LogSoftmax(1)', - 60000, - 28, - 2, - 3, - [20, 50, 500] + ( + "MNIST", + "Conv2d(1, {0}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({0}, {1}, 3, 1, 1)-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-Flatten-Linear({3}, 10)-LogSoftmax(1)", + 60000, + 28, + 2, + 3, + [20, 50, 500], + ), + ( + "CIFAR", + "Conv2d(3, {0}, 3, 1, 1)-MaxPool2d(2, 2)-ReLU-Conv2d({0}, {1}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({2}, {3}, 3, 1, 1)-ReLU-Flatten-Linear({4}, 10)-LogSoftmax(1)", + 60000, + 32, + 3, + 4, + [32, 32, 64, 64], ), - ('CIFAR', - 'Conv2d(3, {0}, 3, 1, 1)-MaxPool2d(2, 2)-ReLU-Conv2d({0}, {1}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({1}, {2}, 3, 1, 1)-ReLU-MaxPool2d(2, 2)-Conv2d({2}, {3}, 3, 1, 1)-ReLU-Flatten-Linear({4}, 10)-LogSoftmax(1)', - 60000, - 32, - 3, - 4, - [32, 32, 64, 64] - ) ] - if mode is 'test': - + if mode is "test": seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] for i in range(len(architectures)): - fname = file_name + "_" + architectures[i][0].lower() + ".csv" steps = int(1e8) @@ -797,15 +852,21 @@ def generate_instance_file(self, file_name, mode='test', n=100): sample_size = architectures[i][3] pool_layer_count = architectures[i][4] - linear_layer_size = conv[-1] * pow(sample_size / pow(2, pool_layer_count), 2) + linear_layer_size = conv[-1] * pow( + sample_size / pow(2, pool_layer_count), 2 + ) linear_layer_size = int(round(linear_layer_size)) dataset = architectures[i][0] if hidden_layers == 3: - architecture = architectures[i][1].format(conv[0], conv[1], conv[2], linear_layer_size) + architecture = architectures[i][1].format( + conv[0], conv[1], conv[2], linear_layer_size + ) else: - architecture = architectures[i][1].format(conv[0], conv[1], conv[2], conv[3], linear_layer_size) + architecture = architectures[i][1].format( + conv[0], conv[1], conv[2], conv[3], linear_layer_size + ) # args = conv # args.append(linear_layer_size) @@ -813,7 +874,7 @@ def generate_instance_file(self, file_name, mode='test', n=100): # args = {0: conv[0], 1: conv[1], 2: conv[2], 3: linear_layer_size} # architecture = architectures[i][1].format(**args) - with open(fname, 'w', encoding='UTF8') as f: + with open(fname, "w", encoding="UTF8") as f: for h in header: f.write(h + ";") @@ -851,18 +912,28 @@ def generate_instance_file(self, file_name, mode='test', n=100): dataset_list = [dataset_index for _ in range(n)] - dataset_size_list = [random.uniform(dataset_size_start, dataset_size_stop) for _ in range(n)] + dataset_size_list = [ + random.uniform(dataset_size_start, dataset_size_stop) for _ in range(n) + ] seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] - steps_list = [random.randrange(start=steps_start, stop=steps_stop) for _ in range(n)] + steps_list = [ + random.randrange(start=steps_start, stop=steps_stop) for _ in range(n) + ] - conv1_list = [random.randrange(start=conv1_start, stop=conv1_stop) for _ in range(n)] - conv2_list = [random.randrange(start=conv2_start, stop=conv2_stop) for _ in range(n)] - conv3_list = [random.randrange(start=conv3_start, stop=conv3_stop) for _ in range(n)] + conv1_list = [ + random.randrange(start=conv1_start, stop=conv1_stop) for _ in range(n) + ] + conv2_list = [ + random.randrange(start=conv2_start, stop=conv2_stop) for _ in range(n) + ] + conv3_list = [ + random.randrange(start=conv3_start, stop=conv3_stop) for _ in range(n) + ] fname = file_name + ".csv" - with open(fname, 'w', encoding='UTF8') as f: + with open(fname, "w", encoding="UTF8") as f: for h in header: f.write(h + ";") @@ -873,12 +944,23 @@ def generate_instance_file(self, file_name, mode='test', n=100): sample_size = architectures[dataset_list[id]][3] pool_layer_count = architectures[dataset_list[id]][4] - linear_layer_size = conv3_list[id] * pow(sample_size / pow(2, pool_layer_count), 2) + linear_layer_size = conv3_list[id] * pow( + sample_size / pow(2, pool_layer_count), 2 + ) linear_layer_size = int(round(linear_layer_size)) - dataset_size = int(dataset_size_list[id] * architectures[dataset_list[id]][2]) - dataset = architectures[dataset_list[id]][0] + "_" + str(dataset_size) - architecture = architectures[dataset_list[id]][1].format(conv1_list[id], conv2_list[id], conv3_list[id], linear_layer_size) + dataset_size = int( + dataset_size_list[id] * architectures[dataset_list[id]][2] + ) + dataset = ( + architectures[dataset_list[id]][0] + "_" + str(dataset_size) + ) + architecture = architectures[dataset_list[id]][1].format( + conv1_list[id], + conv2_list[id], + conv3_list[id], + linear_layer_size, + ) f.write(dataset + ";") f.write(architecture + ";") diff --git a/dacbench/envs/sigmoid.py b/dacbench/envs/sigmoid.py index eeaede31f..682256f31 100644 --- a/dacbench/envs/sigmoid.py +++ b/dacbench/envs/sigmoid.py @@ -19,7 +19,7 @@ class SigmoidEnv(AbstractMADACEnv): """ def _sig(self, x, scaling, inflection): - """ Simple sigmoid function """ + """Simple sigmoid function""" return 1 / (1 + np.exp(-scaling * (x - inflection))) def __init__(self, config) -> None: @@ -186,7 +186,7 @@ def step(self, action: int): r = self.get_reward(self) # magic constants but such that the max step is ~1 and the min step is ~0.25 - self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25))/2 + self.c_step += (r + np.sqrt(np.power(r, 2) + 0.25)) / 2 if self.c_step >= self.n_steps: self.done = True diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index 09461101a..7eaea981e 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -1,11 +1,11 @@ -import numpy as np -from copy import deepcopy import logging +import uuid from collections import deque +from copy import deepcopy -import uuid -import gymnasium as gym +import numpy as np +import gymnasium as gym from dacbench import AbstractEnv @@ -502,17 +502,20 @@ def step(self, action): msg = "Env " + self.env_type + ". " else: msg = "" - msg += "Episode done: n=%d; obj=%d; init_obj=%d; evals=%d; max_evals=%d; steps=%d; r_min=%.1f; r_max=%.1f; r_mean=%.1f; R=%.4f" % ( - self.n, - self.x.fitness, - self.init_obj, - self.total_evals, - self.max_evals, - self.c_step, - min(self.log_r), - max(self.log_r), - sum(self.log_r) / len(self.log_r), - sum(self.log_reward), + msg += ( + "Episode done: n=%d; obj=%d; init_obj=%d; evals=%d; max_evals=%d; steps=%d; r_min=%.1f; r_max=%.1f; r_mean=%.1f; R=%.4f" + % ( + self.n, + self.x.fitness, + self.init_obj, + self.total_evals, + self.max_evals, + self.c_step, + min(self.log_r), + max(self.log_r), + sum(self.log_r) / len(self.log_r), + sum(self.log_reward), + ) ) # self.logger.info(msg) returned_info["msg"] = msg diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index 19d9f1a28..0ddafc2a0 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -1,8 +1,10 @@ -from dacbench import AbstractMADACEnv +from typing import Dict, Optional, Tuple, Union + import numpy as np -from numpy.polynomial import Polynomial -from typing import Union, Tuple, Optional, Dict import pandas as pd +from numpy.polynomial import Polynomial + +from dacbench import AbstractMADACEnv def create_polynomial_instance_set( diff --git a/dacbench/instance_sets/geometric/SampleGeometricInstances.py b/dacbench/instance_sets/geometric/SampleGeometricInstances.py index 8ba1acc67..2bf4d1428 100644 --- a/dacbench/instance_sets/geometric/SampleGeometricInstances.py +++ b/dacbench/instance_sets/geometric/SampleGeometricInstances.py @@ -1,8 +1,10 @@ from __future__ import generators -from typing import Dict + +import os import random +from typing import Dict + import numpy as np -import os FILE_PATH = os.path.dirname(__file__) @@ -96,7 +98,6 @@ def _create_csv_string(index, func_name: str) -> str: value_generator = sample_parabel_cubic_value() for i in range(max_count): - if i < count: if func_name == "sinus": value = np.round(sample_sinus_value(), 1) diff --git a/dacbench/logger.py b/dacbench/logger.py index 601786e70..be0e08638 100644 --- a/dacbench/logger.py +++ b/dacbench/logger.py @@ -1,18 +1,17 @@ import json from abc import ABCMeta, abstractmethod -from collections import defaultdict, ChainMap +from collections import ChainMap, defaultdict from datetime import datetime from functools import reduce from itertools import chain from numbers import Number from pathlib import Path -from typing import Union, Dict, Any, Tuple, List +from typing import Any, Callable, Dict, Iterable, List, Tuple, Union import numpy as np import pandas as pd -from typing import Callable, Iterable -from dacbench import AbstractEnv, AbstractBenchmark +from dacbench import AbstractBenchmark, AbstractEnv from dacbench.abstract_agent import AbstractDACBenchAgent diff --git a/dacbench/plotting.py b/dacbench/plotting.py index 031685e42..e4e1ecb8c 100644 --- a/dacbench/plotting.py +++ b/dacbench/plotting.py @@ -1,8 +1,8 @@ from typing import List, Tuple import numpy as np -import seaborn as sns import pandas as pd +import seaborn as sns sns.set_style("darkgrid") diff --git a/dacbench/run_baselines.py b/dacbench/run_baselines.py index a4971b88e..d2144b8bd 100644 --- a/dacbench/run_baselines.py +++ b/dacbench/run_baselines.py @@ -6,8 +6,8 @@ import numpy as np from dacbench import benchmarks -from dacbench.agents import StaticAgent, GenericAgent, DynamicRandomAgent -from dacbench.envs.policies import OPTIMAL_POLICIES, NON_OPTIMAL_POLICIES +from dacbench.agents import DynamicRandomAgent, GenericAgent, StaticAgent +from dacbench.envs.policies import NON_OPTIMAL_POLICIES, OPTIMAL_POLICIES from dacbench.logger import Logger from dacbench.runner import run_benchmark from dacbench.wrappers import PerformanceTrackingWrapper @@ -217,7 +217,6 @@ def main(args): if args.static: for b in benchs: - if args.actions is None: actions = DISCRETE_ACTIONS[b] else: diff --git a/dacbench/runner.py b/dacbench/runner.py index cc2764b41..fbe2818c6 100644 --- a/dacbench/runner.py +++ b/dacbench/runner.py @@ -1,8 +1,10 @@ +from pathlib import Path + +import seaborn as sb + from dacbench import benchmarks -from dacbench.wrappers import PerformanceTrackingWrapper from dacbench.logger import Logger -import seaborn as sb -from pathlib import Path +from dacbench.wrappers import PerformanceTrackingWrapper sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/__init__.py b/dacbench/wrappers/__init__.py index a44014f61..a266392c1 100644 --- a/dacbench/wrappers/__init__.py +++ b/dacbench/wrappers/__init__.py @@ -1,12 +1,14 @@ from dacbench.wrappers.action_tracking_wrapper import ActionFrequencyWrapper from dacbench.wrappers.episode_time_tracker import EpisodeTimeWrapper from dacbench.wrappers.instance_sampling_wrapper import InstanceSamplingWrapper +from dacbench.wrappers.multidiscrete_action_wrapper import \ + MultiDiscreteActionWrapper +from dacbench.wrappers.observation_wrapper import ObservationWrapper +from dacbench.wrappers.performance_tracking_wrapper import \ + PerformanceTrackingWrapper from dacbench.wrappers.policy_progress_wrapper import PolicyProgressWrapper from dacbench.wrappers.reward_noise_wrapper import RewardNoiseWrapper from dacbench.wrappers.state_tracking_wrapper import StateTrackingWrapper -from dacbench.wrappers.performance_tracking_wrapper import PerformanceTrackingWrapper -from dacbench.wrappers.observation_wrapper import ObservationWrapper -from dacbench.wrappers.multidiscrete_action_wrapper import MultiDiscreteActionWrapper __all__ = [ "ActionFrequencyWrapper", @@ -18,5 +20,5 @@ "PerformanceTrackingWrapper", "PolicyProgressWrapper", "ObservationWrapper", - "MultiDiscreteActionWrapper" + "MultiDiscreteActionWrapper", ] diff --git a/dacbench/wrappers/action_tracking_wrapper.py b/dacbench/wrappers/action_tracking_wrapper.py index 9963a58d0..0c8ac8666 100644 --- a/dacbench/wrappers/action_tracking_wrapper.py +++ b/dacbench/wrappers/action_tracking_wrapper.py @@ -1,10 +1,10 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from gymnasium import Wrapper -from gymnasium import spaces from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +from gymnasium import Wrapper, spaces + sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/episode_time_tracker.py b/dacbench/wrappers/episode_time_tracker.py index bab927cee..182539df0 100644 --- a/dacbench/wrappers/episode_time_tracker.py +++ b/dacbench/wrappers/episode_time_tracker.py @@ -1,9 +1,11 @@ -from gymnasium import Wrapper -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas import time + +import matplotlib.pyplot as plt +import numpy as np import seaborn as sb +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas + +from gymnasium import Wrapper sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/instance_sampling_wrapper.py b/dacbench/wrappers/instance_sampling_wrapper.py index 72a66f707..528f63c37 100644 --- a/dacbench/wrappers/instance_sampling_wrapper.py +++ b/dacbench/wrappers/instance_sampling_wrapper.py @@ -1,5 +1,5 @@ -from gym import Wrapper import numpy as np +from gym import Wrapper from scipy.stats import norm diff --git a/dacbench/wrappers/multidiscrete_action_wrapper.py b/dacbench/wrappers/multidiscrete_action_wrapper.py index 47f07fa9d..642d88acc 100644 --- a/dacbench/wrappers/multidiscrete_action_wrapper.py +++ b/dacbench/wrappers/multidiscrete_action_wrapper.py @@ -1,7 +1,8 @@ import itertools + import numpy as np -from gymnasium import Wrapper -from gymnasium import spaces + +from gymnasium import Wrapper, spaces class MultiDiscreteActionWrapper(Wrapper): @@ -31,4 +32,4 @@ def __init__(self, env): def step(self, action): action = self.action_mapper[action] - return self.env.step(action) \ No newline at end of file + return self.env.step(action) diff --git a/dacbench/wrappers/observation_wrapper.py b/dacbench/wrappers/observation_wrapper.py index 57d8e27fe..5f2ac192c 100644 --- a/dacbench/wrappers/observation_wrapper.py +++ b/dacbench/wrappers/observation_wrapper.py @@ -1,7 +1,7 @@ from collections.abc import Iterable -from gym import Wrapper, spaces import numpy as np +from gym import Wrapper, spaces class ObservationWrapper(Wrapper): diff --git a/dacbench/wrappers/performance_tracking_wrapper.py b/dacbench/wrappers/performance_tracking_wrapper.py index 187e22e85..1c42f58d4 100644 --- a/dacbench/wrappers/performance_tracking_wrapper.py +++ b/dacbench/wrappers/performance_tracking_wrapper.py @@ -1,9 +1,9 @@ from collections import defaultdict -from gym import Wrapper import matplotlib.pyplot as plt import numpy as np import seaborn as sb +from gym import Wrapper sb.set_style("darkgrid") current_palette = list(sb.color_palette()) @@ -178,7 +178,7 @@ def get_performance(self): return self.overall_performance def render_performance(self): - """ Plot performance """ + """Plot performance""" plt.figure(figsize=(12, 6)) plt.plot( np.arange(len(self.overall_performance) // 2), @@ -190,7 +190,7 @@ def render_performance(self): plt.show() def render_instance_performance(self): - """ Plot mean performance for each instance """ + """Plot mean performance for each instance""" plt.figure(figsize=(12, 6)) plt.title("Mean Performance per Instance") plt.ylabel("Mean reward") diff --git a/dacbench/wrappers/policy_progress_wrapper.py b/dacbench/wrappers/policy_progress_wrapper.py index f0aaf4a17..3618ec58e 100644 --- a/dacbench/wrappers/policy_progress_wrapper.py +++ b/dacbench/wrappers/policy_progress_wrapper.py @@ -1,6 +1,6 @@ -from gym import Wrapper import matplotlib.pyplot as plt import numpy as np +from gym import Wrapper class PolicyProgressWrapper(Wrapper): @@ -98,7 +98,7 @@ def step(self, action): return state, reward, terminated, truncated, info def render_policy_progress(self): - """ Plot progress """ + """Plot progress""" plt.figure(figsize=(12, 6)) plt.plot(np.arange(len(self.policy_progress)), self.policy_progress) plt.title("Policy progress over time") diff --git a/dacbench/wrappers/reward_noise_wrapper.py b/dacbench/wrappers/reward_noise_wrapper.py index 779482800..079002e1a 100644 --- a/dacbench/wrappers/reward_noise_wrapper.py +++ b/dacbench/wrappers/reward_noise_wrapper.py @@ -1,5 +1,5 @@ -from gym import Wrapper import numpy as np +from gym import Wrapper class RewardNoiseWrapper(Wrapper): diff --git a/dacbench/wrappers/state_tracking_wrapper.py b/dacbench/wrappers/state_tracking_wrapper.py index c769c96cc..95de9cec9 100644 --- a/dacbench/wrappers/state_tracking_wrapper.py +++ b/dacbench/wrappers/state_tracking_wrapper.py @@ -1,9 +1,9 @@ -from gymnasium import spaces -from gymnasium import Wrapper -import numpy as np import matplotlib.pyplot as plt -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +import numpy as np import seaborn as sb +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas + +from gymnasium import Wrapper, spaces sb.set_style("darkgrid") current_palette = list(sb.color_palette()) @@ -237,7 +237,7 @@ def plot_single(ax=None, index=None, title=None, x=False, y=False): print(self.state_type) print(spaces.Tuple) - print(self.state_type==spaces.Tuple) + print(self.state_type == spaces.Tuple) if self.state_type == spaces.Discrete: figure = plt.figure(figsize=(20, 20)) canvas = FigureCanvas(figure) @@ -286,7 +286,7 @@ def plot_single(ax=None, index=None, title=None, x=False, y=False): p, p2 = plot_single(axarr[i % dim, i // dim], i, x=x, y=y) canvas.draw() else: - raise ValueError('Unknown state type') + raise ValueError("Unknown state type") width, height = figure.get_size_inches() * figure.get_dpi() img = np.fromstring(canvas.tostring_rgb(), dtype="uint8").reshape( int(height), int(width), 3 diff --git a/docs/conf.py b/docs/conf.py index d8c5d1045..bc1975203 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,5 +38,17 @@ "github_url": "https://github.com/automl/DACBench", "twitter_url": "https://twitter.com/automl_org?lang=de", }, + #this is here to exclude the gallery for examples + "extensions": ["myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", # Enables to understand NumPy docstring + # "numpydoc", + "sphinx.ext.autosummary", + "sphinx.ext.autosectionlabel", + "sphinx_autodoc_typehints", + "sphinx.ext.doctest", + ] + } automl_sphinx_theme.set_options(globals(), options) \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 61bbe6cdd..af1388aa1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,12 +20,11 @@ Welcome to DACBench's documentation! source/benchmarks source/benchmark_docs/sigmoid source/benchmark_docs/luby - source/benchmark_docs/toysgd + source/benchmark_docs/toy_sgd source/benchmark_docs/geometric source/benchmark_docs/fastdownward source/benchmark_docs/theory source/benchmark_docs/cma - source/benchmark_docs/modea source/benchmark_docs/modcma source/benchmark_docs/sgd @@ -34,6 +33,7 @@ Welcome to DACBench's documentation! :caption: Using DACBench: source/modifications + source/multi_agent_dac source/state_and_reward source/wrappers source/logging diff --git a/docs/source/benchmark_docs/theory.rst b/docs/source/benchmark_docs/theory.rst index 253580917..470ad49f9 100644 --- a/docs/source/benchmark_docs/theory.rst +++ b/docs/source/benchmark_docs/theory.rst @@ -1,8 +1,8 @@ .. _theory: -==================== +===================== The Theory Benchmark -==================== +===================== | **Task:** controlling number of flips in RLS on LeadingOnes | **Cost:** number of iterations until solution diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index a25867fda..e8ff0a408 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -50,10 +50,12 @@ To instantiate a benchmark environment, run: bench = SigmoidBenchmark() benchmark_env = bench.get_environment() + .. automodule:: dacbench.abstract_benchmark :members: :show-inheritance: + .. automodule:: dacbench.abstract_env :members: :show-inheritance: \ No newline at end of file diff --git a/docs/source/contrib.rst b/docs/source/contrib.rst index fdaf91e27..405078f08 100644 --- a/docs/source/contrib.rst +++ b/docs/source/contrib.rst @@ -1,4 +1,4 @@ -.. _benchmarks: +.. _contrib: ======================== Contributing to DACBench diff --git a/tests/agents/test_dynamic_random_agent.py b/tests/agents/test_dynamic_random_agent.py index b7cad781f..11bea476e 100644 --- a/tests/agents/test_dynamic_random_agent.py +++ b/tests/agents/test_dynamic_random_agent.py @@ -1,9 +1,10 @@ import unittest +import numpy as np + from dacbench.agents import DynamicRandomAgent from dacbench.benchmarks import SigmoidBenchmark from dacbench.wrappers import MultiDiscreteActionWrapper -import numpy as np class MyTestCase(unittest.TestCase): @@ -45,7 +46,7 @@ def test_switing_interval(self): switching_interval = 3 agent, env = self.get_agent(switching_interval) - state, _ = env.reset() + state, _ = env.reset() reward = 0 actions = [] for i in range(21): diff --git a/tests/benchmarks/test_cma_benchmark.py b/tests/benchmarks/test_cma_benchmark.py index e4e20d219..35e639901 100644 --- a/tests/benchmarks/test_cma_benchmark.py +++ b/tests/benchmarks/test_cma_benchmark.py @@ -1,6 +1,6 @@ -import unittest import json import os +import unittest from dacbench.benchmarks import CMAESBenchmark from dacbench.envs import CMAESEnv diff --git a/tests/benchmarks/test_fd_benchmark.py b/tests/benchmarks/test_fd_benchmark.py index f027c5b9f..456657320 100644 --- a/tests/benchmarks/test_fd_benchmark.py +++ b/tests/benchmarks/test_fd_benchmark.py @@ -1,6 +1,7 @@ -import unittest -import os import json +import os +import unittest + from dacbench.benchmarks import FastDownwardBenchmark from dacbench.envs import FastDownwardEnv diff --git a/tests/benchmarks/test_luby_benchmark.py b/tests/benchmarks/test_luby_benchmark.py index 9ed2e2fc6..a0e232570 100644 --- a/tests/benchmarks/test_luby_benchmark.py +++ b/tests/benchmarks/test_luby_benchmark.py @@ -1,8 +1,9 @@ -import unittest import json import os +import unittest import numpy as np + from dacbench.benchmarks import LubyBenchmark from dacbench.envs import LubyEnv from dacbench.wrappers import RewardNoiseWrapper diff --git a/tests/benchmarks/test_sgd_benchmark.py b/tests/benchmarks/test_sgd_benchmark.py index dc5658a60..2f13bc26d 100644 --- a/tests/benchmarks/test_sgd_benchmark.py +++ b/tests/benchmarks/test_sgd_benchmark.py @@ -1,6 +1,6 @@ -import unittest import json import os +import unittest from dacbench.benchmarks import SGDBenchmark from dacbench.envs import SGDEnv diff --git a/tests/benchmarks/test_sigmoid_benchmark.py b/tests/benchmarks/test_sigmoid_benchmark.py index 247381b12..509dc7d1c 100644 --- a/tests/benchmarks/test_sigmoid_benchmark.py +++ b/tests/benchmarks/test_sigmoid_benchmark.py @@ -1,6 +1,6 @@ -import unittest import json import os +import unittest from dacbench.benchmarks import SigmoidBenchmark from dacbench.envs import SigmoidEnv diff --git a/tests/container/test_container_utils.py b/tests/container/test_container_utils.py index 934d8b847..54d481191 100644 --- a/tests/container/test_container_utils.py +++ b/tests/container/test_container_utils.py @@ -2,9 +2,10 @@ import unittest import numpy as np -from gymnasium.spaces import Box, Discrete, Tuple, MultiDiscrete, MultiBinary, Dict -from dacbench.container.container_utils import Encoder, Decoder +from dacbench.container.container_utils import Decoder, Encoder +from gymnasium.spaces import (Box, Dict, Discrete, MultiBinary, MultiDiscrete, + Tuple) class TestEncoder(unittest.TestCase): @@ -21,10 +22,19 @@ def test_spaces(self): restored_space = json.loads(serialized, cls=Decoder) self.assertEqual(space, restored_space) - def test_recursive_spaces(self): - tuple_space = Tuple((Box(low=-1, high=1, shape=(2,)), Box(low=-1, high=1, shape=(2,)))) - dict_space = Dict({'a': Box(low=-1, high=1, shape=(2,)), 'b': MultiBinary([2, 2]), 'c': Tuple((Box(low=-1, high=1, shape=(2,)), Box(low=-1, high=1, shape=(2,))))}) + tuple_space = Tuple( + (Box(low=-1, high=1, shape=(2,)), Box(low=-1, high=1, shape=(2,))) + ) + dict_space = Dict( + { + "a": Box(low=-1, high=1, shape=(2,)), + "b": MultiBinary([2, 2]), + "c": Tuple( + (Box(low=-1, high=1, shape=(2,)), Box(low=-1, high=1, shape=(2,))) + ), + } + ) spaces = [tuple_space, dict_space] @@ -33,4 +43,3 @@ def test_recursive_spaces(self): serialized = json.dumps(space, cls=Encoder) restored_space = json.loads(serialized, cls=Decoder) self.assertEqual(space, restored_space) - diff --git a/tests/envs/test_cma.py b/tests/envs/test_cma.py index a10b19f3f..97c85cb2c 100644 --- a/tests/envs/test_cma.py +++ b/tests/envs/test_cma.py @@ -1,7 +1,9 @@ import unittest + import numpy as np + from dacbench import AbstractEnv -from dacbench.benchmarks.cma_benchmark import CMAESBenchmark, CMAES_DEFAULTS +from dacbench.benchmarks.cma_benchmark import CMAES_DEFAULTS, CMAESBenchmark class TestCMAEnv(unittest.TestCase): diff --git a/tests/envs/test_deterministic.py b/tests/envs/test_deterministic.py index 8f18ecb84..578130720 100644 --- a/tests/envs/test_deterministic.py +++ b/tests/envs/test_deterministic.py @@ -14,7 +14,7 @@ def assert_state_space_equal(state1, state2): elif isinstance(state1, dict): assert state1.keys() == state2.keys() for key in state1.keys(): - if 'history' not in key: + if "history" not in key: assert_almost_equal(state1[key], state2[key]) else: raise NotImplementedError(f"State space type {type(state1)} not comparable") @@ -74,7 +74,7 @@ def test_CMAESBenchmark(self): self.run_deterministic_test("CMAESBenchmark") # This has no get_benchmark method - #def test_ModeaBenchmark(self): + # def test_ModeaBenchmark(self): # self.run_deterministic_test("ModeaBenchmark") def test_SGDBenchmark(self): diff --git a/tests/envs/test_fd.py b/tests/envs/test_fd.py index d45dd2d15..4a36c5066 100644 --- a/tests/envs/test_fd.py +++ b/tests/envs/test_fd.py @@ -1,4 +1,5 @@ import unittest + from dacbench import AbstractEnv from dacbench.benchmarks.fast_downward_benchmark import FastDownwardBenchmark diff --git a/tests/envs/test_geometric.py b/tests/envs/test_geometric.py index 38e0e7771..a7e945a02 100644 --- a/tests/envs/test_geometric.py +++ b/tests/envs/test_geometric.py @@ -3,6 +3,7 @@ from typing import Dict import numpy as np + from dacbench import AbstractEnv from dacbench.abstract_benchmark import objdict from dacbench.benchmarks import GeometricBenchmark diff --git a/tests/envs/test_luby.py b/tests/envs/test_luby.py index 17d0fc685..73c00b884 100644 --- a/tests/envs/test_luby.py +++ b/tests/envs/test_luby.py @@ -1,9 +1,10 @@ import unittest import numpy as np + from dacbench import AbstractEnv -from dacbench.envs import LubyEnv from dacbench.benchmarks.luby_benchmark import LUBY_DEFAULTS +from dacbench.envs import LubyEnv class TestLubyEnv(unittest.TestCase): diff --git a/tests/envs/test_modcma.py b/tests/envs/test_modcma.py index d266be565..bf4fc487f 100644 --- a/tests/envs/test_modcma.py +++ b/tests/envs/test_modcma.py @@ -1,8 +1,10 @@ import unittest + import numpy as np + from dacbench import AbstractEnv -from dacbench.envs import ModCMAEnv from dacbench.abstract_benchmark import objdict +from dacbench.envs import ModCMAEnv from gymnasium import spaces @@ -19,7 +21,7 @@ def make_env(self): config.observation_space = spaces.Box( low=-np.inf * np.ones(5), high=np.inf * np.ones(5) ) - config.reward_range = (-(10 ** 12), 0) + config.reward_range = (-(10**12), 0) env = ModCMAEnv(config) return env diff --git a/tests/envs/test_sgd.py b/tests/envs/test_sgd.py index 6b200ac17..1aaa7c3c8 100644 --- a/tests/envs/test_sgd.py +++ b/tests/envs/test_sgd.py @@ -1,11 +1,12 @@ -import unittest import os +import unittest import numpy as np + from dacbench import AbstractEnv -from dacbench.envs.sgd import SGDEnv, Reward from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.benchmarks.sgd_benchmark import SGDBenchmark, SGD_DEFAULTS +from dacbench.benchmarks.sgd_benchmark import SGD_DEFAULTS, SGDBenchmark +from dacbench.envs.sgd import Reward, SGDEnv from dacbench.wrappers import ObservationWrapper @@ -16,7 +17,7 @@ def setUp(self): @staticmethod def data_path(path): - return os.path.join(os.path.dirname(__file__), 'data', path) + return os.path.join(os.path.dirname(__file__), "data", path) def test_setup(self): self.assertTrue(issubclass(type(self.env), AbstractEnv)) @@ -38,7 +39,7 @@ def test_reward_type(self): env = SGDEnv(benchmark.config) self.assertEqual(env.reward_type, SGD_DEFAULTS.reward_type) - benchmark.config.reward_type = 'invalid_reward' + benchmark.config.reward_type = "invalid_reward" with self.assertRaises(ValueError): env = SGDEnv(benchmark.config) @@ -156,7 +157,7 @@ def test_get_default_state(self): "validationLoss", "step", "alignment", - "crashed" + "crashed", ], ) ) diff --git a/tests/envs/test_sigmoid.py b/tests/envs/test_sigmoid.py index 49e058a28..b11382f1b 100644 --- a/tests/envs/test_sigmoid.py +++ b/tests/envs/test_sigmoid.py @@ -2,9 +2,10 @@ from unittest import mock import numpy as np + from dacbench import AbstractEnv -from dacbench.envs import SigmoidEnv from dacbench.benchmarks.sigmoid_benchmark import SIGMOID_DEFAULTS +from dacbench.envs import SigmoidEnv class TestSigmoidEnv(unittest.TestCase): @@ -30,7 +31,9 @@ def test_setup(self): ) self.assertTrue(env.n_actions == len(SIGMOID_DEFAULTS["action_values"])) self.assertTrue(env.slope_multiplier == SIGMOID_DEFAULTS["slope_multiplier"]) - self.assertTrue((env.action_space.nvec+1 == SIGMOID_DEFAULTS["action_values"]).all()) + self.assertTrue( + (env.action_space.nvec + 1 == SIGMOID_DEFAULTS["action_values"]).all() + ) def test_reset(self): env = self.make_env() diff --git a/tests/envs/test_theory_env.py b/tests/envs/test_theory_env.py index f746ff492..20fe10024 100644 --- a/tests/envs/test_theory_env.py +++ b/tests/envs/test_theory_env.py @@ -1,6 +1,7 @@ -from dacbench.benchmarks import TheoryBenchmark import unittest + import gymnasium as gym +from dacbench.benchmarks import TheoryBenchmark class TestTheoryEnv(unittest.TestCase): diff --git a/tests/test_abstract_benchmark.py b/tests/test_abstract_benchmark.py index b13e0cf93..fca4c0514 100644 --- a/tests/test_abstract_benchmark.py +++ b/tests/test_abstract_benchmark.py @@ -1,18 +1,16 @@ -import unittest import json import os +import tempfile +import unittest + import numpy as np -from gymnasium.spaces import Box, Discrete, Dict, MultiDiscrete, MultiBinary from dacbench.abstract_benchmark import AbstractBenchmark, objdict -import tempfile - -from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import ( - random_reward, -) -from dacbench.challenge_benchmarks.state_space_challenge.random_states import ( - small_random_sigmoid_state, -) +from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import \ + random_reward +from dacbench.challenge_benchmarks.state_space_challenge.random_states import \ + small_random_sigmoid_state +from gymnasium.spaces import Box, Dict, Discrete, MultiBinary, MultiDiscrete class TestAbstractBenchmark(unittest.TestCase): @@ -110,7 +108,10 @@ def assert_restorable(space): bench = AbstractBenchmark() - space = Box(low=np.array([0, 0]), high=np.array([1, 1]),) + space = Box( + low=np.array([0, 0]), + high=np.array([1, 1]), + ) assert_restorable(space) space = Discrete(2) @@ -118,7 +119,10 @@ def assert_restorable(space): space = Dict( { - "box": Box(low=np.array([0, 0]), high=np.array([1, 1]),), + "box": Box( + low=np.array([0, 0]), + high=np.array([1, 1]), + ), "discrete": Discrete(n=2), } ) diff --git a/tests/test_abstract_env.py b/tests/test_abstract_env.py index f84facd79..f6280f86b 100644 --- a/tests/test_abstract_env.py +++ b/tests/test_abstract_env.py @@ -1,9 +1,9 @@ - import unittest import numpy as np -from gymnasium import spaces + from dacbench.abstract_env import AbstractEnv +from gymnasium import spaces class TestAbstractEnv(unittest.TestCase): diff --git a/tests/test_logger.py b/tests/test_logger.py index d1b3ee331..631c1ae54 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -2,13 +2,14 @@ import tempfile import unittest from pathlib import Path + import numpy as np from gym import spaces -from gym.spaces import Discrete, MultiDiscrete, Dict, Box +from gym.spaces import Box, Dict, Discrete, MultiDiscrete from dacbench.agents.simple_agents import RandomAgent from dacbench.benchmarks import SigmoidBenchmark -from dacbench.logger import ModuleLogger, Logger, log2dataframe +from dacbench.logger import Logger, ModuleLogger, log2dataframe class TestLogger(unittest.TestCase): diff --git a/tests/test_multi_agent_interface.py b/tests/test_multi_agent_interface.py index 2bb04c7c5..c72929d60 100644 --- a/tests/test_multi_agent_interface.py +++ b/tests/test_multi_agent_interface.py @@ -1,8 +1,12 @@ import unittest + import numpy as np -from dacbench.benchmarks import SigmoidBenchmark, ToySGDBenchmark, ModCMABenchmark + +from dacbench.benchmarks import (ModCMABenchmark, SigmoidBenchmark, + ToySGDBenchmark) from dacbench.envs import SigmoidEnv, ToySGDEnv + class TestMultiAgentInterface(unittest.TestCase): def test_make_env(self): bench = SigmoidBenchmark() @@ -50,20 +54,20 @@ def test_agent_registration(self): state, _, _, _, _ = env.last() env.register_agent(0) env.register_agent(max(env.possible_agents)) - self.assertTrue(len(env.agents)==2) + self.assertTrue(len(env.agents) == 2) self.assertTrue(0 in env.agents) self.assertTrue(max(env.possible_agents) in env.agents) - self.assertTrue(env.current_agent==0) + self.assertTrue(env.current_agent == 0) env.step(0) state2, _, _, _, _ = env.last() self.assertTrue(np.array_equal(state, state2)) - self.assertTrue(env.current_agent==max(env.possible_agents)) + self.assertTrue(env.current_agent == max(env.possible_agents)) env.step(1) state3, _, _, _, _ = env.last() self.assertFalse(np.array_equal(state, state3)) env.remove_agent(0) - self.assertTrue(len(env.agents)==1) + self.assertTrue(len(env.agents) == 1) self.assertFalse(0 in env.agents) - env.register_agent('value_dim_0') - self.assertTrue(len(env.agents)==2) - self.assertTrue(0 in env.agents) \ No newline at end of file + env.register_agent("value_dim_0") + self.assertTrue(len(env.agents) == 2) + self.assertTrue(0 in env.agents) diff --git a/tests/test_run_baselines.py b/tests/test_run_baselines.py index 5c478a72e..6c2eb1087 100644 --- a/tests/test_run_baselines.py +++ b/tests/test_run_baselines.py @@ -1,16 +1,10 @@ import tempfile import unittest from pathlib import Path -from dacbench.logger import load_logs, log2dataframe -from dacbench.run_baselines import ( - run_random, - DISCRETE_ACTIONS, - run_static, - run_dynamic_policy, - run_optimal, - main, -) +from dacbench.logger import load_logs, log2dataframe +from dacbench.run_baselines import (DISCRETE_ACTIONS, main, run_dynamic_policy, + run_optimal, run_random, run_static) class TestRunBaselines(unittest.TestCase): @@ -55,7 +49,7 @@ def test_run_random_SGDBenchmark(self): self.run_random_test_with_benchmark("SGDBenchmark") # no get_benchmark method - #def test_run_random_ModeaBenchmark(self): + # def test_run_random_ModeaBenchmark(self): # self.run_random_test_with_benchmark("ModeaBenchmark") def run_static_test_with_benchmark(self, benchmark): @@ -98,7 +92,7 @@ def test_run_static_SGDBenchmark(self): self.run_static_test_with_benchmark("SGDBenchmark") # no get_benchmark method - #def test_run_static_ModeaBenchmark(self): + # def test_run_static_ModeaBenchmark(self): # self.run_static_test_with_benchmark("ModeaBenchmark") def test_run_dynamic_policy_CMAESBenchmark(self): diff --git a/tests/test_runner.py b/tests/test_runner.py index 904c946e4..7cd33ecdd 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -1,16 +1,16 @@ +import os import tempfile +import unittest from pathlib import Path -import pytest -import unittest -from gymnasium import spaces -import os +import matplotlib import numpy as np +import pytest +from dacbench.abstract_agent import AbstractDACBenchAgent # import shutil from dacbench.runner import run_dacbench # , plot_results -from dacbench.abstract_agent import AbstractDACBenchAgent -import matplotlib +from gymnasium import spaces matplotlib.use("Agg") @@ -54,7 +54,13 @@ def make(env): return DummyAgent(env) with tempfile.TemporaryDirectory() as tmp_dir: - run_dacbench(tmp_dir, make, 1, bench=["LubyBenchmark", "SigmoidBenchmark"], seeds=[42]) + run_dacbench( + tmp_dir, + make, + 1, + bench=["LubyBenchmark", "SigmoidBenchmark"], + seeds=[42], + ) path = Path(tmp_dir) self.assertFalse(os.stat(path / "LubyBenchmark") == 0) self.assertFalse(os.stat(path / "SigmoidBenchmark") == 0) diff --git a/tests/wrappers/test_action_tracking_wrapper.py b/tests/wrappers/test_action_tracking_wrapper.py index d3037e1ed..b92a2795f 100644 --- a/tests/wrappers/test_action_tracking_wrapper.py +++ b/tests/wrappers/test_action_tracking_wrapper.py @@ -2,18 +2,13 @@ import unittest from pathlib import Path -import gymnasium as gym import numpy as np import pandas as pd - +import gymnasium as gym from dacbench.agents import StaticAgent -from dacbench.benchmarks import ( - LubyBenchmark, - FastDownwardBenchmark, - CMAESBenchmark, - ModCMABenchmark -) +from dacbench.benchmarks import (CMAESBenchmark, FastDownwardBenchmark, + LubyBenchmark, ModCMABenchmark) from dacbench.logger import Logger, load_logs, log2dataframe from dacbench.runner import run_benchmark from dacbench.wrappers import ActionFrequencyWrapper @@ -49,17 +44,17 @@ def test_logging_multi_discrete(self): expected_actions = pd.DataFrame( { - "action_0": [action[0]]*10, - "action_1": [action[1]]*10, - "action_10": [action[10]]*10, - "action_2": [action[2]]*10, - "action_3": [action[3]]*10, - "action_4": [action[4]]*10, - "action_5": [action[5]]*10, - "action_6": [action[6]]*10, - "action_7": [action[7]]*10, - "action_8": [action[8]]*10, - "action_9": [action[9]]*10, + "action_0": [action[0]] * 10, + "action_1": [action[1]] * 10, + "action_10": [action[10]] * 10, + "action_2": [action[2]] * 10, + "action_3": [action[3]] * 10, + "action_4": [action[4]] * 10, + "action_5": [action[5]] * 10, + "action_6": [action[6]] * 10, + "action_7": [action[7]] * 10, + "action_8": [action[8]] * 10, + "action_9": [action[9]] * 10, } ) @@ -75,7 +70,6 @@ def test_logging_multi_discrete(self): temp_dir.cleanup() def test_logging_discrete(self): - temp_dir = tempfile.TemporaryDirectory() seed = 0 @@ -103,8 +97,8 @@ def test_logging_discrete(self): logs = load_logs(action_logger.get_logfile()) dataframe = log2dataframe(logs, wide=True) - expected_actions = [action]*80 - + expected_actions = [action] * 80 + self.assertListEqual(dataframe.action.to_list(), expected_actions) temp_dir.cleanup() diff --git a/tests/wrappers/test_instance_sampling_wrapper.py b/tests/wrappers/test_instance_sampling_wrapper.py index ae78889d2..faf253297 100644 --- a/tests/wrappers/test_instance_sampling_wrapper.py +++ b/tests/wrappers/test_instance_sampling_wrapper.py @@ -1,8 +1,8 @@ - import unittest -from sklearn.metrics import mutual_info_score import numpy as np +from sklearn.metrics import mutual_info_score + from dacbench.benchmarks import LubyBenchmark from dacbench.wrappers import InstanceSamplingWrapper diff --git a/tests/wrappers/test_observation_wrapper.py b/tests/wrappers/test_observation_wrapper.py index 44d2b08e1..a37e2255f 100644 --- a/tests/wrappers/test_observation_wrapper.py +++ b/tests/wrappers/test_observation_wrapper.py @@ -1,4 +1,5 @@ import unittest + import numpy as np from dacbench import AbstractEnv diff --git a/tests/wrappers/test_performance_tracking_wrapper.py b/tests/wrappers/test_performance_tracking_wrapper.py index 6c72de0f3..078e10151 100644 --- a/tests/wrappers/test_performance_tracking_wrapper.py +++ b/tests/wrappers/test_performance_tracking_wrapper.py @@ -2,6 +2,7 @@ from unittest import mock import numpy as np + from dacbench.benchmarks import LubyBenchmark from dacbench.wrappers import PerformanceTrackingWrapper diff --git a/tests/wrappers/test_policy_progress_wrapper.py b/tests/wrappers/test_policy_progress_wrapper.py index bb5fe18ec..39c86f0ea 100644 --- a/tests/wrappers/test_policy_progress_wrapper.py +++ b/tests/wrappers/test_policy_progress_wrapper.py @@ -2,6 +2,7 @@ from unittest import mock import numpy as np + from dacbench.benchmarks import SigmoidBenchmark from dacbench.wrappers import PolicyProgressWrapper diff --git a/tests/wrappers/test_reward_noise_wrapper.py b/tests/wrappers/test_reward_noise_wrapper.py index 1cc33ed9d..c740dbe10 100644 --- a/tests/wrappers/test_reward_noise_wrapper.py +++ b/tests/wrappers/test_reward_noise_wrapper.py @@ -1,4 +1,3 @@ - import unittest from dacbench.benchmarks import LubyBenchmark diff --git a/tests/wrappers/test_state_tracking_wrapper.py b/tests/wrappers/test_state_tracking_wrapper.py index 9d3723dee..bebd7d156 100644 --- a/tests/wrappers/test_state_tracking_wrapper.py +++ b/tests/wrappers/test_state_tracking_wrapper.py @@ -3,12 +3,11 @@ from itertools import groupby from pathlib import Path -import gymnasium as gym import numpy as np - +import gymnasium as gym from dacbench.agents import StaticAgent -from dacbench.benchmarks import LubyBenchmark, CMAESBenchmark +from dacbench.benchmarks import CMAESBenchmark, LubyBenchmark from dacbench.logger import Logger, load_logs, log2dataframe from dacbench.runner import run_benchmark from dacbench.wrappers import StateTrackingWrapper From b1a72c68362f87911a97965b1ac76ad3241ae94c Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 12:24:16 +0100 Subject: [PATCH 21/44] check passing --- .flake8 | 1 + Makefile | 14 +++++------- dacbench/abstract_benchmark.py | 22 +++++++++---------- dacbench/abstract_env.py | 3 +-- dacbench/agents/dynamic_random_agent.py | 3 ++- dacbench/agents/simple_agents.py | 3 ++- dacbench/benchmarks/cma_benchmark.py | 2 +- dacbench/benchmarks/sgd_benchmark.py | 2 +- dacbench/benchmarks/sigmoid_benchmark.py | 3 +-- dacbench/benchmarks/theory_benchmark.py | 2 +- dacbench/benchmarks/toysgd_benchmark.py | 2 +- dacbench/container/container_utils.py | 7 +++--- dacbench/container/remote_runner.py | 6 +++-- dacbench/envs/__init__.py | 10 +++++---- dacbench/envs/geometric.py | 2 -- dacbench/envs/policies/__init__.py | 3 +-- dacbench/envs/sgd.py | 3 +-- dacbench/envs/theory.py | 4 ++-- dacbench/envs/toysgd.py | 2 +- dacbench/wrappers/__init__.py | 6 ++--- dacbench/wrappers/action_tracking_wrapper.py | 3 +-- dacbench/wrappers/episode_time_tracker.py | 3 +-- .../wrappers/multidiscrete_action_wrapper.py | 1 - dacbench/wrappers/observation_wrapper.py | 2 -- dacbench/wrappers/state_tracking_wrapper.py | 3 +-- tests/container/test_container_utils.py | 4 +--- tests/envs/test_modcma.py | 2 +- tests/envs/test_sgd.py | 2 +- tests/envs/test_theory_env.py | 1 + tests/test_abstract_benchmark.py | 12 +++++----- tests/test_abstract_env.py | 2 +- tests/test_multi_agent_interface.py | 3 +-- tests/test_run_baselines.py | 10 +++++++-- tests/test_runner.py | 3 ++- .../wrappers/test_action_tracking_wrapper.py | 10 ++++++--- tests/wrappers/test_state_tracking_wrapper.py | 2 +- 36 files changed, 81 insertions(+), 82 deletions(-) diff --git a/.flake8 b/.flake8 index 0e3fb7a05..1ea2916ff 100644 --- a/.flake8 +++ b/.flake8 @@ -4,6 +4,7 @@ exclude = dacbench/instance_sets, __pycache___, dacbench/envs/fast-downward, + dacbench/envs/rl-plan, algorithms max-line-length = 88 diff --git a/Makefile b/Makefile index 31d244342..e8ae6297b 100644 --- a/Makefile +++ b/Makefile @@ -25,11 +25,10 @@ CTAGS ?= ctags PIP ?= python -m pip MAKE ?= make BLACK ?= python -m black -ISORT ?= isort +ISORT ?= python -m isort --profile black PYDOCSTYLE ?= pydocstyle -MYPY ?= mypy PRECOMMIT ?= pre-commit -FLAKE8 ?= flake8 +FLAKE8 ?= python -m flake8 DIR := ${CURDIR} DIST := ${CURDIR}/dist @@ -44,20 +43,17 @@ check-black: $(BLACK) dacbench tests --check || : check-isort: - $(ISORT) -rc dacbench tests --check || : + $(ISORT) dacbench tests --check || : check-pydocstyle: $(PYDOCSTYLE) dacbench || : -check-mypy: - $(MYPY) dacbench || : - check-flake8: $(FLAKE8) dacbench || : $(FLAKE8) tests || : # pydocstyle does not have easy ignore rules, instead, we include as they are covered -check: check-black check-isort check-mypy check-flake8 # check-pydocstyle +check: check-black check-isort check-flake8 # check-pydocstyle pre-commit: $(PRECOMMIT) run --all-files @@ -66,7 +62,7 @@ format-black: $(BLACK) dacbench tests format-isort: - $(ISORT) -rc dacbench tests + $(ISORT) dacbench tests format: format-black format-isort diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index 0610278a7..4c214bc01 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -3,9 +3,9 @@ from types import FunctionType import numpy as np +from gymnasium import spaces from dacbench import wrappers -from gymnasium import spaces class AbstractBenchmark: @@ -107,22 +107,22 @@ def process_configspace(self, configuration_space): from ConfigSpace.configuration_space import ConfigurationSpace from ConfigSpace.hyperparameters import ( CategoricalHyperparameter, - UniformIntegerHyperparameter, - UniformFloatHyperparameter, - NormalIntegerHyperparameter, + Constant, NormalFloatHyperparameter, + NormalIntegerHyperparameter, OrdinalHyperparameter, - Constant, + UniformFloatHyperparameter, + UniformIntegerHyperparameter, UnParametrizedHyperparameter, ) from ConfigSpace.read_and_write.json import ( - _build_constant, + _build_categorical, _build_condition, - _build_ordinal, + _build_constant, _build_forbidden, - _build_categorical, - _build_normal_int, _build_normal_float, + _build_normal_int, + _build_ordinal, _build_uniform_float, _build_uniform_int, _build_unparametrized_hyperparameter, @@ -187,9 +187,9 @@ def from_json(cls, json_config): if "config_space" in config.keys(): from ConfigSpace import ConfigurationSpace from ConfigSpace.read_and_write.json import ( - _construct_hyperparameter, - _construct_forbidden, _construct_condition, + _construct_forbidden, + _construct_hyperparameter, ) if "name" in config.config_space: diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index ce53603bd..85e655e3f 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -1,8 +1,7 @@ import random -import numpy as np - import gymnasium as gym +import numpy as np from gymnasium.utils import seeding diff --git a/dacbench/agents/dynamic_random_agent.py b/dacbench/agents/dynamic_random_agent.py index 2f312834b..409ed447f 100644 --- a/dacbench/agents/dynamic_random_agent.py +++ b/dacbench/agents/dynamic_random_agent.py @@ -1,6 +1,7 @@ -from dacbench.abstract_agent import AbstractDACBenchAgent from gymnasium import spaces +from dacbench.abstract_agent import AbstractDACBenchAgent + class DynamicRandomAgent(AbstractDACBenchAgent): def __init__(self, env, switching_interval): diff --git a/dacbench/agents/simple_agents.py b/dacbench/agents/simple_agents.py index 3fc6a7f0c..a548ed981 100644 --- a/dacbench/agents/simple_agents.py +++ b/dacbench/agents/simple_agents.py @@ -1,6 +1,7 @@ -from dacbench.abstract_agent import AbstractDACBenchAgent from gymnasium import spaces +from dacbench.abstract_agent import AbstractDACBenchAgent + class RandomAgent(AbstractDACBenchAgent): def __init__(self, env): diff --git a/dacbench/benchmarks/cma_benchmark.py b/dacbench/benchmarks/cma_benchmark.py index 8830c433e..8ac963a20 100644 --- a/dacbench/benchmarks/cma_benchmark.py +++ b/dacbench/benchmarks/cma_benchmark.py @@ -4,10 +4,10 @@ import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH import numpy as np +from gymnasium import spaces from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import CMAESEnv -from gymnasium import spaces HISTORY_LENGTH = 40 INPUT_DIM = 10 diff --git a/dacbench/benchmarks/sgd_benchmark.py b/dacbench/benchmarks/sgd_benchmark.py index 1f27c8025..802b17f62 100755 --- a/dacbench/benchmarks/sgd_benchmark.py +++ b/dacbench/benchmarks/sgd_benchmark.py @@ -4,12 +4,12 @@ import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH import numpy as np +from gymnasium import spaces from torch.nn import NLLLoss from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import SGDEnv from dacbench.envs.sgd import Reward -from gymnasium import spaces DEFAULT_CFG_SPACE = CS.ConfigurationSpace() LR = CSH.UniformIntegerHyperparameter(name="learning_rate", lower=0, upper=10) diff --git a/dacbench/benchmarks/sigmoid_benchmark.py b/dacbench/benchmarks/sigmoid_benchmark.py index 67626b000..921ba7235 100644 --- a/dacbench/benchmarks/sigmoid_benchmark.py +++ b/dacbench/benchmarks/sigmoid_benchmark.py @@ -6,8 +6,7 @@ import numpy as np from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.envs import (ContinuousSigmoidEnv, ContinuousStateSigmoidEnv, - SigmoidEnv) +from dacbench.envs import ContinuousSigmoidEnv, ContinuousStateSigmoidEnv, SigmoidEnv ACTION_VALUES = (5, 10) diff --git a/dacbench/benchmarks/theory_benchmark.py b/dacbench/benchmarks/theory_benchmark.py index ed9da60de..f46098758 100644 --- a/dacbench/benchmarks/theory_benchmark.py +++ b/dacbench/benchmarks/theory_benchmark.py @@ -2,10 +2,10 @@ import ConfigSpace as CS import ConfigSpace.hyperparameters as CSH +import gymnasium as gym import numpy as np import pandas as pd -import gymnasium as gym from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs.theory import RLSEnv, RLSEnvDiscrete diff --git a/dacbench/benchmarks/toysgd_benchmark.py b/dacbench/benchmarks/toysgd_benchmark.py index 7c49df090..3dbeae1d4 100644 --- a/dacbench/benchmarks/toysgd_benchmark.py +++ b/dacbench/benchmarks/toysgd_benchmark.py @@ -4,10 +4,10 @@ import ConfigSpace.hyperparameters as CSH import numpy as np import pandas as pd +from gymnasium import spaces from dacbench.abstract_benchmark import AbstractBenchmark, objdict from dacbench.envs import ToySGDEnv -from gymnasium import spaces DEFAULT_CFG_SPACE = CS.ConfigurationSpace() LR = CSH.UniformFloatHyperparameter(name="0_log_learning_rate", lower=-10, upper=0) diff --git a/dacbench/container/container_utils.py b/dacbench/container/container_utils.py index 4da87ad00..c1223613a 100644 --- a/dacbench/container/container_utils.py +++ b/dacbench/container/container_utils.py @@ -3,11 +3,10 @@ import os import socket import time -from typing import Any, Dict, List, Tuple, Union - -import numpy as np +from typing import Any, Dict, Union import gymnasium as gym +import numpy as np class Encoder(json.JSONEncoder): @@ -96,7 +95,7 @@ def encode_space(space_obj: gym.Space): ) ) else: - raise NotImplemented( + raise NotImplementedError( f"Serialisation for type {properties['__type__']} not implemented" ) diff --git a/dacbench/container/remote_runner.py b/dacbench/container/remote_runner.py index 613ba0f59..4812ee87a 100644 --- a/dacbench/container/remote_runner.py +++ b/dacbench/container/remote_runner.py @@ -18,8 +18,10 @@ from dacbench.abstract_benchmark import AbstractBenchmark from dacbench.argument_parsing import PathType from dacbench.container.container_utils import wait_for_unixsocket -from dacbench.container.remote_env import (RemoteEnvironmentClient, - RemoteEnvironmentServer) +from dacbench.container.remote_env import ( + RemoteEnvironmentClient, + RemoteEnvironmentServer, +) # Needed in order to combine event loops of name_server and daemon Pyro4.config.SERVERTYPE = "multiplex" diff --git a/dacbench/envs/__init__.py b/dacbench/envs/__init__.py index 432a5b343..32fc2b6f7 100644 --- a/dacbench/envs/__init__.py +++ b/dacbench/envs/__init__.py @@ -5,8 +5,11 @@ from dacbench.envs.fast_downward import FastDownwardEnv from dacbench.envs.geometric import GeometricEnv from dacbench.envs.luby import LubyEnv, luby_gen -from dacbench.envs.sigmoid import (ContinuousSigmoidEnv, - ContinuousStateSigmoidEnv, SigmoidEnv) +from dacbench.envs.sigmoid import ( + ContinuousSigmoidEnv, + ContinuousStateSigmoidEnv, + SigmoidEnv, +) from dacbench.envs.toysgd import ToySGDEnv __all__ = [ @@ -19,7 +22,6 @@ ] - cma_spec = importlib.util.find_spec("cma") found = cma_spec is not None if found: @@ -58,7 +60,7 @@ theory_spec = importlib.util.find_spec("uuid") found = theory_spec is not None if found: - from dacbench.envs.theory import RLSEnvDiscrete, RLSEnv + from dacbench.envs.theory import RLSEnv, RLSEnvDiscrete __all__.append("RLSEnv") __all__.append("RLSEnvDiscrete") diff --git a/dacbench/envs/geometric.py b/dacbench/envs/geometric.py index 5157c4f88..0c8bcec12 100644 --- a/dacbench/envs/geometric.py +++ b/dacbench/envs/geometric.py @@ -3,7 +3,6 @@ Original environment authors: Rasmus von Glahn """ import bisect -import itertools import math import os from typing import Dict, List, Tuple @@ -18,7 +17,6 @@ sns.set_theme(style="darkgrid") - class GeometricEnv(AbstractEnv): """ Environment for tracing different curves that are orthogonal to each other diff --git a/dacbench/envs/policies/__init__.py b/dacbench/envs/policies/__init__.py index 50e62adf0..6a1f123cf 100644 --- a/dacbench/envs/policies/__init__.py +++ b/dacbench/envs/policies/__init__.py @@ -1,8 +1,7 @@ from dacbench.envs.policies.csa_cma import csa from dacbench.envs.policies.optimal_fd import get_optimum as optimal_fd from dacbench.envs.policies.optimal_luby import get_optimum as optimal_luby -from dacbench.envs.policies.optimal_sigmoid import \ - get_optimum as optimal_sigmoid +from dacbench.envs.policies.optimal_sigmoid import get_optimum as optimal_sigmoid OPTIMAL_POLICIES = { "LubyBenchmark": optimal_luby, diff --git a/dacbench/envs/sgd.py b/dacbench/envs/sgd.py index ea981ad4d..41e66638b 100644 --- a/dacbench/envs/sgd.py +++ b/dacbench/envs/sgd.py @@ -10,7 +10,6 @@ import torch from backpack import backpack, extend from backpack.extensions import BatchGrad -from numpy import float32 from torchvision import datasets, transforms from dacbench import AbstractEnv @@ -839,7 +838,7 @@ def generate_instance_file(self, file_name, mode="test", n=100): [32, 32, 64, 64], ), ] - if mode is "test": + if mode == "test": seed_list = [random.randrange(start=0, stop=1e9) for _ in range(n)] for i in range(len(architectures)): diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index 7eaea981e..2937c9c7e 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -3,9 +3,9 @@ from collections import deque from copy import deepcopy +import gymnasium as gym import numpy as np -import gymnasium as gym from dacbench import AbstractEnv @@ -23,7 +23,7 @@ def initialise_with_fixed_number_of_bits(self, k, rng=np.random.default_rng()): nbits = self.data.sum() if nbits < k: ids = rng.choice( - np.where(self.data == False)[0], size=k - nbits, replace=False + np.where(self.data is False)[0], size=k - nbits, replace=False ) self.data[ids] = True self.eval() diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index 0ddafc2a0..abdf0a77b 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -1,4 +1,4 @@ -from typing import Dict, Optional, Tuple, Union +from typing import Dict, Tuple, Union import numpy as np import pandas as pd diff --git a/dacbench/wrappers/__init__.py b/dacbench/wrappers/__init__.py index a266392c1..dd13698a0 100644 --- a/dacbench/wrappers/__init__.py +++ b/dacbench/wrappers/__init__.py @@ -1,11 +1,9 @@ from dacbench.wrappers.action_tracking_wrapper import ActionFrequencyWrapper from dacbench.wrappers.episode_time_tracker import EpisodeTimeWrapper from dacbench.wrappers.instance_sampling_wrapper import InstanceSamplingWrapper -from dacbench.wrappers.multidiscrete_action_wrapper import \ - MultiDiscreteActionWrapper +from dacbench.wrappers.multidiscrete_action_wrapper import MultiDiscreteActionWrapper from dacbench.wrappers.observation_wrapper import ObservationWrapper -from dacbench.wrappers.performance_tracking_wrapper import \ - PerformanceTrackingWrapper +from dacbench.wrappers.performance_tracking_wrapper import PerformanceTrackingWrapper from dacbench.wrappers.policy_progress_wrapper import PolicyProgressWrapper from dacbench.wrappers.reward_noise_wrapper import RewardNoiseWrapper from dacbench.wrappers.state_tracking_wrapper import StateTrackingWrapper diff --git a/dacbench/wrappers/action_tracking_wrapper.py b/dacbench/wrappers/action_tracking_wrapper.py index 0c8ac8666..2a6e5bd32 100644 --- a/dacbench/wrappers/action_tracking_wrapper.py +++ b/dacbench/wrappers/action_tracking_wrapper.py @@ -1,9 +1,8 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas - from gymnasium import Wrapper, spaces +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/episode_time_tracker.py b/dacbench/wrappers/episode_time_tracker.py index 182539df0..267332197 100644 --- a/dacbench/wrappers/episode_time_tracker.py +++ b/dacbench/wrappers/episode_time_tracker.py @@ -3,9 +3,8 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas - from gymnasium import Wrapper +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/multidiscrete_action_wrapper.py b/dacbench/wrappers/multidiscrete_action_wrapper.py index 642d88acc..c4747f51a 100644 --- a/dacbench/wrappers/multidiscrete_action_wrapper.py +++ b/dacbench/wrappers/multidiscrete_action_wrapper.py @@ -1,7 +1,6 @@ import itertools import numpy as np - from gymnasium import Wrapper, spaces diff --git a/dacbench/wrappers/observation_wrapper.py b/dacbench/wrappers/observation_wrapper.py index 5f2ac192c..55847fcf9 100644 --- a/dacbench/wrappers/observation_wrapper.py +++ b/dacbench/wrappers/observation_wrapper.py @@ -1,5 +1,3 @@ -from collections.abc import Iterable - import numpy as np from gym import Wrapper, spaces diff --git a/dacbench/wrappers/state_tracking_wrapper.py b/dacbench/wrappers/state_tracking_wrapper.py index 95de9cec9..367ae99b6 100644 --- a/dacbench/wrappers/state_tracking_wrapper.py +++ b/dacbench/wrappers/state_tracking_wrapper.py @@ -1,9 +1,8 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas - from gymnasium import Wrapper, spaces +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/tests/container/test_container_utils.py b/tests/container/test_container_utils.py index 54d481191..cb25019dc 100644 --- a/tests/container/test_container_utils.py +++ b/tests/container/test_container_utils.py @@ -1,11 +1,9 @@ import json import unittest -import numpy as np +from gymnasium.spaces import Box, Dict, Discrete, MultiBinary, MultiDiscrete, Tuple from dacbench.container.container_utils import Decoder, Encoder -from gymnasium.spaces import (Box, Dict, Discrete, MultiBinary, MultiDiscrete, - Tuple) class TestEncoder(unittest.TestCase): diff --git a/tests/envs/test_modcma.py b/tests/envs/test_modcma.py index bf4fc487f..2b414e547 100644 --- a/tests/envs/test_modcma.py +++ b/tests/envs/test_modcma.py @@ -1,11 +1,11 @@ import unittest import numpy as np +from gymnasium import spaces from dacbench import AbstractEnv from dacbench.abstract_benchmark import objdict from dacbench.envs import ModCMAEnv -from gymnasium import spaces class TestModCMAEnv(unittest.TestCase): diff --git a/tests/envs/test_sgd.py b/tests/envs/test_sgd.py index 1aaa7c3c8..777fff408 100644 --- a/tests/envs/test_sgd.py +++ b/tests/envs/test_sgd.py @@ -4,7 +4,7 @@ import numpy as np from dacbench import AbstractEnv -from dacbench.abstract_benchmark import AbstractBenchmark, objdict +from dacbench.abstract_benchmark import objdict from dacbench.benchmarks.sgd_benchmark import SGD_DEFAULTS, SGDBenchmark from dacbench.envs.sgd import Reward, SGDEnv from dacbench.wrappers import ObservationWrapper diff --git a/tests/envs/test_theory_env.py b/tests/envs/test_theory_env.py index 20fe10024..668bc3754 100644 --- a/tests/envs/test_theory_env.py +++ b/tests/envs/test_theory_env.py @@ -1,6 +1,7 @@ import unittest import gymnasium as gym + from dacbench.benchmarks import TheoryBenchmark diff --git a/tests/test_abstract_benchmark.py b/tests/test_abstract_benchmark.py index fca4c0514..c067d5880 100644 --- a/tests/test_abstract_benchmark.py +++ b/tests/test_abstract_benchmark.py @@ -4,13 +4,15 @@ import unittest import numpy as np +from gymnasium.spaces import Box, Dict, Discrete, MultiBinary, MultiDiscrete from dacbench.abstract_benchmark import AbstractBenchmark, objdict -from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import \ - random_reward -from dacbench.challenge_benchmarks.state_space_challenge.random_states import \ - small_random_sigmoid_state -from gymnasium.spaces import Box, Dict, Discrete, MultiBinary, MultiDiscrete +from dacbench.challenge_benchmarks.reward_quality_challenge.reward_functions import ( + random_reward, +) +from dacbench.challenge_benchmarks.state_space_challenge.random_states import ( + small_random_sigmoid_state, +) class TestAbstractBenchmark(unittest.TestCase): diff --git a/tests/test_abstract_env.py b/tests/test_abstract_env.py index f6280f86b..69b6e846b 100644 --- a/tests/test_abstract_env.py +++ b/tests/test_abstract_env.py @@ -1,9 +1,9 @@ import unittest import numpy as np +from gymnasium import spaces from dacbench.abstract_env import AbstractEnv -from gymnasium import spaces class TestAbstractEnv(unittest.TestCase): diff --git a/tests/test_multi_agent_interface.py b/tests/test_multi_agent_interface.py index c72929d60..0c0c21719 100644 --- a/tests/test_multi_agent_interface.py +++ b/tests/test_multi_agent_interface.py @@ -2,8 +2,7 @@ import numpy as np -from dacbench.benchmarks import (ModCMABenchmark, SigmoidBenchmark, - ToySGDBenchmark) +from dacbench.benchmarks import ModCMABenchmark, SigmoidBenchmark, ToySGDBenchmark from dacbench.envs import SigmoidEnv, ToySGDEnv diff --git a/tests/test_run_baselines.py b/tests/test_run_baselines.py index 6c2eb1087..74d2d726c 100644 --- a/tests/test_run_baselines.py +++ b/tests/test_run_baselines.py @@ -3,8 +3,14 @@ from pathlib import Path from dacbench.logger import load_logs, log2dataframe -from dacbench.run_baselines import (DISCRETE_ACTIONS, main, run_dynamic_policy, - run_optimal, run_random, run_static) +from dacbench.run_baselines import ( + DISCRETE_ACTIONS, + main, + run_dynamic_policy, + run_optimal, + run_random, + run_static, +) class TestRunBaselines(unittest.TestCase): diff --git a/tests/test_runner.py b/tests/test_runner.py index 7cd33ecdd..9df8fd1a8 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -6,11 +6,12 @@ import matplotlib import numpy as np import pytest +from gymnasium import spaces from dacbench.abstract_agent import AbstractDACBenchAgent + # import shutil from dacbench.runner import run_dacbench # , plot_results -from gymnasium import spaces matplotlib.use("Agg") diff --git a/tests/wrappers/test_action_tracking_wrapper.py b/tests/wrappers/test_action_tracking_wrapper.py index b92a2795f..05f28f486 100644 --- a/tests/wrappers/test_action_tracking_wrapper.py +++ b/tests/wrappers/test_action_tracking_wrapper.py @@ -2,13 +2,17 @@ import unittest from pathlib import Path +import gymnasium as gym import numpy as np import pandas as pd -import gymnasium as gym from dacbench.agents import StaticAgent -from dacbench.benchmarks import (CMAESBenchmark, FastDownwardBenchmark, - LubyBenchmark, ModCMABenchmark) +from dacbench.benchmarks import ( + CMAESBenchmark, + FastDownwardBenchmark, + LubyBenchmark, + ModCMABenchmark, +) from dacbench.logger import Logger, load_logs, log2dataframe from dacbench.runner import run_benchmark from dacbench.wrappers import ActionFrequencyWrapper diff --git a/tests/wrappers/test_state_tracking_wrapper.py b/tests/wrappers/test_state_tracking_wrapper.py index bebd7d156..8301f1f04 100644 --- a/tests/wrappers/test_state_tracking_wrapper.py +++ b/tests/wrappers/test_state_tracking_wrapper.py @@ -3,9 +3,9 @@ from itertools import groupby from pathlib import Path +import gymnasium as gym import numpy as np -import gymnasium as gym from dacbench.agents import StaticAgent from dacbench.benchmarks import CMAESBenchmark, LubyBenchmark from dacbench.logger import Logger, load_logs, log2dataframe From d9174d2a4346e319cda593ec8eeb3bdcee99c160 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 12:24:32 +0100 Subject: [PATCH 22/44] remove mypy --- .pre-commit-config.yaml | 2 +- setup.cfg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ee172b4c..eebbe0375 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: rev: stable hooks: - id: black - language_version: python3.6 + language_version: python3.10 exclude: dacbench/envs/fast-downward - repo: https://gitlab.com/pycqa/flake8 rev: 3.8.4 diff --git a/setup.cfg b/setup.cfg index dbf53d01c..edfd4aebc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -47,6 +47,7 @@ dev = black==23.1.0 scikit-learn==1.2.2 flake8==6.0.0 + isort==5.12.0 pytest==7.1.0 pytest-html==3.2.0 pytest-cov==4.0.0 From e1552be763107de517682039ea4da07dde3c4926 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 16:10:19 +0100 Subject: [PATCH 23/44] Docstring formatting --- .pre-commit-config.yaml | 6 +- Makefile | 4 +- dacbench/abstract_agent.py | 22 +- dacbench/abstract_benchmark.py | 163 +++++++--- dacbench/abstract_env.py | 118 +++++-- dacbench/argument_parsing.py | 27 +- dacbench/container/container_utils.py | 22 +- dacbench/container/remote_env.py | 17 + dacbench/container/remote_runner.py | 98 +++--- .../geometric/SampleGeometricInstances.py | 11 +- dacbench/logger.py | 303 ++++++++---------- dacbench/plotting.py | 31 +- dacbench/run_baselines.py | 82 +++++ dacbench/runner.py | 17 +- dacbench/wrappers/action_tracking_wrapper.py | 20 +- dacbench/wrappers/episode_time_tracker.py | 22 +- .../wrappers/instance_sampling_wrapper.py | 23 +- .../wrappers/multidiscrete_action_wrapper.py | 11 +- dacbench/wrappers/observation_wrapper.py | 21 +- .../wrappers/performance_tracking_wrapper.py | 22 +- dacbench/wrappers/policy_progress_wrapper.py | 19 +- dacbench/wrappers/reward_noise_wrapper.py | 21 +- dacbench/wrappers/state_tracking_wrapper.py | 30 +- pyproject.toml | 5 + 24 files changed, 709 insertions(+), 406 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eebbe0375..b8a863aa2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,4 +9,8 @@ repos: rev: 3.8.4 hooks: - id: flake8 - +- repo: https://github.com/PyCQA/pydocstyle + rev: master + hooks: + - id: pydocstyle + exclude: 'dacbench/envs/rl-plan/*' diff --git a/Makefile b/Makefile index e8ae6297b..da093e2e0 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ PIP ?= python -m pip MAKE ?= make BLACK ?= python -m black ISORT ?= python -m isort --profile black -PYDOCSTYLE ?= pydocstyle +PYDOCSTYLE ?= python -m pydocstyle PRECOMMIT ?= pre-commit FLAKE8 ?= python -m flake8 @@ -53,7 +53,7 @@ check-flake8: $(FLAKE8) tests || : # pydocstyle does not have easy ignore rules, instead, we include as they are covered -check: check-black check-isort check-flake8 # check-pydocstyle +check: check-black check-isort check-flake8 check-pydocstyle pre-commit: $(PRECOMMIT) run --all-files diff --git a/dacbench/abstract_agent.py b/dacbench/abstract_agent.py index 79c2cf755..f8f282d82 100644 --- a/dacbench/abstract_agent.py +++ b/dacbench/abstract_agent.py @@ -1,23 +1,24 @@ class AbstractDACBenchAgent: - """Abstract class to implement for use with the runner function""" + """Abstract class to implement for use with the runner function.""" def __init__(self, env): """ - Initialize agent + Initialize agent. Parameters - ------- + ---------- env : gym.Env Environment to train on + """ pass def act(self, state, reward): """ - Compute and return environment action + Compute and return environment action. Parameters - ------- + ---------- state Environment state reward @@ -27,31 +28,34 @@ def act(self, state, reward): ------- action Action to take + """ raise NotImplementedError def train(self, next_state, reward): """ - Train during episode if needed (pass if not) + Train during episode if needed (pass if not). Parameters - ------- + ---------- next_state Environment state after step reward Environment reward + """ raise NotImplementedError def end_episode(self, state, reward): """ - End of episode training if needed (pass if not) + End of episode training if needed (pass if not). Parameters - ------- + ---------- state Environment state reward Environment reward + """ raise NotImplementedError diff --git a/dacbench/abstract_benchmark.py b/dacbench/abstract_benchmark.py index 4c214bc01..22bb8ca3e 100644 --- a/dacbench/abstract_benchmark.py +++ b/dacbench/abstract_benchmark.py @@ -9,20 +9,19 @@ class AbstractBenchmark: - """ - Abstract template for benchmark classes - """ + """Abstract template for benchmark classes.""" def __init__(self, config_path=None, config: "objdict" = None): """ - Initialize benchmark class + Initialize benchmark class. Parameters - ------- + ---------- config_path : str Path to load configuration from (if read from file) config : objdict Object dict containing the config + """ if config is not None and config_path is not None: raise ValueError("Both path to config and config where provided") @@ -37,23 +36,25 @@ def __init__(self, config_path=None, config: "objdict" = None): def get_config(self): """ - Return current configuration + Return current configuration. Returns ------- dict Current config + """ return self.config def serialize_config(self): """ - Save configuration to json + Save configuration to json. Parameters ---------- path : str File to save config to + """ conf = self.config.copy() if "observation_space_type" in self.config: @@ -100,10 +101,7 @@ def serialize_config(self): return conf def process_configspace(self, configuration_space): - """ - This is largely the builting cs.json.write method, but doesn't save the result directly - If this is ever implemented in cs, we can replace this method - """ + """This is largely the builting cs.json.write method, but doesn't save the result directly. If this is ever implemented in cs, we can replace this method.""" from ConfigSpace.configuration_space import ConfigurationSpace from ConfigSpace.hyperparameters import ( CategoricalHyperparameter, @@ -183,6 +181,7 @@ def process_configspace(self, configuration_space): @classmethod def from_json(cls, json_config): + """Get config from json dict.""" config = objdict(json.loads(json_config)) if "config_space" in config.keys(): from ConfigSpace import ConfigurationSpace @@ -226,22 +225,25 @@ def from_json(cls, json_config): return cls(config=config) def to_json(self): + """Write config to json.""" conf = self.serialize_config() - for k in conf: - print(k) - print(conf[k]) - from copy import deepcopy - - del_conf = deepcopy(conf)[k] - json.dumps(del_conf) return json.dumps(conf) def save_config(self, path): + """Write config to path.""" conf = self.serialize_config() with open(path, "w") as fp: json.dump(conf, fp, default=lambda o: "not serializable") def jsonify_wrappers(self): + """ + Write wrapper description to list. + + Returns + ------- + list + + """ wrappers = [] for func in self.wrap_funcs: args = func.args @@ -265,6 +267,15 @@ def jsonify_wrappers(self): return wrappers def dejson_wrappers(self, wrapper_list): + """ + Load wrapper from list. + + Parameters + ---------- + wrapper_list : list + wrapper description to load + + """ for i in range(len(wrapper_list)): import importlib @@ -287,33 +298,37 @@ def dejson_wrappers(self, wrapper_list): @staticmethod def __import_from(module: str, name: str): """ - Imports the class / function / ... with name from module + Imports the class / function / ... with name from module. + Parameters ---------- - module - name + module : str + module to import from + name : str + name to import Returns ------- the imported object + """ module = __import__(module, fromlist=[name]) return getattr(module, name) @classmethod def class_to_str(cls): + """Get string name from class.""" return cls.__module__, cls.__name__ @staticmethod def __decorate_config_with_functions(conf: dict): """ - Replaced the stringified functions with the callable objects + Replaced the stringified functions with the callable objects. + Parameters ---------- - config - - Returns - ------- + conf : + config to parse """ for key, value in { @@ -328,16 +343,17 @@ def __decorate_config_with_functions(conf: dict): @staticmethod def __stringify_functions(conf: dict) -> dict: """ - Replaced all callables in the config with a - triple ('function', module_name, function_name) + Replaced all callables in the config with a triple ('function', module_name, function_name). Parameters ---------- - config + conf : dict + config to parse Returns ------- modified dict + """ for key, value in { k: v for k, v in conf.items() if isinstance(v, FunctionType) @@ -346,6 +362,15 @@ def __stringify_functions(conf: dict) -> dict: return conf def space_to_list(self, space): + """ + Make list from gym space. + + Parameters + ---------- + space: gym.spaces.Space + space to parse + + """ res = [] if isinstance(space, spaces.Box): res.append("Box") @@ -366,9 +391,19 @@ def space_to_list(self, space): return res def list_to_space(self, space_list): + """ + Make gym space from list. + + Parameters + ---------- + space_list: list + list to space-ify + + """ if space_list[0] == "Dict": args = self.dictify_json(space_list[1]) space = getattr(spaces, space_list[0])(args) + elif len(space_list) == 2: space = getattr(spaces, space_list[0])(*space_list[1]) else: @@ -379,6 +414,15 @@ def list_to_space(self, space_list): return space def jsonify_dict_space(self, dict_space): + """ + Gym spaces to json dict. + + Parameters + ---------- + dict_space : dict + space dict + + """ keys = [] types = [] arguments = [] @@ -403,6 +447,15 @@ def jsonify_dict_space(self, dict_space): return [keys, types, arguments] def dictify_json(self, dict_list): + """ + Json to dict structure for gym spaces. + + Parameters + ---------- + dict_list: list + list of dicts + + """ dict_space = {} keys, types, args = dict_list for k, type, args_ in zip(keys, types, args): @@ -418,6 +471,15 @@ def dictify_json(self, dict_list): return dict_space def load_config(self, config: "objdict"): + """ + Load config. + + Parameters + ---------- + config: objdict + config to load + + """ self.config = config if "observation_space_type" in self.config: # Types have to be numpy dtype (for gym spaces)s @@ -461,12 +523,13 @@ def load_config(self, config: "objdict"): def read_config_file(self, path): """ - Read configuration from file + Read configuration from file. Parameters ---------- path : str Path to config file + """ with open(path, "r") as fp: config = objdict(json.load(fp)) @@ -475,29 +538,31 @@ def read_config_file(self, path): def get_environment(self): """ - Make benchmark environment + Make benchmark environment. Returns ------- env : gym.Env Benchmark environment + """ raise NotImplementedError def set_seed(self, seed): """ - Set environment seed + Set environment seed. Parameters ---------- seed : int New seed + """ self.config["seed"] = seed def set_action_space(self, kind, args): """ - Change action space + Change action space. Parameters ---------- @@ -505,13 +570,14 @@ def set_action_space(self, kind, args): Name of action space class args: list List of arguments to pass to action space class + """ self.config["action_space"] = kind self.config["action_space_args"] = args def set_observation_space(self, kind, args, data_type): """ - Change observation_space + Change observation_space. Parameters ---------- @@ -521,54 +587,60 @@ def set_observation_space(self, kind, args, data_type): List of arguments to pass to observation space class data_type : type Data type of observation space + """ self.config["observation_space"] = kind self.config["observation_space_args"] = args self.config["observation_space_type"] = data_type def register_wrapper(self, wrap_func): + """ + Register wrapper. + + Parameters + ---------- + wrap_func : function + wrapper init function + + """ if isinstance(wrap_func, list): self.wrap_funcs.append(*wrap_func) else: self.wrap_funcs.append(wrap_func) def __eq__(self, other): + """Check for equality.""" return type(self) == type(other) and self.config == other.config # This code is taken from https://goodcode.io/articles/python-dict-object/ class objdict(dict): - """ - Modified dict to make config changes more flexible - """ + """Modified dict to make config changes more flexible.""" def __getattr__(self, name): + """Get attribute.""" if name in self: return self[name] else: raise AttributeError("No such attribute: " + name) def __setattr__(self, name, value): + """Set attribute.""" self[name] = value def __delattr__(self, name): + """Delete attribute.""" if name in self: del self[name] else: raise AttributeError("No such attribute: " + name) def copy(self): + """Copy self.""" return objdict(**super().copy()) def __eq__(self, other): - """return isinstance(other, dict) \ - and set(other.keys()) == set(self.keys()) \ - and all( - np.array_equal(self[key], other[key]) - if any(isinstance(obj[key], np.ndarray) for obj in (self, other)) - else other[key] == self[key] - for key in self.keys() - )""" + """Check for equality.""" if not isinstance(other, dict): return False if not set(other.keys()) == set(self.keys()): @@ -582,4 +654,5 @@ def __eq__(self, other): return all(truth) def __ne__(self, other): + """Check for inequality.""" return not self == other diff --git a/dacbench/abstract_env.py b/dacbench/abstract_env.py index 85e655e3f..7459ec2e3 100644 --- a/dacbench/abstract_env.py +++ b/dacbench/abstract_env.py @@ -6,19 +6,18 @@ class AbstractEnv(gym.Env): - """ - Abstract template for environments - """ + """Abstract template for environments.""" def __init__(self, config): """ - Initialize environment + Initialize environment. Parameters - ------- + ---------- config : dict Environment configuration If to seed the action space as well + """ super(AbstractEnv, self).__init__() self.config = config @@ -142,12 +141,13 @@ def __init__(self, config): def step_(self): """ - Pre-step function for step count and cutoff + Pre-step function for step count and cutoff. Returns ------- bool End of episode + """ truncated = False self.c_step += 1 @@ -156,10 +156,7 @@ def step_(self): return truncated def reset_(self, seed=0, options={}, instance=None, instance_id=None, scheme=None): - """ - Pre-reset function for progressing through the instance set - Will either use round robin, random or no progression scheme - """ + """Pre-reset function for progressing through the instance set.Will either use round robin, random or no progression scheme.""" if seed is not None: self.seed(seed, self.config.get("seed_action_space", False)) self.c_step = 0 @@ -169,16 +166,17 @@ def reset_(self, seed=0, options={}, instance=None, instance_id=None, scheme=Non def use_next_instance(self, instance=None, instance_id=None, scheme=None): """ - Changes instance according to chosen instance progession + Changes instance according to chosen instance progession. Parameters - ------- + ---------- instance Instance specification for potentional new instances instance_id ID of the instance to switch to scheme Update scheme for this progression step (either round robin, random or no progression) + """ if instance is not None: self.instance = instance @@ -195,10 +193,10 @@ def use_next_instance(self, instance=None, instance_id=None, scheme=None): def step(self, action): """ - Execute environment step + Execute environment step. Parameters - ------- + ---------- action Action to take @@ -214,15 +212,16 @@ def step(self, action): Run timed out flag info : dict Additional metainfo + """ raise NotImplementedError def reset(self, seed: int = None): """ - Reset environment + Reset environment. Parameters - ------- + ---------- seed Seed for the environment @@ -232,23 +231,25 @@ def reset(self, seed: int = None): Environment state info: dict Additional metainfo + """ raise NotImplementedError def get_inst_id(self): """ - Return instance ID + Return instance ID. Returns ------- int ID of current instance + """ return self.inst_id def get_instance_set(self): """ - Return instance set + Return instance set. Returns ------- @@ -260,53 +261,57 @@ def get_instance_set(self): def get_instance(self): """ - Return current instance + Return current instance. Returns ------- type flexible Currently used instance + """ return self.instance def set_inst_id(self, inst_id): """ - Change current instance ID + Change current instance ID. Parameters ---------- inst_id : int New instance index + """ self.inst_id = inst_id self.instance_index = self.instance_id_list.index(self.inst_id) def set_instance_set(self, inst_set): """ - Change instance set + Change instance set. Parameters ---------- inst_set: list New instance set + """ self.instance_set = inst_set self.instance_id_list = sorted(list(self.instance_set.keys())) def set_instance(self, instance): """ - Change currently used instance + Change currently used instance. Parameters ---------- instance: New instance + """ self.instance = instance def seed(self, seed=None, seed_action_space=False): """ - Set rng seed + Set rng seed. Parameters ---------- @@ -314,8 +319,8 @@ def seed(self, seed=None, seed_action_space=False): seed for rng seed_action_space: bool, default False if to seed the action space as well - """ + """ self.initial_seed = seed # maybe one should use the seed generated by seeding.np_random(seed) but it can be to large see issue https://github.com/openai/gym/issues/2210 random.seed(seed) @@ -329,9 +334,7 @@ def seed(self, seed=None, seed_action_space=False): return [seed] def use_test_set(self): - """ - Change to test instance set - """ + """Change to test instance set.""" if self.test_set is None: raise ValueError( "No test set was provided, please check your benchmark config." @@ -349,9 +352,7 @@ def use_test_set(self): self.instance = self.test_instance def use_training_set(self): - """ - Change to training instance set - """ + """Change to training instance set.""" self.test = False self.test_set = self.instance_set self.test_instance_id_list = self.instance_id_list @@ -365,15 +366,18 @@ def use_training_set(self): class AbstractMADACEnv(AbstractEnv): + """Multi-Agent version of DAC environment.""" + def __init__(self, config): """ - Initialize environment + Initialize environment. Parameters - ------- + ---------- config : dict Environment configuration If to seed the action space as well + """ super(AbstractMADACEnv, self).__init__(config) self.multi_agent = False @@ -435,9 +439,26 @@ def __init__(self, config): self.action_spaces[a] = subspace def multi_agent_reset(self, seed: int = None): + """ + Reset env, but don't return observations. + + Parameters + ---------- + seed : int + seed to use + + """ self.observation, self.info = self.env_reset(seed) def last(self): + """ + Get current step data. + + Returns + ------- + np.array, float, bool, bool, dict + + """ return ( self.observation, self.reward, @@ -447,6 +468,15 @@ def last(self): ) def multi_agent_step(self, action): + """ + Step for a single hyperparameter. + + Parameters + ---------- + action + the action in the current agent's dimension + + """ self.action[self.current_agent] = action self.current_agent = self.agents.index(self.current_agent) + 1 if self.current_agent >= len(self.agents): @@ -460,6 +490,15 @@ def multi_agent_step(self, action): self.current_agent = self.agents[0] def register_agent(self, agent_id): + """ + Add agent. + + Parameters + ---------- + agent_id : int + id of the agent to add + + """ if type(agent_id) == str: if len(agent_id) > 1: if agent_id in self.hp_names: @@ -473,19 +512,31 @@ def register_agent(self, agent_id): self.current_agent = agent_id def remove_agent(self, agent_id): + """ + Remove agent. + + Parameters + ---------- + agent_id : int + id of the agent to remove + + """ if agent_id in self.agents: self.agents.remove(agent_id) @property def num_agents(self): + """Current number of agents.""" return len(self.agents) @property def agent_selection(self): + """Current agent.""" return self.current_agent @property def infos(self): + """Current infos per agent.""" infos = {} for a in self.agents: infos[a] = self.info @@ -493,6 +544,7 @@ def infos(self): @property def rewards(self): + """Current rewards values per agent.""" rewards = {} for a in self.agents: rewards[a] = self.rewards @@ -500,6 +552,7 @@ def rewards(self): @property def terminations(self): + """Current termination values per agent.""" terminations = {} for a in self.agents: terminations[a] = self.termination @@ -507,6 +560,7 @@ def terminations(self): @property def truncations(self): + """Current truncation values per agent.""" truncations = {} for a in self.agents: truncations[a] = self.truncation diff --git a/dacbench/argument_parsing.py b/dacbench/argument_parsing.py index 0d492fa51..6285d615d 100644 --- a/dacbench/argument_parsing.py +++ b/dacbench/argument_parsing.py @@ -11,21 +11,21 @@ class PathType(object): def __init__(self, exists=True, type="file", dash_ok=True): """ + Initialize Path. Parameters ---------- - exists : bool - True: a path that does exist - False: a path that does not exist, in a valid parent directory - None: don't care - type : str - file, dir, symlink, socket, None, or a function returning True for valid paths - None: don't care - dash_ok: whether to allow "-" as stdin/stdout + True: a path that does exist + False: a path that does not exist, in a valid parent directory + None: don't care + type : str + file, dir, symlink, socket, None, or a function returning True for valid paths + None: don't care + dash_ok: bool + whether to allow "-" as stdin/stdout """ - assert exists in (True, False, None) assert type in ("file", "dir", "symlink", "socket", None) or hasattr( type, "__call__" @@ -36,6 +36,15 @@ def __init__(self, exists=True, type="file", dash_ok=True): self._dash_ok = dash_ok def __call__(self, string: str): + """ + Call Path. + + Parameters + ---------- + string : str + string to check + + """ if string == "-": # the special argument "-" means sys.std{in,out} if self._type == "dir": diff --git a/dacbench/container/container_utils.py b/dacbench/container/container_utils.py index c1223613a..f564c3ead 100644 --- a/dacbench/container/container_utils.py +++ b/dacbench/container/container_utils.py @@ -10,13 +10,16 @@ class Encoder(json.JSONEncoder): - """Json Encoder to save tuple and or numpy arrays | numpy floats / integer. + """ + Json Encoder to save tuple and or numpy arrays | numpy floats / integer. + Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py Serializing tuple/numpy array may not work. We need to annotate those types, to reconstruct them correctly. """ @staticmethod def hint(item): + """Encode different object types.""" # Annotate the different item types if isinstance(item, tuple): return {"__type__": "tuple", "__items__": [Encoder.hint(e) for e in item]} @@ -42,10 +45,12 @@ def hint(item): # pylint: disable=arguments-differ def encode(self, obj): + """Generic encode.""" return super(Encoder, self).encode(Encoder.hint(obj)) @staticmethod def encode_space(space_obj: gym.Space): + """Encode gym space.""" properties = [ ( "__type__", @@ -103,17 +108,16 @@ def encode_space(space_obj: gym.Space): class Decoder(json.JSONDecoder): - """ - Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py - - """ + """Adapted from: https://github.com/automl/HPOBench/blob/master/hpobench/util/container_utils.py""" def __init__(self, *args, **kwargs): + """Init decoder.""" json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) def object_hook( self, obj: Any ) -> Union[Union[tuple, np.ndarray, float, float, int], Any]: + """Encode different types of objects.""" if "__type__" in obj: __type = obj["__type__"] if __type == "tuple": @@ -131,6 +135,7 @@ def object_hook( return obj def decode_space(self, space_dict: Dict) -> gym.Space: + """Dict to gym space.""" __type = space_dict["__type__"] __class = getattr(gym.spaces, __type.split(".")[-1]) @@ -165,6 +170,7 @@ def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: :param path: path to the socket :param timeout: timeout in seconds :return: + """ start = time.time() while not os.path.exists(path): @@ -177,8 +183,7 @@ def wait_for_unixsocket(path: str, timeout: float = 10.0) -> None: def wait_for_port(port, host="localhost", timeout=5.0): """ - Taken from https://gist.github.com/butla/2d9a4c0f35ea47b7452156c96a4e7b12 - Wait until a port starts accepting TCP connections. + Taken from https://gist.github.com/butla/2d9a4c0f35ea47b7452156c96a4e7b12 - Wait until a port starts accepting TCP connections. Parameters ---------- @@ -189,9 +194,10 @@ def wait_for_port(port, host="localhost", timeout=5.0): timeout : float Timeout in seconds. - Raises: + Raises ------ TimeoutError: The port isn't accepting connection after time specified in `timeout`. + """ start_time = time.perf_counter() while True: diff --git a/dacbench/container/remote_env.py b/dacbench/container/remote_env.py index b1b6876c1..5ff000f5e 100644 --- a/dacbench/container/remote_env.py +++ b/dacbench/container/remote_env.py @@ -29,47 +29,61 @@ def json_encode(obj: Jsonable) -> str: + """Encode object""" return json.dumps(obj, indent=None, cls=Encoder) def json_decode(json_str: str) -> Jsonable: + """Decode object""" return json.loads(json_str, cls=Decoder) @Pyro4.expose class RemoteEnvironmentServer: + """Server for remote environment.""" + def __init__(self, env): + """Make env server.""" self.__env: AbstractEnv = env def step(self, action: Union[Dict[str, List[Number]], List[Number]]): + """Env step.""" action = json_decode(action) json_str = json_encode(self.__env.step(action)) return json_str def reset(self): + """Reset env.""" state = self.__env.reset() state = json_encode(state) return state def render(self, mode="human"): + """Render, does nothing.""" # ever used? pass def close(self): + """Close.""" self.__env.close() @property def action_space(self): + """Return action space.""" return json_encode(self.__env.action_space) class RemoteEnvironmentClient: + """Client for remote environment.""" + def __init__(self, env: RemoteEnvironmentServer): + """Make client.""" self.__env = env def step( self, action: Union[Dict[str, np.ndarray], np.ndarray] ) -> Tuple[Union[Dict[str, np.ndarray], np.ndarray], Number, bool, dict]: + """Remote step.""" action = json_encode(action) json_str = self.__env.step(action) @@ -79,13 +93,16 @@ def step( return state, reward, done, info def reset(self) -> Union[Dict[str, np.ndarray], np.ndarray]: + """Remote reset.""" state = self.__env.reset() state = json_decode(state) return state def close(self): + """Close.""" self.__env.close() @property def action_space(self): + """Return env action space.""" return json_decode(self.__env.action_space) diff --git a/dacbench/container/remote_runner.py b/dacbench/container/remote_runner.py index 4812ee87a..e4ed94667 100644 --- a/dacbench/container/remote_runner.py +++ b/dacbench/container/remote_runner.py @@ -1,7 +1,5 @@ -""" -This is strongly guided and partially copy from -https://github.com/automl/HPOBench/blob/master/hpobench/container/client_abstract_benchmark.py -""" +"""This is strongly guided and partially copy from:https://github.com/automl/HPOBench/blob/master/hpobench/container/client_abstract_benchmark.py""" + import argparse import logging import os @@ -51,16 +49,21 @@ @Pyro4.expose class RemoteRunnerServer: + """Server for container running.""" + def __init__(self, pyro_demon): + """Init server.""" self.benchmark = None self.pyro_demon = pyro_demon def start(self, config: str, benchmark: Tuple[str, str]): + """Start server.""" benchmark = AbstractBenchmark.import_from(*benchmark) self.benchmark = benchmark.from_json(config) def get_environment(self) -> str: + """Get environment.""" env = self.benchmark.get_environment() # set up logger and stuff @@ -71,6 +74,8 @@ def get_environment(self) -> str: class RemoteRunner: + """Runner for remote benchmarks.""" + FACTORY_NAME: str = "RemoteRunnerServerFactory" def __init__( @@ -85,42 +90,42 @@ def __init__( socket_id=None, ): """ + Runner for containers. - Parameters: - ---------------- - - benchmark: AbstractBenchmark - The benchmark to run - container_source : Optional[str] - Path to the container. Either local path or url to a hosting - platform, e.g. singularity hub. - container_tag : str - Singularity containers are specified by an address as well as a container tag. We use the tag as a version - number. By default the tag is set to `latest`, which then pulls the latest container from the container - source. The tag-versioning allows the users to rerun an experiment, which was performed with an older - container version. Take a look in the container_source to find the right tag to use. - bind_str : Optional[str] - Defaults to ''. You can bind further directories into the container. - This string have the form src[:dest[:opts]]. - For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html - env_str : Optional[str] - Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some - environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. - For more information, see - https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview - gpu : bool - If True, the container has access to the local cuda-drivers. - (Not tested) + Parameters + ---------- + benchmark: AbstractBenchmark + The benchmark to run + container_name : str + name for container + container_source : Optional[str] + Path to the container. Either local path or url to a hosting platform, e.g. singularity hub. + container_tag : str + Singularity containers are specified by an address as well as a container tag. We use the tag as a version + number. By default the tag is set to `latest`, which then pulls the latest container from the container + source. The tag-versioning allows the users to rerun an experiment, which was performed with an older + container version. Take a look in the container_source to find the right tag to use. + bind_str : Optional[str] + Defaults to ''. You can bind further directories into the container. + This string have the form src[:dest[:opts]]. + For more information, see https://sylabs.io/guides/3.5/user-guide/bind_paths_and_mounts.html + env_str : Optional[str] + Defaults to ''. Sometimes you want to pass a parameter to your container. You can do this by setting some + environmental variables. The list should follow the form VAR1=VALUE1,VAR2=VALUE2,.. + For more information, see + https://sylabs.io/guides/3.5/user-guide/environment_and_metadata.html#environment-overview + gpu : bool + If True, the container has access to the local cuda-drivers. (Not tested) socket_id : Optional[str] - Setting up the container is done in two steps: - 1) Start the benchmark on a random generated socket id. - 2) Create a proxy connection to the container via this socket id. + Setting up the container is done in two steps: + 1) Start the benchmark on a random generated socket id. + 2) Create a proxy connection to the container via this socket id. - When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is - stored in the class attribute Benchmark.socket_id + When no `socket_id` is given, a new container is started. The `socket_id` (address) of this containers is + stored in the class attribute Benchmark.socket_id - When a `socket_id` is given, instead of creating a new container, connect only to the container that is - reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. + When a `socket_id` is given, instead of creating a new container, connect only to the container that is + reachable at `socket_id`. Make sure that a container is already running with the address `socket_id`. """ logger.info(f"Logging level: {logger.level}") @@ -146,20 +151,22 @@ def __init__( @property def socket(self) -> Path: + """Get socket.""" return self.socket_from_id(self.__socket_id) @staticmethod def id_generator() -> str: - """Helper function: Creates unique socket ids for the benchmark server""" + """Helper function: Creates unique socket ids for the benchmark server.""" return str(uuid1()) @staticmethod def socket_from_id(socket_id: str) -> Path: + """Get socket from id.""" return Path(SOCKET_PATH) / f"{socket_id}.unixsock" def __start_server(self, env_str, bind_str, gpu): """ - Starts container and the pyro server + Starts container and the pyro server. Parameters ---------- @@ -169,6 +176,7 @@ def __start_server(self, env_str, bind_str, gpu): Bind string for the container gpu : bool True if the container should use gpu, False otherwise + """ # start container logger.debug(f"Starting server on {self.socket}") @@ -189,9 +197,7 @@ def __start_server(self, env_str, bind_str, gpu): wait_for_unixsocket(self.socket, 10) def __connect_to_server(self, benchmark: AbstractBenchmark): - """ - Connects to the server and initializes the benchmark - """ + """Connects to the server and initializes the benchmark.""" # Pyro4.config.REQUIRE_EXPOSE = False # Generate Pyro 4 URI for connecting to client ns = Pyro4.Proxy(f"PYRO:Pyro.NameServer@./u:{self.socket}") @@ -207,6 +213,7 @@ def __connect_to_server(self, benchmark: AbstractBenchmark): self.env = None def get_environment(self): + """Get remote environment.""" if self.env is None: env_uri = self.remote_runner.get_environment() remote_env_server = Pyro4.Proxy(env_uri) @@ -214,6 +221,7 @@ def get_environment(self): return self.env def run(self, agent: AbstractDACBenchAgent, number_of_episodes: int): + """Run agent on remote.""" # todo: seeding env = self.get_environment() @@ -232,11 +240,13 @@ def run(self, agent: AbstractDACBenchAgent, number_of_episodes: int): self.env = None def close(self): + """Termiante all processes.""" # todo add context manager self.daemon_process.terminate() self.daemon_process.wait() def __del__(self): + """Close.""" self.close() def load_benchmark( @@ -246,6 +256,7 @@ def load_benchmark( container_source: Union[str, Path], container_tag: str, ): + """Load benchmark from recipe.""" # see for implementation guideline hpobench hpobench/container/client_abstract_benchmark.py # in the end self.container_source should contain the path to the file to run @@ -261,15 +272,20 @@ def load_benchmark( @Pyro4.expose class RemoteRunnerServerFactory: + """Creates remoter runner servers.""" + def __init__(self, pyro_demon): + """Make server factory.""" self.pyro_demon = pyro_demon def create(self): + """Get server.""" remote_runner_server = RemoteRunnerServer(pyro_demon=self.pyro_demon) remote_runner_server_uri = daemon.register(remote_runner_server) return remote_runner_server_uri def __call__(self): + """Make.""" return self.create() diff --git a/dacbench/instance_sets/geometric/SampleGeometricInstances.py b/dacbench/instance_sets/geometric/SampleGeometricInstances.py index 2bf4d1428..f8212da5d 100644 --- a/dacbench/instance_sets/geometric/SampleGeometricInstances.py +++ b/dacbench/instance_sets/geometric/SampleGeometricInstances.py @@ -38,6 +38,7 @@ def save_geometric_instances( ): """ First delete old isntance_set. + Create new instances based on config. Parameters @@ -46,6 +47,9 @@ def save_geometric_instances( name of instance set config : Dict, optional config that has info about which functions will get selected, by default FUNCTION_CONFIG + path : std + path to save to + """ if path: csv_path = os.path.join(path, filename) @@ -72,8 +76,7 @@ def save_geometric_instances( def _create_csv_string(index, func_name: str) -> str: """ - Create comma separated string with function name and parameter values. - Set 0 for irrelevant params. + Create comma separated string with function name and parameter values. Set 0 for irrelevant params. Parameters ---------- @@ -86,6 +89,7 @@ def _create_csv_string(index, func_name: str) -> str: ------- str comma separated string + """ count = FUNCTION_PARAMETER_NUMBERS[func_name] max_count = max(list(FUNCTION_PARAMETER_NUMBERS.values())) @@ -119,10 +123,12 @@ def _create_csv_string(index, func_name: str) -> str: def sample_sinus_value(): + """Get values for sinus.""" return np.round(np.random.uniform(low=0.5, high=2.0), 1) def sample_sigmoid_value(): + """Get values for sigmoid.""" scale = np.round(np.random.uniform(low=0.1, high=4.0), 1) yield scale infliction = np.round(np.random.uniform(low=0, high=10), 1) @@ -130,6 +136,7 @@ def sample_sigmoid_value(): def sample_parabel_cubic_value(): + """Get values for cubic.""" sig = [-1, 1] yield random.choice(sig) diff --git a/dacbench/logger.py b/dacbench/logger.py index be0e08638..83803ff59 100644 --- a/dacbench/logger.py +++ b/dacbench/logger.py @@ -30,6 +30,7 @@ def load_logs(log_file: Path) -> List[Dict]: } ... } + Parameters ---------- log_file: pathlib.Path @@ -38,6 +39,7 @@ def load_logs(log_file: Path) -> List[Dict]: Returns ------- [Dict, ...] + """ with open(log_file, "r") as log_file: logs = list(map(json.loads, log_file)) @@ -54,10 +56,12 @@ def split(predicate: Callable, iterable: Iterable) -> Tuple[List, List]: predicate: Callable A function taking an element of the iterable and return Ture or False iterable: Iterable + the iterable to split Returns ------- (positives, negatives) + """ positives, negatives = [], [] @@ -69,9 +73,9 @@ def split(predicate: Callable, iterable: Iterable) -> Tuple[List, List]: def flatten_log_entry(log_entry: Dict) -> List[Dict]: """ - Transforms a log entry of format like - + Transforms a log entry. + From: { 'step': 0, 'episode': 2, @@ -80,7 +84,7 @@ def flatten_log_entry(log_entry: Dict) -> List[Dict]: 'times':['28-12-20 16:20:53', '28-12-20 16:21:30'], } } - into + To: [ { 'step': 0,'episode': 2, 'value': 34, 'time': '28-12-20 16:20:53'}, { 'step': 0,'episode': 2, 'value': 45, 'time': '28-12-20 16:21:30'} @@ -91,8 +95,6 @@ def flatten_log_entry(log_entry: Dict) -> List[Dict]: log_entry: Dict A log entry - Returns - ------- """ dict_entries, top_level_entries = split( lambda item: isinstance(item[1], dict), log_entry.items() @@ -114,7 +116,8 @@ def flatten_log_entry(log_entry: Dict) -> List[Dict]: def list_to_tuple(list_: List) -> Tuple: """ - Recursively transforms a list of lists into tuples of tuples + Recursively transforms a list of lists into tuples of tuples. + Parameters ---------- list_: @@ -123,6 +126,7 @@ def list_to_tuple(list_: List) -> Tuple: Returns ------- (nested) tuple + """ return tuple( list_to_tuple(item) if isinstance(item, list) else item for item in list_ @@ -152,8 +156,8 @@ def log2dataframe( Returns ------- dataframe - """ + """ flat_logs = map(flatten_log_entry, logs) rows = reduce(lambda l1, l2: l1 + l2, flat_logs) @@ -189,12 +193,14 @@ def log2dataframe( def seed_mapper(self): + """Helper function for seeding.""" if self.env is None: return None return self.env.initial_seed def instance_mapper(self): + """Helper function to get instance id.""" if self.env is None: return None return self.env.get_inst_id() @@ -223,6 +229,7 @@ def __init__( episode_write_frequency: int = 1, ): """ + Initializes Logger. Parameters ---------- @@ -236,6 +243,7 @@ def __init__( or on close episode_write_frequency: int see step_write_frequency + """ self.experiment_name = experiment_name self.output_path = output_path @@ -251,6 +259,7 @@ def __init__( @property def additional_info(self): + """Log additional info.""" additional_info = self._additional_info.copy() auto_info = { key: mapper(self) @@ -264,25 +273,19 @@ def additional_info(self): def set_env(self, env: AbstractEnv) -> None: """ - Needed to infer automatically logged information like the instance id + Needed to infer automatically logged information like the instance id. + Parameters ---------- env: AbstractEnv - - Returns - ------- + env to log """ self.env = env @staticmethod def _pretty_valid_types() -> str: - """ - Returns a string pretty string representation of the types that can be logged as values - Returns - ------- - - """ + """Returns a string pretty string representation of the types that can be logged as values.""" valid_types = chain( AbstractLogger.valid_types["recursive"], AbstractLogger.valid_types["primitive"], @@ -292,30 +295,35 @@ def _pretty_valid_types() -> str: @staticmethod def _init_logging_dir(log_dir: Path) -> None: """ - Prepares the logging directory + Prepares the logging directory. + Parameters ---------- log_dir: pathlib.Path + dir to prepare for logging Returns ------- None + """ log_dir.mkdir(parents=True, exist_ok=True) return log_dir def is_of_valid_type(self, value: Any) -> bool: - f""" - Checks if the value of any type in {AbstractLogger._pretty_valid_types()} + """ + Checks if the value of any type in the logger's valid types. + Parameters ---------- value + value to check Returns ------- bool - """ + """ if any(isinstance(value, type) for type in self.valid_types["primitive"]): return True @@ -328,66 +336,36 @@ def is_of_valid_type(self, value: Any) -> bool: @abstractmethod def close(self) -> None: - """ - Makes sure, that all remaining entries in the are written to file and the file is closed. - - Returns - ------- - - """ + """Makes sure, that all remaining entries in the are written to file and the file is closed.""" pass @abstractmethod def next_step(self) -> None: - """ - Call at the end of the step. - Updates the internal state and dumps the information of the last step into a json - - Returns - ------- - - """ + """Call at the end of the step. Updates the internal state and dumps the information of the last step into a json.""" pass @abstractmethod def next_episode(self) -> None: - """ - Call at the end of episode. - - See next_step - Returns - ------- - - """ + """Call at the end of episode. See next_step.""" pass @abstractmethod def write(self) -> None: - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ + """Writes buffered logs to file. Invoke manually if you want to load logs during a run.""" pass @abstractmethod def log(self, key: str, value) -> None: - f""" - Writes value to list of values and save the current time for key + """ + Writes value to list of values and save the current time for key. Parameters ---------- key: str + key to log value: the value must of of a type that is json serializable. - Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. - - Returns - ------- + Currently only {str, int, float, bool, np.number} and recursive types of those are supported. """ pass @@ -402,9 +380,6 @@ def log_dict(self, data): data: dict a dict with key-value so that each value is a valid value for log - Returns - ------- - """ pass @@ -427,9 +402,6 @@ def log_space(self, key: str, value: Union[np.ndarray, Dict], space_info=None): space_info: a list of column names. The length of this list must equal the resulting number of columns. - Returns - ------- - """ pass @@ -450,7 +422,7 @@ def __init__( episode_write_frequency: int = 1, ) -> None: """ - All results are placed under 'output_path / experiment_name' + All results are placed under 'output_path / experiment_name'. Parameters ---------- @@ -483,39 +455,36 @@ def __init__( def get_logfile(self) -> Path: """ + Get logfile name. + Returns ------- pathlib.Path the path to the log file of this logger + """ return Path(self.log_file.name) def close(self): - """ - Makes sure, that all remaining entries in the are written to file and the file is closed. - - Returns - ------- - - """ + """Makes sure, that all remaining entries in the are written to file and the file is closed.""" if not self.log_file.closed: self.write() self.log_file.close() def __del__(self): + """Makes sure, that all remaining entries in the are written to file and the file is closed.""" if not self.log_file.closed: self.close() @staticmethod def __json_default(object): """ - Add supoort for dumping numpy arrays and numbers to json + Add supoort for dumping numpy arrays and numbers to json. + Parameters ---------- object - - Returns - ------- + numpy object to jsonify """ if isinstance(object, np.ndarray): @@ -540,15 +509,7 @@ def __init_dict(): return defaultdict(lambda: {"times": [], "values": []}) def reset_episode(self) -> None: - """ - Resets the episode and step. - - Be aware that this can lead to ambitious keys if no instance or seed or other identifying additional info is set - - Returns - ------- - - """ + """Resets the episode and step. Be aware that this can lead to ambitious keys if no instance or seed or other identifying additional info is set.""" self.__end_step() self.episode = 0 self.step = 0 @@ -558,14 +519,7 @@ def __reset_step(self): self.step = 0 def next_step(self): - """ - Call at the end of the step. - Updates the internal state and dumps the information of the last step into a json - - Returns - ------- - - """ + """Call at the end of the step. Updates the internal state and dumps the information of the last step into a json.""" self.__end_step() if ( self.step_write_frequency is not None @@ -575,15 +529,7 @@ def next_step(self): self.step += 1 def next_episode(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ + """Writes buffered logs to file. Invoke manually if you want to load logs during a run.""" self.__reset_step() if ( self.episode_write_frequency is not None @@ -593,15 +539,7 @@ def next_episode(self): self.episode += 1 def write(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ + """Writes buffered logs to file. Invoke manually if you want to load logs during a run.""" self.__end_step() self.__buffer_to_file() @@ -614,13 +552,12 @@ def __buffer_to_file(self): def set_additional_info(self, **kwargs): """ - Can be used to log additional information for each step e.g. for seed, and instance id. + Can be used to log additional information for each step e.g. for seed and instance id. + Parameters ---------- - kwargs - - Returns - ------- + kwargs : dict + info dict """ self._additional_info.update(kwargs) @@ -628,18 +565,16 @@ def set_additional_info(self, **kwargs): def log( self, key: str, value: Union[Dict, List, Tuple, str, int, float, bool] ) -> None: - f""" - Writes value to list of values and save the current time for key + """ + Writes value to list of values and save the current time for key. Parameters ---------- key: str + key to log value: the value must of of a type that is json serializable. - Currently only {AbstractLogger._pretty_valid_types()} and recursive types of those are supported. - - Returns - ------- + Currently only {str, int, float, bool, np.number} and recursive types of those are supported. """ self.__log(key, value, datetime.now().strftime("%d-%m-%y %H:%M:%S.%f")) @@ -662,8 +597,6 @@ def log_dict(self, data: Dict) -> None: data: dict a dict with key-value so that each value is a valid value for log - Returns - ------- """ time = datetime.now().strftime("%d-%m-%y %H:%M:%S.%f") for key, value in data.items(): @@ -727,9 +660,6 @@ def log_space(self, key, value, space_info=None): space_info: a list of column names. The length of this list must equal the resulting number of columns. - Returns - ------- - """ data = self.__space_dict(key, value, space_info) self.log_dict(data) @@ -754,6 +684,7 @@ def __init__( episode_write_frequency: int = 1, ) -> None: """ + Create Logger. Parameters ---------- @@ -767,6 +698,7 @@ def __init__( or on close episode_write_frequency: int see step_write_frequency + """ super(Logger, self).__init__( experiment_name, output_path, step_write_frequency, episode_write_frequency @@ -775,75 +707,61 @@ def __init__( self.module_logger: Dict[str, ModuleLogger] = dict() def set_env(self, env: AbstractEnv) -> None: + """ + Writes information about the environment. + + Parameters + ---------- + env: AbstractEnv + the env object to track + + """ super().set_env(env) for _, module_logger in self.module_logger.items(): module_logger.set_env(env) def close(self): - """ - Makes sure, that all remaining entries (from all sublogger) are written to files and the files are closed. - - Returns - ------- - - """ + """Makes sure, that all remaining entries (from all sublogger) are written to files and the files are closed.""" for _, module_logger in self.module_logger.items(): module_logger.close() def __del__(self): + """Removes Logger.""" self.close() def next_step(self): - """ - Call at the end of the step. - Updates the internal state of all subloggers and dumps the information of the last step into a json - - Returns - ------- - - """ + """Call at the end of the step. Updates the internal state of all subloggers and dumps the information of the last step into a json.""" for _, module_logger in self.module_logger.items(): module_logger.next_step() def next_episode(self): - """ - Call at the end of episode. - - See next_step - Returns - ------- - - """ + """Call at the end of episode. See next_step.""" for _, module_logger in self.module_logger.items(): module_logger.next_episode() def reset_episode(self): + """Resets in all modules.""" for _, module_logger in self.module_logger.items(): module_logger.reset_episode() def write(self): - """ - Writes buffered logs to file. - - Invoke manually if you want to load logs during a run. - - Returns - ------- - - """ + """Writes buffered logs to file. Invoke manually if you want to load logs during a run.""" for _, module_logger in self.module_logger.items(): module_logger.write() def add_module(self, module: Union[str, type]) -> ModuleLogger: """ - Creates a sub-logger. For more details see class level documentation + Creates a sub-logger. For more details see class level documentation. + Parameters ---------- module: str or type The module name or Wrapper-Type to create a sub-logger for + Returns ------- ModuleLogger + """ if isinstance(module, str): pass @@ -869,13 +787,13 @@ def add_module(self, module: Union[str, type]) -> ModuleLogger: def add_agent(self, agent: AbstractDACBenchAgent): """ - Writes information about the agent + Writes information about the agent. + Parameters ---------- agent: AbstractDACBenchAgent + the agent object to add - Returns - ------- """ agent_config = {"type": str(agent.__class__)} with open(self.log_dir / "agent.json", "w") as f: @@ -883,32 +801,79 @@ def add_agent(self, agent: AbstractDACBenchAgent): def add_benchmark(self, benchmark: AbstractBenchmark) -> None: """ - Writes the config to the experiment path + Add benchmark to logger. + Parameters ---------- - benchmark - - Returns - ------- + benchmark : AbstractBenchmark + the benchmark object to add """ benchmark.save_config(self.log_dir / "benchmark.json") def set_additional_info(self, **kwargs): + """ + Add additional info. + + Parameters + ---------- + kwargs : dict + info dict + + """ for _, module_logger in self.module_logger.items(): module_logger.set_additional_info(**kwargs) def log(self, key, value, module): + """ + Log a key-value pair to module. + + Parameters + ---------- + key : str | int + key to log + value : + value to log + module : + module to log to + + """ if module not in self.module_logger: raise ValueError(f"Module {module} not registered yet") self.module_logger.log(key, value) def log_space(self, key, value, module, space_info=None): + """ + Log a key-value pair to module with optional info. + + Parameters + ---------- + key : str | int + key to log + value : + value to log + module : + module to log to + space_info : + additional log info + + """ if module not in self.module_logger: raise ValueError(f"Module {module} not registered yet") self.module_logger.log_space(key, value, space_info) def log_dict(self, data, module): + """ + Log a data dict to module. + + Parameters + ---------- + data : dict + data to log + module + module to log to + + """ if module not in self.module_logger: raise ValueError(f"Module {module} not registered yet") self.module_logger.log_space(data) diff --git a/dacbench/plotting.py b/dacbench/plotting.py index e4e1ecb8c..ff2a2e45e 100644 --- a/dacbench/plotting.py +++ b/dacbench/plotting.py @@ -9,16 +9,17 @@ def space_sep_upper(column_name: str) -> str: """ - Separates strings at underscores into headings. - Used to generate labels from logging names. + Separates strings at underscores into headings. Used to generate labels from logging names. Parameters ---------- column_name : str + Name to generate label for Returns ------- str + """ if column_name is None: return None @@ -39,7 +40,8 @@ def generate_global_step( Parameters ---------- - data: + data: pd.DataFrame + data source x_column: str the name of the global_step (default 'global_step') x_label_columns: [str, ...] @@ -48,6 +50,7 @@ def generate_global_step( Returns ------- (data, plot_index, x_column, x_label_columns) + """ plot_index = ( data.groupby(x_label_columns) @@ -65,7 +68,7 @@ def add_multi_level_ticks( grid: sns.FacetGrid, plot_index: pd.DataFrame, x_column: str, x_label_columns: str ) -> None: """ - Expects a FacedGrid with global_step (x_column) as x-axis and replaces the tick labels to match format episode:step + Expects a FacedGrid with global_step (x_column) as x-axis and replaces the tick labels to match format episode:step. E.g. Run with 3 episodes, each of 10 steps. This results in 30 global steps. The resulting tick labels could be ['0', '4', '9', '14', '19', '24', '29']. @@ -74,7 +77,7 @@ def add_multi_level_ticks( Parameters ---------- grid: sns.FacesGrid - + The grid to plot onto plot_index: pd.DataFrame The mapping between current tick labels (global step values) and new tick labels joined by ':'. usually the result from generate_global_step @@ -83,9 +86,6 @@ def add_multi_level_ticks( x_label_columns: [str, ...] columns labels of columns to use for new labels (joined by ':' - Returns - ------- - """ for ax in grid.axes.flat: ticks = ax.get_xticks() @@ -111,7 +111,8 @@ def plot( **kwargs, ) -> sns.FacetGrid: """ - Helper function that: create a FacetGrid + Helper function that creates a FacetGrid. + 1. Updates settings with kwargs (overwrites values) 2. Plots using plot_function(**settings) 3. Set x and y labels of not provided the columns names will converted to pretty strings using space_sep_upper @@ -183,6 +184,7 @@ def plot_performance( Returns ------- sns.FacedGrid + """ settings = { "data": data, @@ -223,6 +225,7 @@ def plot_performance_per_instance( Returns ------- sns.FacedGrid + """ # order the columns by mean instance order = data.groupby("instance").mean().sort_values("overall_performance").index @@ -277,6 +280,7 @@ def plot_step_time( Returns ------- sns.FacedGrid + """ multi_level_x_label = "Epoch:Step" data, plot_index, x_column, x_label_columns = generate_global_step(data) @@ -331,6 +335,7 @@ def plot_episode_time( Returns ------- sns.FacedGrid + """ settings = { "data": data, @@ -386,8 +391,8 @@ def plot_action( Returns ------- sns.FacedGrid - """ + """ return plot_space( data, "action", show_global_step, interval, title, x_label, y_label, **kargs ) @@ -435,6 +440,7 @@ def plot_state( Returns ------- sns.FacedGrid + """ return plot_space( data, "state", show_global_step, interval, title, x_label, y_label, **kargs @@ -452,7 +458,7 @@ def plot_space( **args, ) -> sns.FacetGrid: """ - Create a line plot showing sapce over time. + Create a line plot showing space over time. Please be aware that spaces can be quite large and the plots can become quite messy (and take some time) if you try plot all dimensions at once. It is therefore recommended to select a subset of columns before running the @@ -471,6 +477,8 @@ def plot_space( ---------- data: pd.DataFrame Dataframe resulting from logging and loading using log2dataframe(logs, wide=True) + space_column_name : str + Name of the column in the space which to plot show_global_step: bool If to show the global_step (step enumerated over all episodes) or Episode:Step. (False default) interval: int @@ -487,6 +495,7 @@ def plot_space( Returns ------- sns.FacedGrid + """ # first find columns with prefix space_column_name space_entries = list( diff --git a/dacbench/run_baselines.py b/dacbench/run_baselines.py index d2144b8bd..1631c8686 100644 --- a/dacbench/run_baselines.py +++ b/dacbench/run_baselines.py @@ -36,6 +36,23 @@ def run_random(results_path, benchmark_name, num_episodes, seeds, fixed): + """ + Run random policy. + + Parameters + ---------- + results_path : str + Path to where results should be saved + benchmark_name : str + Name of the benchmark to run + num_episodes : int + Number of episodes to run for each benchmark + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + fixed : int + Number of fixed steps per action + + """ bench = getattr(benchmarks, benchmark_name)() for s in seeds: if fixed > 1: @@ -61,6 +78,23 @@ def run_random(results_path, benchmark_name, num_episodes, seeds, fixed): def run_static(results_path, benchmark_name, action, num_episodes, seeds=np.arange(10)): + """ + Run static policy. + + Parameters + ---------- + results_path : str + Path to where results should be saved + benchmark_name : str + Name of the benchmark to run + action : int | float + The action to run + num_episodes : int + Number of episodes to run for each benchmark + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + + """ bench = getattr(benchmarks, benchmark_name)() for s in seeds: logger = Logger( @@ -84,6 +118,21 @@ def run_static(results_path, benchmark_name, action, num_episodes, seeds=np.aran def run_optimal(results_path, benchmark_name, num_episodes, seeds): + """ + Run optimal policy. + + Parameters + ---------- + results_path : str + Path to where results should be saved + benchmark_name : str + Name of the benchmark to run + num_episodes : int + Number of episodes to run for each benchmark + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + + """ if benchmark_name not in OPTIMAL_POLICIES: print("No optimal policy found for this benchmark") return @@ -92,6 +141,21 @@ def run_optimal(results_path, benchmark_name, num_episodes, seeds): def run_dynamic_policy(results_path, benchmark_name, num_episodes, seeds=np.arange(10)): + """ + Run dynamic baseline policy. + + Parameters + ---------- + results_path : str + Path to where results should be saved + benchmark_name : str + Name of the benchmark to run + num_episodes : int + Number of episodes to run for each benchmark + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + + """ if benchmark_name not in NON_OPTIMAL_POLICIES: print("No dynamic policy found for this benchmark") policy = NON_OPTIMAL_POLICIES[benchmark_name] @@ -99,6 +163,23 @@ def run_dynamic_policy(results_path, benchmark_name, num_episodes, seeds=np.aran def run_policy(results_path, benchmark_name, num_episodes, policy, seeds=np.arange(10)): + """ + Run generic policy. + + Parameters + ---------- + results_path : str + Path to where results should be saved + benchmark_name : str + Name of the benchmark to run + num_episodes : int + Number of episodes to run for each benchmark + policy : AbstractDACBenchAgent + The policy to run + seeds : list[int] + List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. + + """ bench = getattr(benchmarks, benchmark_name)() for s in seeds: @@ -126,6 +207,7 @@ def run_policy(results_path, benchmark_name, num_episodes, policy, seeds=np.aran def main(args): + """Main evaluation loop.""" parser = argparse.ArgumentParser( description="Run simple baselines for DAC benchmarks", formatter_class=argparse.ArgumentDefaultsHelpFormatter, diff --git a/dacbench/runner.py b/dacbench/runner.py index fbe2818c6..b87f4d5c9 100644 --- a/dacbench/runner.py +++ b/dacbench/runner.py @@ -12,17 +12,19 @@ def run_benchmark(env, agent, num_episodes, logger=None): """ - Run single benchmark env for a given number of episodes with a given agent + Run single benchmark env for a given number of episodes with a given agent. Parameters - ------- + ---------- env : gym.Env Benchmark environment agent Any agent implementing the methods act, train and end_episode (see AbstractDACBenchAgent below) num_episodes : int Number of episodes to run - logger : dacbench.logger.Logger: logger to use for logging. Not closed automatically like env + logger : dacbench.logger.Logger + logger to use for logging. Not closed automatically like env + """ if logger is not None: logger.reset_episode() @@ -48,21 +50,22 @@ def run_benchmark(env, agent, num_episodes, logger=None): def run_dacbench(results_path, agent_method, num_episodes, bench=None, seeds=None): """ - Run all benchmarks for 10 seeds for a given number of episodes with a given agent and save result + Run all benchmarks for 10 seeds for a given number of episodes with a given agent and save result. Parameters - ------- - bench + ---------- results_path : str Path to where results should be saved agent_method : function Method that takes an env as input and returns an agent num_episodes : int Number of episodes to run for each benchmark + bench: AbstractBenchmark + benchmark to run. If none is given, run all. seeds : list[int] List of seeds to runs all benchmarks for. If None (default) seeds [1, ..., 10] are used. - """ + """ if bench is None: bench = map(benchmarks.__dict__.get, benchmarks.__all__) else: diff --git a/dacbench/wrappers/action_tracking_wrapper.py b/dacbench/wrappers/action_tracking_wrapper.py index 2a6e5bd32..85f7461e4 100644 --- a/dacbench/wrappers/action_tracking_wrapper.py +++ b/dacbench/wrappers/action_tracking_wrapper.py @@ -11,20 +11,23 @@ class ActionFrequencyWrapper(Wrapper): """ Wrapper to action frequency. + Includes interval mode that returns frequencies in lists of len(interval) instead of one long list. """ def __init__(self, env, action_interval=None, logger=None): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap action_interval : int If not none, mean in given intervals is tracked, too logger: logger.ModuleLogger + logger to write to + """ super(ActionFrequencyWrapper, self).__init__(env) self.action_interval = action_interval @@ -37,7 +40,7 @@ def __init__(self, env, action_interval=None, logger=None): def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -45,6 +48,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in [ "action_interval", @@ -63,7 +67,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -74,6 +78,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in [ "action_interval", @@ -93,7 +98,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and record state + Execute environment step and record state. Parameters ---------- @@ -104,6 +109,7 @@ def step(self, action): ------- np.array, float, bool, dict state, reward, done, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) self.overall_actions.append(action) @@ -120,7 +126,7 @@ def step(self, action): def get_actions(self): """ - Get state progression + Get state progression. Returns ------- @@ -137,7 +143,7 @@ def get_actions(self): def render_action_tracking(self): """ - Render action progression + Render action progression. Returns ------- diff --git a/dacbench/wrappers/episode_time_tracker.py b/dacbench/wrappers/episode_time_tracker.py index 267332197..dc3507e2b 100644 --- a/dacbench/wrappers/episode_time_tracker.py +++ b/dacbench/wrappers/episode_time_tracker.py @@ -13,20 +13,23 @@ class EpisodeTimeWrapper(Wrapper): """ Wrapper to track time spent per episode. + Includes interval mode that returns times in lists of len(interval) instead of one long list. """ def __init__(self, env, time_interval=None, logger=None): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap time_interval : int If not none, mean in given intervals is tracked, too logger : dacbench.logger.ModuleLogger + logger to write to + """ super(EpisodeTimeWrapper, self).__init__(env) self.time_interval = time_interval @@ -44,7 +47,7 @@ def __init__(self, env, time_interval=None, logger=None): def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -52,6 +55,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in [ "time_interval", @@ -76,7 +80,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -87,6 +91,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in [ "time_interval", @@ -112,7 +117,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and record time + Execute environment step and record time. Parameters ---------- @@ -123,6 +128,7 @@ def step(self, action): ------- np.array, float, bool, bool, dict state, reward, terminated, truncated, metainfo + """ start = time.time() state, reward, terminated, truncated, info = self.env.step(action) @@ -156,7 +162,7 @@ def step(self, action): def get_times(self): """ - Get times + Get times. Returns ------- @@ -178,7 +184,7 @@ def get_times(self): return np.array(self.overall_times), np.array(self.all_steps) def render_step_time(self): - """Render step times""" + """Render step times.""" figure = plt.figure(figsize=(12, 6)) canvas = FigureCanvas(figure) plt.title("Time per Step") @@ -208,7 +214,7 @@ def render_step_time(self): return img def render_episode_time(self): - """Render episode times""" + """Render episode times.""" figure = plt.figure(figsize=(12, 6)) canvas = FigureCanvas(figure) plt.title("Time per Episode") diff --git a/dacbench/wrappers/instance_sampling_wrapper.py b/dacbench/wrappers/instance_sampling_wrapper.py index 528f63c37..ca5ea16ef 100644 --- a/dacbench/wrappers/instance_sampling_wrapper.py +++ b/dacbench/wrappers/instance_sampling_wrapper.py @@ -6,22 +6,27 @@ class InstanceSamplingWrapper(Wrapper): """ Wrapper to sample a new instance at a given time point. + Instances can either be sampled using a given method or a distribution infered from a given list of instances. """ def __init__(self, env, sampling_function=None, instances=None, reset_interval=0): """ - Initialize wrapper + Initialize wrapper. + Either sampling_function or instances must be given Parameters - ------- + ---------- env : gym.Env Environment to wrap sampling_function : function Function to sample instances from instances : list List of instances to infer distribution from + reset_interval : int + additional episodes for which to keep an instance + """ super(InstanceSamplingWrapper, self).__init__(env) if sampling_function: @@ -35,7 +40,7 @@ def __init__(self, env, sampling_function=None, instances=None, reset_interval=0 def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -43,6 +48,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in ["sampling_function", "env", "fit_dist", "reset"]: object.__setattr__(self, name, value) @@ -51,7 +57,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -62,6 +68,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in ["sampling_function", "env", "fit_dist", "reset"]: return object.__getattribute__(self, name) @@ -71,12 +78,13 @@ def __getattribute__(self, name): def reset(self): """ - Reset environment and use sampled instance for training + Reset environment and use sampled instance for training. Returns ------- np.array state + """ if self.reset_tracker >= self.reset_interval: instance = self.sampling_function() @@ -85,7 +93,7 @@ def reset(self): def fit_dist(self, instances): """ - Approximate instance distribution in given instance set + Approximate instance distribution in given instance set. Parameters ---------- @@ -93,9 +101,10 @@ def fit_dist(self, instances): instance set Returns - --------- + ------- method sampling method for new instances + """ dists = [] for i in range(len(instances[0])): diff --git a/dacbench/wrappers/multidiscrete_action_wrapper.py b/dacbench/wrappers/multidiscrete_action_wrapper.py index c4747f51a..b08bdc7f7 100644 --- a/dacbench/wrappers/multidiscrete_action_wrapper.py +++ b/dacbench/wrappers/multidiscrete_action_wrapper.py @@ -5,19 +5,17 @@ class MultiDiscreteActionWrapper(Wrapper): - """ - Wrapper to cast MultiDiscrete action spaces to Discrete. - This should improve usability with standard RL libraries. - """ + """Wrapper to cast MultiDiscrete action spaces to Discrete. This should improve usability with standard RL libraries.""" def __init__(self, env): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap + """ super().__init__(env) self.n_actions = len(self.env.action_space.nvec) @@ -30,5 +28,6 @@ def __init__(self, env): self.action_mapper[idx] = prod_idx def step(self, action): + """Maps discrete action value to array.""" action = self.action_mapper[action] return self.env.step(action) diff --git a/dacbench/wrappers/observation_wrapper.py b/dacbench/wrappers/observation_wrapper.py index 55847fcf9..7b505f0a3 100644 --- a/dacbench/wrappers/observation_wrapper.py +++ b/dacbench/wrappers/observation_wrapper.py @@ -4,20 +4,22 @@ class ObservationWrapper(Wrapper): """ - Wrapper covert observations spaces to spaces.Box for convenience + Wrapper covert observations spaces to spaces.Box for convenience. + Currently only supports Dict -> Box """ def __init__(self, env): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap compute_optimal : function Function to compute optimal policy + """ super(ObservationWrapper, self).__init__(env) obs_sample = self.flatten(self.env.observation_space.sample()) @@ -28,7 +30,7 @@ def __init__(self, env): def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -36,6 +38,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in ["observation_space", "step", "env", "flatten", "reset"]: object.__setattr__(self, name, value) @@ -44,7 +47,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -55,6 +58,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in ["observation_space", "step", "env", "flatten", "reset"]: return object.__getattribute__(self, name) @@ -63,7 +67,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and record distance + Execute environment step and record distance. Parameters ---------- @@ -74,6 +78,7 @@ def step(self, action): ------- np.array, float, bool, bool, dict state, reward, terminated, truncated, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) state = self.flatten(state) @@ -81,18 +86,20 @@ def step(self, action): def reset(self): """ - Execute environment step and record distance + Execute environment step and record distance. Returns ------- np.array, dict state, info + """ state, info = self.env.reset() state = self.flatten(state) return state, info def flatten(self, state_dict): + """Flatten dict to list.""" keys = sorted(list(state_dict.keys())) values = [] for k in keys: diff --git a/dacbench/wrappers/performance_tracking_wrapper.py b/dacbench/wrappers/performance_tracking_wrapper.py index 1c42f58d4..9b4ccaece 100644 --- a/dacbench/wrappers/performance_tracking_wrapper.py +++ b/dacbench/wrappers/performance_tracking_wrapper.py @@ -12,6 +12,7 @@ class PerformanceTrackingWrapper(Wrapper): """ Wrapper to track episode performance. + Includes interval mode that returns performance in lists of len(interval) instead of one long list. """ @@ -23,10 +24,10 @@ def __init__( logger=None, ): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap performance_interval : int @@ -34,6 +35,8 @@ def __init__( track_instance_performance : bool Indicates whether to track per-instance performance logger : dacbench.logger.ModuleLogger + logger to write to + """ super(PerformanceTrackingWrapper, self).__init__(env) self.performance_interval = performance_interval @@ -50,7 +53,7 @@ def __init__( def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -58,6 +61,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in [ "performance_interval", @@ -80,7 +84,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -91,6 +95,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in [ "performance_interval", @@ -114,7 +119,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and record performance + Execute environment step and record performance. Parameters ---------- @@ -125,6 +130,7 @@ def step(self, action): ------- np.array, float, bool, dict state, reward, done, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) self.episode_performance += reward @@ -151,7 +157,7 @@ def step(self, action): def get_performance(self): """ - Get state performance + Get state performance. Returns ------- @@ -178,7 +184,7 @@ def get_performance(self): return self.overall_performance def render_performance(self): - """Plot performance""" + """Plot performance.""" plt.figure(figsize=(12, 6)) plt.plot( np.arange(len(self.overall_performance) // 2), @@ -190,7 +196,7 @@ def render_performance(self): plt.show() def render_instance_performance(self): - """Plot mean performance for each instance""" + """Plot mean performance for each instance.""" plt.figure(figsize=(12, 6)) plt.title("Mean Performance per Instance") plt.ylabel("Mean reward") diff --git a/dacbench/wrappers/policy_progress_wrapper.py b/dacbench/wrappers/policy_progress_wrapper.py index 3618ec58e..c8b1b209e 100644 --- a/dacbench/wrappers/policy_progress_wrapper.py +++ b/dacbench/wrappers/policy_progress_wrapper.py @@ -6,19 +6,21 @@ class PolicyProgressWrapper(Wrapper): """ Wrapper to track progress towards optimal policy. - Can only be used if a way to obtain the optimal policy given an instance can be obtained + + Can only be used if a way to obtain the optimal policy given an instance can be obtained. """ def __init__(self, env, compute_optimal): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap compute_optimal : function Function to compute optimal policy + """ super(PolicyProgressWrapper, self).__init__(env) self.compute_optimal = compute_optimal @@ -27,7 +29,7 @@ def __init__(self, env, compute_optimal): def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -35,6 +37,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in [ "compute_optimal", @@ -49,7 +52,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -60,6 +63,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in [ "step", @@ -75,7 +79,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and record distance + Execute environment step and record distance. Parameters ---------- @@ -86,6 +90,7 @@ def step(self, action): ------- np.array, float, bool, bool, dict state, reward, terminated, truncated, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) self.episode.append(action) @@ -98,7 +103,7 @@ def step(self, action): return state, reward, terminated, truncated, info def render_policy_progress(self): - """Plot progress""" + """Plot progress.""" plt.figure(figsize=(12, 6)) plt.plot(np.arange(len(self.policy_progress)), self.policy_progress) plt.title("Policy progress over time") diff --git a/dacbench/wrappers/reward_noise_wrapper.py b/dacbench/wrappers/reward_noise_wrapper.py index 079002e1a..a8021cc09 100644 --- a/dacbench/wrappers/reward_noise_wrapper.py +++ b/dacbench/wrappers/reward_noise_wrapper.py @@ -5,18 +5,20 @@ class RewardNoiseWrapper(Wrapper): """ Wrapper to add noise to the reward signal. - Noise can be sampled from a custom distribution or any distribution in numpy's random module + + Noise can be sampled from a custom distribution or any distribution in numpy's random module. """ def __init__( self, env, noise_function=None, noise_dist="standard_normal", dist_args=None ): """ - Initialize wrapper + Initialize wrapper. + Either noise_function or noise_dist and dist_args need to be given Parameters - ------- + ---------- env : gym.Env Environment to wrap noise_function : function @@ -25,6 +27,7 @@ def __init__( Name of distribution to sample noise from dist_args : list Arguments for noise distribution + """ super(RewardNoiseWrapper, self).__init__(env) @@ -37,7 +40,7 @@ def __init__( def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -45,6 +48,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in ["noise_function", "env", "add_noise", "step"]: object.__setattr__(self, name, value) @@ -53,7 +57,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -64,6 +68,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in ["noise_function", "env", "add_noise", "step"]: return object.__getattribute__(self, name) @@ -73,7 +78,7 @@ def __getattribute__(self, name): def step(self, action): """ - Execute environment step and add noise + Execute environment step and add noise. Parameters ---------- @@ -84,6 +89,7 @@ def step(self, action): ------- np.array, float, bool, bool, dict state, reward, terminated, truncated, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) reward += self.noise_function() @@ -92,7 +98,7 @@ def step(self, action): def add_noise(self, dist, args): """ - Make noise function from distribution name and arguments + Make noise function from distribution name and arguments. Parameters ---------- @@ -105,6 +111,7 @@ def add_noise(self, dist, args): ------- function Noise sampling function + """ rng = np.random.default_rng() function = getattr(rng, dist) diff --git a/dacbench/wrappers/state_tracking_wrapper.py b/dacbench/wrappers/state_tracking_wrapper.py index 367ae99b6..6a0833186 100644 --- a/dacbench/wrappers/state_tracking_wrapper.py +++ b/dacbench/wrappers/state_tracking_wrapper.py @@ -10,21 +10,24 @@ class StateTrackingWrapper(Wrapper): """ - Wrapper to track state changed over time + Wrapper to track state changed over time. + Includes interval mode that returns states in lists of len(interval) instead of one long list. """ def __init__(self, env, state_interval=None, logger=None): """ - Initialize wrapper + Initialize wrapper. Parameters - ------- + ---------- env : gym.Env Environment to wrap state_interval : int If not none, mean in given intervals is tracked, too logger : dacbench.logger.ModuleLogger + logger to write to + """ super(StateTrackingWrapper, self).__init__(env) self.state_interval = state_interval @@ -45,7 +48,7 @@ def __init__(self, env, state_interval=None, logger=None): def __setattr__(self, name, value): """ - Set attribute in wrapper if available and in env if not + Set attribute in wrapper if available and in env if not. Parameters ---------- @@ -53,6 +56,7 @@ def __setattr__(self, name, value): Attribute to set value Value to set attribute to + """ if name in [ "state_interval", @@ -74,7 +78,7 @@ def __setattr__(self, name, value): def __getattribute__(self, name): """ - Get attribute value of wrapper if available and of env if not + Get attribute value of wrapper if available and of env if not. Parameters ---------- @@ -85,6 +89,7 @@ def __getattribute__(self, name): ------- value Value of given name + """ if name in [ "state_interval", @@ -107,12 +112,13 @@ def __getattribute__(self, name): def reset(self): """ - Reset environment and record starting state + Reset environment and record starting state. Returns ------- np.array, {} state, info + """ state, info = self.env.reset() self.overall_states.append(state) @@ -126,7 +132,7 @@ def reset(self): def step(self, action): """ - Execute environment step and record state + Execute environment step and record state. Parameters ---------- @@ -137,6 +143,7 @@ def step(self, action): ------- np.array, float, bool, dict state, reward, done, metainfo + """ state, reward, terminated, truncated, info = self.env.step(action) self.overall_states.append(state) @@ -152,7 +159,7 @@ def step(self, action): def get_states(self): """ - Get state progression + Get state progression. Returns ------- @@ -169,14 +176,14 @@ def get_states(self): def render_state_tracking(self): """ - Render state progression + Render state progression. Returns ------- np.array RBG data of state tracking - """ + """ def plot_single(ax=None, index=None, title=None, x=False, y=False): if ax is None: plt.xlabel("Episode") @@ -234,9 +241,6 @@ def plot_single(ax=None, index=None, title=None, x=False, y=False): ax.legend(loc="upper left") return p, p2 - print(self.state_type) - print(spaces.Tuple) - print(self.state_type == spaces.Tuple) if self.state_type == spaces.Discrete: figure = plt.figure(figsize=(20, 20)) canvas = FigureCanvas(figure) diff --git a/pyproject.toml b/pyproject.toml index 3b6fe05c4..7ff56d88d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,11 @@ requires = [ ] build-backend = "setuptools.build_meta" +[tool.pydocstyle] +inherit = false +ignore = 'D100,D212,D401,D203,D404,D104,D400,D415' +match = '.*\.py' + [tool.pytest.ini_options] filterwarnings = [ "ignore::UserWarning", From fbf04c58d1d7f67928f70dceadf9ab9a4c419268 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 16:46:38 +0100 Subject: [PATCH 24/44] stray gym references --- dacbench/envs/toysgd.py | 1 + dacbench/wrappers/instance_sampling_wrapper.py | 2 +- dacbench/wrappers/observation_wrapper.py | 2 +- dacbench/wrappers/performance_tracking_wrapper.py | 2 +- dacbench/wrappers/policy_progress_wrapper.py | 2 +- dacbench/wrappers/reward_noise_wrapper.py | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index abdf0a77b..7bc48dc58 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -233,4 +233,5 @@ def render(self, **kwargs): plt.show() def close(self): + """Close env.""" pass diff --git a/dacbench/wrappers/instance_sampling_wrapper.py b/dacbench/wrappers/instance_sampling_wrapper.py index ca5ea16ef..ae4481b30 100644 --- a/dacbench/wrappers/instance_sampling_wrapper.py +++ b/dacbench/wrappers/instance_sampling_wrapper.py @@ -1,5 +1,5 @@ import numpy as np -from gym import Wrapper +from gymnasium import Wrapper from scipy.stats import norm diff --git a/dacbench/wrappers/observation_wrapper.py b/dacbench/wrappers/observation_wrapper.py index 7b505f0a3..bb0db4cdd 100644 --- a/dacbench/wrappers/observation_wrapper.py +++ b/dacbench/wrappers/observation_wrapper.py @@ -1,5 +1,5 @@ import numpy as np -from gym import Wrapper, spaces +from gymnasium import Wrapper, spaces class ObservationWrapper(Wrapper): diff --git a/dacbench/wrappers/performance_tracking_wrapper.py b/dacbench/wrappers/performance_tracking_wrapper.py index 9b4ccaece..cb3fff49d 100644 --- a/dacbench/wrappers/performance_tracking_wrapper.py +++ b/dacbench/wrappers/performance_tracking_wrapper.py @@ -3,7 +3,7 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sb -from gym import Wrapper +from gymnasium import Wrapper sb.set_style("darkgrid") current_palette = list(sb.color_palette()) diff --git a/dacbench/wrappers/policy_progress_wrapper.py b/dacbench/wrappers/policy_progress_wrapper.py index c8b1b209e..76c53ee13 100644 --- a/dacbench/wrappers/policy_progress_wrapper.py +++ b/dacbench/wrappers/policy_progress_wrapper.py @@ -1,6 +1,6 @@ import matplotlib.pyplot as plt import numpy as np -from gym import Wrapper +from gymnasium import Wrapper class PolicyProgressWrapper(Wrapper): diff --git a/dacbench/wrappers/reward_noise_wrapper.py b/dacbench/wrappers/reward_noise_wrapper.py index a8021cc09..55f42eca0 100644 --- a/dacbench/wrappers/reward_noise_wrapper.py +++ b/dacbench/wrappers/reward_noise_wrapper.py @@ -1,5 +1,5 @@ import numpy as np -from gym import Wrapper +from gymnasium import Wrapper class RewardNoiseWrapper(Wrapper): From 4ff0042139fcaf541492cf58abb6bc7c754d14ce Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 16:52:56 +0100 Subject: [PATCH 25/44] doc links --- dacbench/envs/toysgd.py | 20 +++++++++++++++++--- docs/source/benchmarks.rst | 2 +- docs/source/installation.rst | 2 +- docs/source/multi_agent_dac.rst | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/dacbench/envs/toysgd.py b/dacbench/envs/toysgd.py index 7bc48dc58..94629d55f 100644 --- a/dacbench/envs/toysgd.py +++ b/dacbench/envs/toysgd.py @@ -14,6 +14,7 @@ def create_polynomial_instance_set( low: float = -10, high: float = 10, ): + """Make instance set.""" instances = [] for i in range(n_samples): coeffs = sample_coefficients(order=order, low=low, high=high) @@ -31,6 +32,7 @@ def create_polynomial_instance_set( def sample_coefficients(order: int = 2, low: float = -10, high: float = 10): + """Sample function coefficients.""" n_coeffs = order + 1 coeffs = np.zeros((n_coeffs,)) coeffs[0] = np.random.uniform(0, high, size=1) @@ -42,7 +44,6 @@ class ToySGDEnv(AbstractMADACEnv): """ Optimize toy functions with SGD + Momentum. - Action: [log_learning_rate, log_momentum] (log base 10) State: Dict with entries remaining_budget, gradient, learning_rate, momentum Reward: negative log regret of current and true function value @@ -58,6 +59,7 @@ class ToySGDEnv(AbstractMADACEnv): """ def __init__(self, config): + """Init env.""" super(ToySGDEnv, self).__init__(config) self.n_steps_max = config.get("cutoff", 1000) @@ -76,6 +78,7 @@ def __init__(self, config): self.n_steps = 0 # type: Optional[int] def build_objective_function(self): + """Make base function.""" if self.instance["family"] == "polynomial": order = int(self.instance["order"]) if order != 2: @@ -102,13 +105,14 @@ def build_objective_function(self): ) def get_initial_position(self): + """Get initial position.""" return 0 # np.random.uniform(-5, 5, size=self.n_dim-1) def step( self, action: Union[float, Tuple[float, float]] ) -> Tuple[Dict[str, float], float, bool, Dict]: """ - Take one step with SGD + Take one step with SGD. Parameters ---------- @@ -126,6 +130,7 @@ def step( - terminated : bool - truncated : bool - info : Dict + """ truncated = super(ToySGDEnv, self).step_() info = {} @@ -172,7 +177,14 @@ def step( def reset(self, seed=None, options={}): """ - Reset environment + Reset environment. + + Parameters + ---------- + seed : int + seed + options : dict + options dict (not used) Returns ------- @@ -180,6 +192,7 @@ def reset(self, seed=None, options={}): Environment state dict Meta-info + """ super(ToySGDEnv, self).reset_(seed) @@ -204,6 +217,7 @@ def reset(self, seed=None, options={}): }, {} def render(self, **kwargs): + """Render progress.""" import matplotlib.pyplot as plt history = np.array(self.history).flatten() diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index e8ff0a408..f194edb42 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -18,7 +18,7 @@ They are both based on artificial functions and real algorithms: Sigmoid function approximation in multiple dimensions. - :doc:`Luby ` (Artificial Benchmark): Learning the Luby sequence. -- :doc:`ToySGD ` (Artificial Benchmark): +- :doc:`ToySGD ` (Artificial Benchmark): Controlling the learning rate in gradient descent. - :doc:`Geometric ` (Artificial Benchmark): Approximating several functions at once. diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 29a77655b..c426b0efb 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -5,7 +5,7 @@ How to Install DACBench ======================= This is a guide on how to install DACBench and its benchmarks. Alternatively, you can also -use `pre-built containers containers `_. +use `pre-built containers `. .. role:: bash(code) :language: bash diff --git a/docs/source/multi_agent_dac.rst b/docs/source/multi_agent_dac.rst index dddfb7384..40e7d4773 100644 --- a/docs/source/multi_agent_dac.rst +++ b/docs/source/multi_agent_dac.rst @@ -15,7 +15,7 @@ In order to create a Multi-Agent DACBench environment, select either of the foll - :doc:`Sigmoid ` (Artificial Benchmark): Sigmoid function approximation in multiple dimensions. -- :doc:`ToySGD ` (Artificial Benchmark): +- :doc:`ToySGD ` (Artificial Benchmark): Controlling the learning rate in gradient descent. - :doc:`Geometric ` (Artificial Benchmark): Approximating several functions at once. From ef6ef918cf9fc07a86b99b271c1bc93b6f1513ef Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 17:07:36 +0100 Subject: [PATCH 26/44] Some more docstrings --- .pre-commit-config.yaml | 5 -- dacbench/envs/sigmoid.py | 49 +++++++----- dacbench/envs/theory.py | 161 ++++++++++++++++++++++++++------------- 3 files changed, 135 insertions(+), 80 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8a863aa2..4f267ebf6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,8 +9,3 @@ repos: rev: 3.8.4 hooks: - id: flake8 -- repo: https://github.com/PyCQA/pydocstyle - rev: master - hooks: - - id: pydocstyle - exclude: 'dacbench/envs/rl-plan/*' diff --git a/dacbench/envs/sigmoid.py b/dacbench/envs/sigmoid.py index 682256f31..a685ff25f 100644 --- a/dacbench/envs/sigmoid.py +++ b/dacbench/envs/sigmoid.py @@ -1,9 +1,11 @@ """ -Sigmoid environment from +Sigmoid environment from: + "Dynamic Algorithm Configuration:Foundation of a New Meta-Algorithmic Framework" by A. Biedenkapp and H. F. Bozkurt and T. Eimer and F. Hutter and M. Lindauer. Original environment authors: André Biedenkapp, H. Furkan Bozkurt """ + from typing import List import matplotlib.cm as cm @@ -14,9 +16,7 @@ class SigmoidEnv(AbstractMADACEnv): - """ - Environment for tracing sigmoid curves - """ + """Environment for tracing sigmoid curves.""" def _sig(self, x, scaling, inflection): """Simple sigmoid function""" @@ -24,12 +24,13 @@ def _sig(self, x, scaling, inflection): def __init__(self, config) -> None: """ - Initialize Sigmoid Env + Initialize Sigmoid Env. Parameters - ------- + ---------- config : objdict Environment configuration + """ super(SigmoidEnv, self).__init__(config) @@ -52,7 +53,7 @@ def __init__(self, config) -> None: def step(self, action: int): """ - Execute environment step + Execute environment step. Parameters ---------- @@ -63,6 +64,7 @@ def step(self, action: int): ------- np.array, float, bool, bool, dict state, reward, terminated, truncated, info + """ self.done = super(SigmoidEnv, self).step_() self.last_action = action @@ -72,12 +74,13 @@ def step(self, action: int): def reset(self, seed=None, options={}) -> List[int]: """ - Resets env + Resets env. Returns ------- numpy.array Environment state + """ super(SigmoidEnv, self).reset_(seed) self.shifts = self.instance[: self.n_actions] @@ -86,6 +89,7 @@ def reset(self, seed=None, options={}) -> List[int]: return self.get_state(self), {} def get_default_reward(self, _): + """Get default reward.""" r = [ 1 - np.abs(self._sig(self.c_step, slope, shift) - (act / (max_act - 1))) for slope, shift, act, max_act in zip( @@ -97,6 +101,7 @@ def get_default_reward(self, _): return r def get_default_state(self, _): + """Get default state representation.""" remaining_budget = self.n_steps - self.c_step next_state = [remaining_budget] for shift, slope in zip(self.shifts, self.slopes): @@ -110,23 +115,25 @@ def get_default_state(self, _): def close(self) -> bool: """ - Close Env + Close Env. Returns ------- bool Closing confirmation + """ return True def render(self, mode: str) -> None: """ - Render env in human mode + Render env in human mode. Parameters ---------- mode : str Execution mode + """ if mode == "human" and self.n_actions == 2: plt.ion() @@ -151,24 +158,23 @@ def render(self, mode: str) -> None: class ContinuousStateSigmoidEnv(SigmoidEnv): - """ - Environment for tracing sigmoid curves with a continuous state on the x-axis - """ + """Environment for tracing sigmoid curves with a continuous state on the x-axis.""" def __init__(self, config) -> None: """ - Initialize Sigmoid Env + Initialize Sigmoid Env. Parameters - ------- + ---------- config : objdict Environment configuration + """ super().__init__(config) def step(self, action: int): """ - Execute environment step + Execute environment step. Parameters ---------- @@ -179,6 +185,7 @@ def step(self, action: int): ------- np.array, float, bool, dict state, reward, done, info + """ self.last_action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along @@ -201,18 +208,17 @@ def step(self, action: int): class ContinuousSigmoidEnv(SigmoidEnv): - """ - Environment for tracing sigmoid curves with a continuous state on the x-axis - """ + """Environment for tracing sigmoid curves with a continuous state on the x-axis.""" def __init__(self, config) -> None: """ - Initialize Sigmoid Env + Initialize Sigmoid Env. Parameters - ------- + ---------- config : objdict Environment configuration + """ super().__init__(config) @@ -229,6 +235,7 @@ def step(self, action: np.ndarray): ------- np.array, float, bool, dict state, reward, done, info + """ self.last_action = action # The reward measures how wrong the choice was so we can take this error to determine how far we travel along diff --git a/dacbench/envs/theory.py b/dacbench/envs/theory.py index 2937c9c7e..e5a61068b 100644 --- a/dacbench/envs/theory.py +++ b/dacbench/envs/theory.py @@ -10,16 +10,16 @@ class BinaryProblem: - """ - An abstract class for an individual in binary representation - """ + """An abstract class for an individual in binary representation.""" def __init__(self, n, rng=np.random.default_rng()): + """Init problem.""" self.data = rng.choice([True, False], size=n) self.n = n self.fitness = self.eval() def initialise_with_fixed_number_of_bits(self, k, rng=np.random.default_rng()): + """Init with given number of bits.""" nbits = self.data.sum() if nbits < k: ids = rng.choice( @@ -29,12 +29,15 @@ def initialise_with_fixed_number_of_bits(self, k, rng=np.random.default_rng()): self.eval() def is_optimal(self): + """Get is_optimal flag.""" pass def get_optimal(self): + """Get optimum.""" pass def eval(self): + """Evaluate fitness.""" pass def get_fitness_after_flipping(self, locs): @@ -42,44 +45,50 @@ def get_fitness_after_flipping(self, locs): Calculate the change in fitness after flipping the bits at positions locs Parameters - ----------- - locs: 1d-array - positions where bits are flipped + ---------- + locs: 1d-array + positions where bits are flipped - Returns: int - ----------- + Returns + ------- objective after flipping + """ raise NotImplementedError def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): """ - Calculate fitness of the child aftering being crossovered with xprime + Calculate fitness of the child aftering being crossovered with xprime. Parameters - ----------- - xprime: 1d boolean array - the individual to crossover with - locs_x: 1d boolean/integer array - positions where we keep current bits of self - locs_xprime: : 1d boolean/integer array - positions where we change to xprime's bits - - Returns: fitness of the new individual after crossover - ----------- + ---------- + xprime: 1d boolean array + the individual to crossover with + locs_x: 1d boolean/integer array + positions where we keep current bits of self + locs_xprime: : 1d boolean/integer array + positions where we change to xprime's bits + + Returns + ------- + fitness of the new individual after crossover + """ raise NotImplementedError def flip(self, locs): """ - flip the bits at position indicated by locs + Flip the bits at position indicated by locs. Parameters - ----------- - locs: 1d-array - positions where bits are flipped + ---------- + locs: 1d-array + positions where bits are flipped + + Returns + ------- + the new individual after the flip - Returns: the new individual after the flip """ child = deepcopy(self) child.data[locs] = ~child.data[locs] @@ -88,18 +97,20 @@ def flip(self, locs): def combine(self, xprime, locs_xprime): """ - combine (crossover) self and xprime by taking xprime's bits at locs_xprime and self's bits at other positions + Combine (crossover) self and xprime by taking xprime's bits at locs_xprime and self's bits at other positions. Parameters - ----------- - xprime: 1d boolean array - the individual to crossover with - locs_x: 1d boolean/integer array - positions where we keep current bits of self - locs_xprime: : 1d boolean/integer array - positions where we change to xprime's bits - - Returns: the new individual after the crossover + ---------- + xprime: 1d boolean array + the individual to crossover with + locs_x: 1d boolean/integer array + positions where we keep current bits of self + locs_xprime: : 1d boolean/integer array + positions where we change to xprime's bits + + Returns + ------- + the new individual after the crossover """ child = deepcopy(self) @@ -109,9 +120,14 @@ def combine(self, xprime, locs_xprime): def mutate(self, p, n_childs, rng=np.random.default_rng()): """ - Draw l ~ binomial(n, p), l>0 + Draw l ~ binomial(n, p), l>0. + Generate n_childs children by flipping exactly l bits - Return: the best child (maximum fitness), its fitness and number of evaluations used + + Returns + ------- + the best child (maximum fitness), its fitness and number of evaluations used + """ assert p >= 0 @@ -137,8 +153,12 @@ def mutate(self, p, n_childs, rng=np.random.default_rng()): def mutate_rls(self, l, rng=np.random.default_rng()): """ - generate a child by flipping exactly l bits - Return: child, its fitness + Generate a child by flipping exactly l bits. + + Returns + ------- + child, its fitness + """ assert l >= 0 @@ -160,11 +180,25 @@ def crossover( rng=np.random.default_rng(), ): """ - Crossover operator: - for each bit, taking value from x with probability p and from self with probability 1-p - Arguments: - x: the individual to crossover with - p (float): in [0,1] + Crossover operation in population. + + Crossover operator: for each bit, taking value from x with probability p and from self with probability 1-p + + Parameters + ---------- + xprime + the individual to crossover with + p : float + probability in [0,1] + n_childs : int + number of child individuals + include_xprime : bool + whether to inculde x + count_different_inds_only : bool + whether to only count different individuals + rng: + random number generator + """ assert p <= 1 @@ -212,11 +246,13 @@ def crossover( class LeadingOne(BinaryProblem): """ - An individual for LeadingOne problem + An individual for LeadingOne problem. + The aim is to maximise the number of leading (and consecutive) 1 bits in the string """ def __init__(self, n, rng=np.random.default_rng(), initObj=None): + """Make individual""" if initObj is None: super(LeadingOne, self).__init__(n=n, rng=rng) else: @@ -227,6 +263,7 @@ def __init__(self, n, rng=np.random.default_rng(), initObj=None): self.fitness = self.eval() def eval(self): + """Evaluate fitness.""" k = self.data.argmin() if self.data[k]: self.fitness = self.n @@ -235,12 +272,15 @@ def eval(self): return self.fitness def is_optimal(self): + """Return is_optimal flag.""" return self.data.all() def get_optimal(self): + """Return optimum.""" return self.n def get_fitness_after_flipping(self, locs): + """Return fitness after flipping.""" min_loc = locs.min() if min_loc < self.fitness: return min_loc @@ -255,6 +295,7 @@ def get_fitness_after_flipping(self, locs): return new_fitness def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): + """Return fitness after crossover.""" child = self.combine(xprime, locs_xprime) child.eval() return child.fitness @@ -266,18 +307,22 @@ def get_fitness_after_crossover(self, xprime, locs_x, locs_xprime): class RLSEnv(AbstractEnv): """ - Environment for RLS with step size + Environment for RLS with step size. + Current assumption: we only consider (1+1)-RLS, so there's only one parameter to tune (r) """ def __init__(self, config, test_env=False) -> None: """ - Initialize RLSEnv + Initialize RLSEnv. Parameters - ------- + ---------- config : objdict Environment configuration + test_env : bool + whether to use test mode + """ super(RLSEnv, self).__init__(config) self.logger = logging.getLogger(self.__str__()) @@ -358,20 +403,25 @@ def __init__(self, config, test_env=False) -> None: def get_obs_domain_from_name(var_name): """ Get default lower and upperbound of a observation variable based on its name. + The observation space will then be created - Return: + + Returns + ------- Two int values, e.g., 1, np.inf + """ return 0, np.inf def reset(self, seed=None, options={}): """ - Resets env + Resets env. Returns ------- numpy.array Environment state + """ super(RLSEnv, self).reset_(seed) @@ -413,11 +463,12 @@ def reset(self, seed=None, options={}): return self.get_state(), {} def get_state(self): + """Return state.""" return np.asarray([f() for f in self.state_functions]) def step(self, action): """ - Execute environment step + Execute environment step. Parameters ---------- @@ -428,6 +479,7 @@ def step(self, action): ------- state, reward, terminated, truncated, info np.array, float, bool, bool, dict + """ truncated = super(RLSEnv, self).step_() @@ -539,7 +591,7 @@ def step(self, action): def close(self) -> bool: """ - Close Env + Close Env. No additional cleanup necessary @@ -547,16 +599,16 @@ def close(self) -> bool: ------- bool Closing confirmation + """ return True class RLSEnvDiscrete(RLSEnv): - """ - RLS environment where the choices of r is discretised - """ + """RLS environment where the choices of r is discretised.""" def __init__(self, config, test_env=False): + """Init env.""" super(RLSEnvDiscrete, self).__init__(config, test_env) assert ( "action_choices" in config @@ -571,6 +623,7 @@ def __init__(self, config, test_env=False): self.action_choices = config["action_choices"] def step(self, action): + """Take step.""" if isinstance(action, np.ndarray) or isinstance(action, list): assert len(action) == 1 action = action[0] From 34a0ab5fd1cccf25086fee5411a6fa7392c5fec2 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Fri, 24 Mar 2023 17:36:30 +0100 Subject: [PATCH 27/44] updated structure --- repo_structure.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/repo_structure.md b/repo_structure.md index 42e4eea54..eb94342e1 100644 --- a/repo_structure.md +++ b/repo_structure.md @@ -11,8 +11,6 @@ This file gives on overview the poruses of the different files and folders: ├── LICENSE: the licence for this software ├── pyproject.toml: configuration file for setuptools, tests (pytest, coverage), black (code formatter) ├── README.md: project readme -├── run_ppo.sh: shell script to run ppo baselines on SLURM -├── run.py: runs random agent on ModCMA ├── runscripts: shell scripts to run baselines on SLURM ├── setup.cfg: pip-package config. Contains: dependencies, extras and thier dependencies, tags, project meta ├── setup.py: dummy setup.py require for downward compatibility From f545a0bea247850eed1ff07cf1b47e33056ebd8c Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 12:17:51 +0200 Subject: [PATCH 28/44] dont build fd remotely --- .github/workflows/pytest.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index b61efbbda..a9bae975d 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -31,16 +31,10 @@ jobs: uses: actions/setup-python@v4 with: python-version: '3.10' - - name: Setup cmake - uses: jwlawson/actions-setup-cmake@v1.13 - with: - cmake-version: '3.10.2' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e.[dev,example,all] - - name: Build fast-downward - run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest run: coverage run -m pytest --html=test-report.html - name: Run coverage From 159ea668a7141e9c729e624bf0120e17997b28e5 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 12:36:25 +0200 Subject: [PATCH 29/44] build fd --- .github/workflows/pytest.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index a9bae975d..16509aad4 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -35,6 +35,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -e.[dev,example,all] + - name: Build fast-downward + run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest run: coverage run -m pytest --html=test-report.html - name: Run coverage From 5e26d3db768810db164c7c364be295624b8502f9 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 12:37:18 +0200 Subject: [PATCH 30/44] no more readthedocs config file --- .readthedocs.yaml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index 686486a6c..000000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# use version 2, which is now recommended -version: 2 - -# Build from the docs/ directory with Sphinx -sphinx: - configuration: docs/conf.py - -# build all -formats: all - -# Explicitly set the version of Python and its requirements -python: - version: 3.10 - install: - - method: pip - path: . - extra_requirements: - - docs From c618c41f584a06293230efa81884d6451acb88c7 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 13:37:16 +0200 Subject: [PATCH 31/44] gnu version in workflow --- .github/workflows/pytest.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 16509aad4..d574e4f18 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -35,6 +35,11 @@ jobs: run: | python -m pip install --upgrade pip pip install -e.[dev,example,all] + - name: Set up GCC + uses: egor-tensin/setup-gcc@v1 + with: + version: '7.5.0' + platform: x64 - name: Build fast-downward run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest From 7d15d0f9c61707139b891fd2bfc487e21ab91ad7 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 13:39:16 +0200 Subject: [PATCH 32/44] maint --- .github/workflows/pytest.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index d574e4f18..09811c65e 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -35,11 +35,11 @@ jobs: run: | python -m pip install --upgrade pip pip install -e.[dev,example,all] - - name: Set up GCC - uses: egor-tensin/setup-gcc@v1 - with: - version: '7.5.0' - platform: x64 + - name: Set up GCC + uses: egor-tensin/setup-gcc@v1 + with: + version: '7.5.0' + platform: x64 - name: Build fast-downward run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest From c52da8b3c4e80f1eed80cbcba57ddc7e3f1626e1 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 14:13:58 +0200 Subject: [PATCH 33/44] maint --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 09811c65e..57c876583 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -10,7 +10,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 with: From 8e68535c8315e4cd974e90bdbef9b56069f162a9 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 14:20:42 +0200 Subject: [PATCH 34/44] maint --- .github/workflows/pytest.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 57c876583..4d29e0bdb 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -35,11 +35,6 @@ jobs: run: | python -m pip install --upgrade pip pip install -e.[dev,example,all] - - name: Set up GCC - uses: egor-tensin/setup-gcc@v1 - with: - version: '7.5.0' - platform: x64 - name: Build fast-downward run: ./dacbench/envs/rl-plan/fast-downward/build.py - name: Run tests with pytest From 450a712cdfe5bf0b6c2d02711740e2791f31f8d5 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Wed, 29 Mar 2023 14:50:58 +0200 Subject: [PATCH 35/44] maint --- tests/benchmarks/test_fd_benchmark.py | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/benchmarks/test_fd_benchmark.py b/tests/benchmarks/test_fd_benchmark.py index 456657320..3a9517216 100644 --- a/tests/benchmarks/test_fd_benchmark.py +++ b/tests/benchmarks/test_fd_benchmark.py @@ -17,25 +17,25 @@ def test_get_env(self): env = bench.get_environment() self.assertTrue(issubclass(type(env), FastDownwardEnv)) - def test_scenarios(self): - scenarios = [ - "fd_barman.json", - # "fd_blocksworld.json", - # "fd_visitall.json", - # "fd_childsnack.json", - # "fd_sokoban.json", - # "fd_rovers.json", - ] - for s in scenarios: - path = os.path.join("dacbench/additional_configs/fast_downward/", s) - bench = FastDownwardBenchmark(path) - self.assertTrue(bench.config is not None) - env = bench.get_environment() - state, info = env.reset() - self.assertTrue(state is not None) - self.assertTrue(info is not None) - state, _, _, _, _ = env.step(0) - self.assertTrue(state is not None) + # def test_scenarios(self): + # scenarios = [ + # "fd_barman.json", + # # "fd_blocksworld.json", + # # "fd_visitall.json", + # # "fd_childsnack.json", + # # "fd_sokoban.json", + # # "fd_rovers.json", + # ] + # for s in scenarios: + # path = os.path.join("dacbench/additional_configs/fast_downward/", s) + # bench = FastDownwardBenchmark(path) + # self.assertTrue(bench.config is not None) + # env = bench.get_environment() + # state, info = env.reset() + # self.assertTrue(state is not None) + # self.assertTrue(info is not None) + # state, _, _, _, _ = env.step(0) + # self.assertTrue(state is not None) def test_save_conf(self): bench = FastDownwardBenchmark() From 42534a42df5f2ca0dfbf697a26df93a770135250 Mon Sep 17 00:00:00 2001 From: Theresa Eimer Date: Thu, 30 Mar 2023 13:38:08 +0200 Subject: [PATCH 36/44] Examples --- README.md | 17 +-- dacbench/__init__.py | 13 +++ dacbench/abstract_benchmark.py | 1 - dacbench/benchmarks/theory_benchmark.py | 10 +- dacbench/container/remote_env.py | 2 +- dacbench/envs/__init__.py | 19 +--- dacbench/envs/theory.py | 16 +-- docs/source/benchmarks.rst | 8 ++ examples/baselines_ppo.py | 73 ------------- examples/benchmarks/baselines_ppo_sigmoid.py | 51 --------- examples/benchmarks/chainerrl_cma.py | 52 --------- examples/benchmarks/ray_dqn_fd.py | 24 ---- examples/coax_ppo_cmaes.py | 103 ++++++++++++++++++ examples/multi_agent_sigmoid.py | 19 ++++ examples/ray_ppo.py | 6 +- .../tabular_luby.py => tabular_rl_luby.py} | 0 tests/benchmarks/test_fd_benchmark.py | 2 + 17 files changed, 172 insertions(+), 244 deletions(-) delete mode 100644 examples/baselines_ppo.py delete mode 100644 examples/benchmarks/baselines_ppo_sigmoid.py delete mode 100644 examples/benchmarks/chainerrl_cma.py delete mode 100644 examples/benchmarks/ray_dqn_fd.py create mode 100644 examples/coax_ppo_cmaes.py create mode 100644 examples/multi_agent_sigmoid.py rename examples/{benchmarks/tabular_luby.py => tabular_rl_luby.py} (100%) diff --git a/README.md b/README.md index 7bfbc5285..e6c45996f 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,7 @@ -