Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplifies isolation mechanisms #224

Merged
merged 15 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading