<commit_before>__author__ = '<NAME>'

from apsis.assistants.experiment_assistant import ExperimentAssistant
from apsis.utilities.file_utils import ensure_directory_exists
import time
import datetime
import os
import json
from apsis.utilities.logging_utils import get_logger
from apsis.utilities.plot_utils import plot_lists, write_plot_to_file
import matplotlib.pyplot as plt
import uuid
import copy
import numpy as np
import apsis.models.experiment as experiment

# These are the colours supported by the plot.
COLORS = ["g", "r", "c", "b", "m", "y"]


class LabAssistant(object):
    """
    This is used to control multiple experiments at once.

    This is done by abstracting a dict of named experiment assistants.

    Attributes
    ----------
    _exp_assistants : dict of ExperimentAssistants.
        The dictionary of experiment assistants this LabAssistant uses.
    _write_directory_base : String, optional
        The directory to write all the results and plots to.
    _logger : logging.logger
        The logger for this class.
    """
    _exp_assistants = None

    _write_directory_base = None
    _lab_run_directory = None
    _global_start_date = None
    _logger = None



    def __init__(self, write_directory_base=None, continue_path=None):
        """
        Initializes the lab assistant.

        Parameters
        ----------
        write_directory_base : string, optional
            Sets the base write directory for the lab assistant. If None
            (default) the directory depends on the operating system.
            ./APSIS_WRITING if on Windows, /tmp/APSIS_WRITING otherwise.
        continue_path : string, optional
            The path for continuing the experiment. If None (default) a new
            lab assistant is started.
        """
        self._logger = get_logger(self)
        if write_directory_base is None:
            if os.name == "nt":
                write_directory_base = os.path.relpath("APSIS_WRITING")
            else:
                write_directory_base = "/tmp/APSIS_WRITING"

        self._logger.info("Initializing lab assistant.")
        self._logger.info("Writing results to %s" %write_directory_base)
        self._write_directory_base = write_directory_base

        self._exp_assistants = {}
        if continue_path is None:
            self._global_start_date = time.time()
            self._init_directory_structure()
        else:
            # set the correct path.
            self._lab_run_directory = continue_path
            with open(continue_path + "/lab_assistant.json", 'r') as infile:
                lab_assistant_json = json.load(infile)
            self._global_start_date = lab_assistant_json["global_start_date"]
            for p in lab_assistant_json["exp_assistants"].values():
                self._load_exp_assistant_from_path(p)

        self._write_state_to_file(self._lab_run_directory)
        self._logger.info("lab assistant successfully initialized.")

    def init_experiment(self, name, optimizer, param_defs, exp_id=None,
                        notes=None, optimizer_arguments=None,
                        minimization=True):
        """
        Initializes an experiment.

        Parameters
        ----------
        name : string
            name of the experiment.
        optimizer : string
            String representation of the optimizer.
        param_defs : dict of parameter definitions
            Dictionary of parameter definition classes.
        optimizer_arguments : dict, optional
            A dictionary defining the operation of the optimizer. See the
            respective documentation of the optimizers.
            Default is None, which are default values.
        exp_id : string or None, optional
            The id of the experiment, which will be used to reference it.
            Should be a proper uuid, and especially has to be unique. If it is
            not, an error may be returned.
        notes : jsonable object or None, optional
            Any note that you'd like to put in the experiment. Could be used
            to provide some details on the experiment, on the start time or the
            user starting it.
        minimization : bool, optional
            Whether the problem is one of minimization. Defaults to True.

        Returns
        -------
        exp_id : string
            String representing the id of the experiment or "failed" if failed.

        Raises
        ------
        ValueError :
            Iff there already is an experiment with the exp_id for this lab
            assistant. Does not occur if no exp_id is given.
        """
        if exp_id in self._exp_assistants.keys():
            raise ValueError("Already an experiment with id %s registered."
                             %exp_id)

        if exp_id is None:
            while True:
                exp_id = uuid.uuid4().hex
                if exp_id not in self._exp_assistants.keys():
                    break

        exp_assistant_write_directory = os.path.join(self._lab_run_directory +
                                                     "/" + exp_id)

        ensure_directory_exists(exp_assistant_write_directory)

        exp = experiment.Experiment(name,
                                    param_defs,
                                    exp_id,
                                    notes,
                                    minimization)

        exp_ass = ExperimentAssistant(optimizer,
                                      experiment=exp,
                                      optimizer_arguments=optimizer_arguments,
                                      write_dir=exp_assistant_write_directory,
                                      csv_write_frequency=1)
        self._exp_assistants[exp_id] = exp_ass
        self._logger.info("Experiment initialized successfully.")
        self._write_state_to_file(self._lab_run_directory)
        return exp_id

    def _init_directory_structure(self):
        """
        Method to create the directory structure if it does not exist
        for results and plot writing.
        """
        if self._lab_run_directory is None:
            date_name = datetime.datetime.utcfromtimestamp(
                self._global_start_date).strftime("%Y-%m-%d_%H.%M.%S")

            self._lab_run_directory = os.path.join(self._write_directory_base,
                                                  date_name)

            ensure_directory_exists(self._lab_run_directory)

    def _load_exp_assistant_from_path(self, path):
        with open(path + "/exp_assistant.json", 'r') as infile:
            exp_assistant_json = json.load(infile)

        optimizer_class = exp_assistant_json["optimizer_class"]
        optimizer_arguments = exp_assistant_json["optimizer_arguments"]
        exp_ass_write_dir = exp_assistant_json["write_dir"]
        ensure_directory_exists(exp_ass_write_dir)
        csv_write_frequency = exp_assistant_json["csv_write_frequency"]
        exp = self._load_experiment(path)

        exp_ass = ExperimentAssistant(optimizer_class=optimizer_class,
                                      experiment=exp,
                                      optimizer_arguments=optimizer_arguments,
                                      write_dir=exp_ass_write_dir,
                                      csv_write_frequency=csv_write_frequency)

        self._exp_assistants[exp_ass.get_exp_id()] = exp_ass

    def _load_experiment(self, path):
        with open(path + "/experiment.json", 'r') as infile:
            exp_json = json.load(infile)
        exp = experiment.from_dict(exp_json)
        return exp


    def _write_state_to_file(self, path):
        state = {"global_start_date": self._global_start_date,
                "exp_assistants": {x.get_exp_id(): x.write_dir for x
                                    in self._exp_assistants.values()}}
        with open(path + '/lab_assistant.json', 'w') as outfile:
            json.dump(state, outfile)

    def get_candidates(self, experiment_id):
        """
        Returns all candidates for a specific experiment.

        Parameters
        ----------
        experiment_id : string
            The id of the experiment for which to return the candidates.

        Returns<commit_msg>Removed the specification of the csv write from lab assistant.<commit_after>__author__ = '<NAME>'

from apsis.assistants.experiment_assistant import ExperimentAssistant
from apsis.utilities.file_utils import ensure_directory_exists
import time
import datetime
import os
import json
from apsis.utilities.logging_utils import get_logger
from apsis.utilities.plot_utils import plot_lists, write_plot_to_file
import matplotlib.pyplot as plt
import uuid
import copy
import numpy as np
import apsis.models.experiment as experiment

# These are the colours supported by the plot.
COLORS = ["g", "r", "c", "b", "m", "y"]


class LabAssistant(object):
    """
    This is used to control multiple experiments at once.

    This is done by abstracting a dict of named experiment assistants.

    Attributes
    ----------
    _exp_assistants : dict of ExperimentAssistants.
        The dictionary of experiment assistants this LabAssistant uses.
    _write_directory_base : String, optional
        The directory to write all the results and plots to.
    _logger : logging.logger
        The logger for this class.
    """
    _exp_assistants = None

    _write_directory_base = None
    _lab_run_directory = None
    _global_start_date = None
    _logger = None



    def __init__(self, write_directory_base=None, continue_path=None):
        """
        Initializes the lab assistant.

        Parameters
        ----------
        write_directory_base : string, optional
            Sets the base write directory for the lab assistant. If None
            (default) the directory depends on the operating system.
            ./APSIS_WRITING if on Windows, /tmp/APSIS_WRITING otherwise.
        continue_path : string, optional
            The path for continuing the experiment. If None (default) a new
            lab assistant is started.
        """
        self._logger = get_logger(self)
        if write_directory_base is None:
            if os.name == "nt":
                write_directory_base = os.path.relpath("APSIS_WRITING")
            else:
                write_directory_base = "/tmp/APSIS_WRITING"

        self._logger.info("Initializing lab assistant.")
        self._logger.info("Writing results to %s" %write_directory_base)
        self._write_directory_base = write_directory_base

        self._exp_assistants = {}
        if continue_path is None:
            self._global_start_date = time.time()
            self._init_directory_structure()
        else:
            # set the correct path.
            self._lab_run_directory = continue_path
            with open(continue_path + "/lab_assistant.json", 'r') as infile:
                lab_assistant_json = json.load(infile)
            self._global_start_date = lab_assistant_json["global_start_date"]
            for p in lab_assistant_json["exp_assistants"].values():
                self._load_exp_assistant_from_path(p)

        self._write_state_to_file(self._lab_run_directory)
        self._logger.info("lab assistant successfully initialized.")

    def init_experiment(self, name, optimizer, param_defs, exp_id=None,
                        notes=None, optimizer_arguments=None,
                        minimization=True):
        """
        Initializes an experiment.

        Parameters
        ----------
        name : string
            name of the experiment.
        optimizer : string
            String representation of the optimizer.
        param_defs : dict of parameter definitions
            Dictionary of parameter definition classes.
        optimizer_arguments : dict, optional
            A dictionary defining the operation of the optimizer. See the
            respective documentation of the optimizers.
            Default is None, which are default values.
        exp_id : string or None, optional
            The id of the experiment, which will be used to reference it.
            Should be a proper uuid, and especially has to be unique. If it is
            not, an error may be returned.
        notes : jsonable object or None, optional
            Any note that you'd like to put in the experiment. Could be used
            to provide some details on the experiment, on the start time or the
            user starting it.
        minimization : bool, optional
            Whether the problem is one of minimization. Defaults to True.

        Returns
        -------
        exp_id : string
            String representing the id of the experiment or "failed" if failed.

        Raises
        ------
        ValueError :
            Iff there already is an experiment with the exp_id for this lab
            assistant. Does not occur if no exp_id is given.
        """
        if exp_id in self._exp_assistants.keys():
            raise ValueError("Already an experiment with id %s registered."
                             %exp_id)

        if exp_id is None:
            while True:
                exp_id = uuid.uuid4().hex
                if exp_id not in self._exp_assistants.keys():
                    break

        exp_assistant_write_directory = os.path.join(self._lab_run_directory +
                                                     "/" + exp_id)

        ensure_directory_exists(exp_assistant_write_directory)

        exp = experiment.Experiment(name,
                                    param_defs,
                                    exp_id,
                                    notes,
                                    minimization)

        exp_ass = ExperimentAssistant(optimizer,
                                      experiment=exp,
                                      optimizer_arguments=optimizer_arguments,
                                      write_dir=exp_assistant_write_directory)
        self._exp_assistants[exp_id] = exp_ass
        self._logger.info("Experiment initialized successfully.")
        self._write_state_to_file(self._lab_run_directory)
        return exp_id

    def _init_directory_structure(self):
        """
        Method to create the directory structure if it does not exist
        for results and plot writing.
        """
        if self._lab_run_directory is None:
            date_name = datetime.datetime.utcfromtimestamp(
                self._global_start_date).strftime("%Y-%m-%d_%H.%M.%S")

            self._lab_run_directory = os.path.join(self._write_directory_base,
                                                  date_name)

            ensure_directory_exists(self._lab_run_directory)

    def _load_exp_assistant_from_path(self, path):
        with open(path + "/exp_assistant.json", 'r') as infile:
            exp_assistant_json = json.load(infile)

        optimizer_class = exp_assistant_json["optimizer_class"]
        optimizer_arguments = exp_assistant_json["optimizer_arguments"]
        exp_ass_write_dir = exp_assistant_json["write_dir"]
        ensure_directory_exists(exp_ass_write_dir)
        exp = self._load_experiment(path)

        exp_ass = ExperimentAssistant(optimizer_class=optimizer_class,
                                      experiment=exp,
                                      optimizer_arguments=optimizer_arguments,
                                      write_dir=exp_ass_write_dir)

        self._exp_assistants[exp_ass.get_exp_id()] = exp_ass

    def _load_experiment(self, path):
        with open(path + "/experiment.json", 'r') as infile:
            exp_json = json.load(infile)
        exp = experiment.from_dict(exp_json)
        return exp


    def _write_state_to_file(self, path):
        state = {"global_start_date": self._global_start_date,
                "exp_assistants": {x.get_exp_id(): x.write_dir for x
                                    in self._exp_assistants.values()}}
        with open(path + '/lab_assistant.json', 'w') as outfile:
            json.dump(state, outfile)

    def get_candidates(self, experiment_id):
        """
        Returns all candidates for a specific experiment.

        Parameters
        ----------
        experiment_id : string
            The id of the experiment for which to return the candidates.

        Returns
{'fraction_non_alphanumeric': 0.0685274537348073, 'fraction_numerical': 0.00018322848592194468, 'mean_word_length': 1.9333572196345397, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4876910', 'n_tokens_mistral': 4265, 'n_tokens_neox': 4121, 'n_words': 1186}