Skip to content

Commit

Permalink
Simplifies isolation mechanisms (#224)
Browse files Browse the repository at this point in the history
* Clarifies registration and env creation using create

* Removes problem registration from all black boxes

* Fixes a misimport in toy function testing

* Modifies the logic of the force isolation test

* Removes problem registration in create

* Refactors some of the utilities of isolation

* removes problem registration related functions

* removes external black boxes and problem factory scripts

* Removes force registration kwarg

* Improves comments and docs

* Runs the ruff linter

* Cleans comments in objective factory

* Adds a force isolation flag to the abstract black box

* Changes the commit message on rmf
  • Loading branch information
miguelgondu authored Aug 2, 2024
1 parent 2b4142a commit 9261a9d
Show file tree
Hide file tree
Showing 63 changed files with 170 additions and 1,513 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-tox-testing-rmf-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ jobs:
- name: Install dependencies
run: |
python -m pip install tox
- name: Test rmf-related black boxes with tox and pytest
- name: Test RMF-related black boxes with tox and pytest
run: |
tox -c tox.ini -e poli-rmf-py39
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
parallelize=True,
num_workers=5,
batch_size=10,
force_register=True,
)
f, x0 = foldx_problem_in_parallel.black_box, foldx_problem_in_parallel.x0
print("Running in parallel")
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 2 additions & 0 deletions src/poli/core/abstract_black_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(
parallelize: bool = False,
num_workers: int = None,
evaluation_budget: int = float("inf"),
force_isolation: bool = False,
):
"""
Initialize the AbstractBlackBox object.
Expand All @@ -95,6 +96,7 @@ def __init__(
self.parallelize = parallelize
self.evaluation_budget = evaluation_budget
self.num_evaluations = 0
self.force_isolation = force_isolation

if num_workers is None:
num_workers = cpu_count() // 2
Expand Down
5 changes: 4 additions & 1 deletion src/poli/core/abstract_problem_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def create(
parallelize: bool = False,
num_workers: int = None,
evaluation_budget: int = float("inf"),
force_isolation: bool = False,
) -> Problem:
"""
Returns a blackbox function and initial observations.
Expand All @@ -75,7 +76,9 @@ def create(
The number of workers for parallel evaluation. Default is None.
evaluation_budget: int, optional
The maximum number of function evaluations. Default is infinity.
force_isolation: bool, optional
Whether to force the isolation of the black box. Default
is False.
Returns
--------
problem: AbstractProblem
Expand Down
171 changes: 0 additions & 171 deletions src/poli/core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@
"""

import configparser
import subprocess
import warnings
from pathlib import Path
from typing import List, Type, Union

from poli.core.abstract_black_box import AbstractBlackBox
from poli.core.abstract_isolated_function import AbstractIsolatedFunction
from poli.core.abstract_problem_factory import AbstractProblemFactory
from poli.core.util.abstract_observer import AbstractObserver
from poli.core.util.objective_management.make_run_script import (
make_isolated_function_script,
make_observer_script,
make_run_script,
)

# from poli.objective_repository import AVAILABLE_PROBLEM_FACTORIES, AVAILABLE_OBJECTIVES
Expand Down Expand Up @@ -125,59 +122,6 @@ def remove_default_observer():
_write_config()


def register_problem(
problem_factory: AbstractProblemFactory,
conda_environment_name: Union[str, Path] = None,
python_paths: List[str] = None,
force: bool = True,
**kwargs,
):
"""Registers a problem.
This function takes a problem factory, a conda environment, a list of python
environments, and additional keyword arguments. With these, it creates a
script that can be run to instantiate the problem factory in a separate
process. It also sets the configuration so that the problem factory can be
instantiated later.
Parameters
----------
problem_factory : AbstractProblemFactory or str
The problem factory to be registered.
conda_environment_name : str or Path
The name or path of the conda environment to be used.
python_paths : List[str]
A list of paths to append to the python path of the run script.
force : bool
Flag indicating whether to overwrite the existing problem.
**kwargs : dict
Additional keyword arguments to be passed to the problem factory.
"""
if "conda_environment_location" in kwargs:
conda_environment_name = kwargs["conda_environment_location"]

problem_name = problem_factory.get_setup_information().get_problem_name()
if problem_name not in config.sections():
config.add_section(problem_name)
elif not force:
# If force is false, we warn the user and ask for confirmation
user_input = input(
f"Problem {problem_name} already exists. "
f"Do you want to overwrite it? (y/[n]) "
)
if user_input.lower() != "y":
warnings.warn(f"Problem {problem_name} already exists. Not overwriting.")
return

warnings.warn(f"Problem {problem_name} already exists. Overwriting.")

run_script_location = make_run_script(
type(problem_factory), conda_environment_name, python_paths, **kwargs
)
config[problem_name][_RUN_SCRIPT_LOCATION] = run_script_location
_write_config()


def register_isolated_function(
isolated_function: Union[AbstractBlackBox, AbstractIsolatedFunction],
name: str,
Expand Down Expand Up @@ -216,121 +160,6 @@ def register_isolated_function(
_write_config()


def register_problem_from_repository(name: str, quiet: bool = False):
"""Registers a problem from the repository.
This function takes a problem name, and registers it. The problem name
corresponds to a folder inside the objective_repository folder. The
function will:
1. create the environment from the yaml file
2. run the file from said enviroment (since we can't
import the factory: it may have dependencies that are
not installed)
Parameters
----------
name : str
The name of the problem to be registered.
quiet : bool, optional
If True, we squelch the feedback about environment creation and
problem registration, by default False.
"""
# the name is actually the folder inside
# poli/objective_repository, so we need
# to
# 1. create the environment from the yaml file
# 2. run the file from said enviroment (since
# we can't import the factory: it may have
# dependencies that are not installed)

# Load up the environment name
PATH_TO_REPOSITORY = (
Path(__file__).parent.parent / "objective_repository"
).resolve()

with open(PATH_TO_REPOSITORY / name / "environment.yml", "r") as f:
# This is a really crude way of doing this,
# but it works. We should probably use a
# yaml parser instead, but the idea is to keep
# the dependencies to a minimum.
yml = f.read()
lines = yml.split("\n")
conda_env_name_line = lines[0]
assert conda_env_name_line.startswith("name:"), (
"The first line of the environment.yml file "
"should be the name of the environment"
)
env_name = lines[0].split(":")[1].strip()

# Moreover, we should only be doing this
# if the problem is not already registered.
# TODO: do we?
if name in config.sections():
warnings.warn(f"Problem {name} already registered. Skipping")
return

# 1. create the environment from the yaml file
if not quiet:
print(f"poli 🧪: creating environment {env_name} from {name}/environment.yml")
try:
subprocess.run(
" ".join(
[
"conda",
"env",
"create",
"-f",
str(PATH_TO_REPOSITORY / name / "environment.yml"),
]
),
shell=True,
check=True,
capture_output=True,
)
except subprocess.CalledProcessError as e:
if "already exists" in e.stderr.decode():
if not quiet:
print(
f"poli 🧪: creating environment {env_name} from {name}/environment.yml"
)
warnings.warn(f"Environment {env_name} already exists. Will not create it.")
else:
raise e

# 2. run the file from said enviroment (since
# we can't import the factory: it may have
# dependencies that are not installed)

# Running the file
file_to_run = PATH_TO_REPOSITORY / name / "register.py"
command = " ".join(["conda", "run", "-n", env_name, "python", str(file_to_run)])
warnings.warn("Running the following command: %s. " % command)

if not quiet:
print(f"poli 🧪: running registration of {name} from environment {env_name}")
try:
subprocess.run(command, check=True, shell=True, capture_output=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(
f"Found error when running {file_to_run} from environment {env_name}: \n"
f"{e.stderr.decode()}"
)


def delete_problem(problem_name: str):
"""Deletes a problem.
This function takes a problem name, and deletes it from the configuration.
Parameters
----------
problem_name : str
The name of the problem to be deleted.
"""
config.remove_section(problem_name)
_write_config()


def _write_config():
with open(config_file, "w+") as configfile:
config.write(configfile)
Loading

0 comments on commit 9261a9d

Please sign in to comment.