Esempio n. 1
0
    def get_scenario(self):
        run_1_existed = os.path.exists('run_1')
        in_reader = InputReader()
        # Create Scenario (disable output_dir to avoid cluttering)
        scen_fn = os.path.join(self.folder, 'scenario.txt')
        if not os.path.isfile(scen_fn):
            scen_fn = self.get_glob_file(self.folder, 'scenario.txt')
        scen_dict = in_reader.read_scenario_file(scen_fn)
        scen_dict['output_dir'] = ""

        with changedir(self.ta_exec_dir):
            # We always prefer the less error-prone json-format if available:
            pcs_fn = scen_dict.get('pcs_fn', 'no_pcs_fn')
            cs_json = os.path.join(os.path.dirname(pcs_fn), 'configspace.json')
            if not pcs_fn.endswith('.json') and os.path.exists(cs_json):
                self.logger.debug("Detected, '%s' ignoring '%s'", cs_json, pcs_fn)
                with open(cs_json, 'r') as fh:
                    scen_dict['cs'] = pcs_json.read(fh.read())
                    scen_dict['pcs_fn'] = cs_json

            self.logger.debug("Creating scenario from '%s'", self.ta_exec_dir)
            scen = Scenario(scen_dict)

        if (not run_1_existed) and os.path.exists('run_1'):
            shutil.rmtree('run_1')
        return scen
Esempio n. 2
0
    def get_scenario(self):
        run_1_existed = os.path.exists('run_1')
        in_reader = InputReader()
        # Create Scenario (disable output_dir to avoid cluttering)
        scen_fn = os.path.join(self.folder, 'scenario.txt')
        scen_dict = in_reader.read_scenario_file(scen_fn)
        scen_dict['output_dir'] = ""

        # We always prefer the less error-prone json-format if available:
        cs_json = os.path.join(self.folder, 'configspace.json')
        if os.path.exists(cs_json):
            self.logger.debug("Detected '%s'", cs_json)
            with open(cs_json, 'r') as fh:
                pcs_fn = scen_dict.pop('pcs_fn', 'no pcs_fn in scenario')
                self.logger.debug("Ignoring %s", pcs_fn)
                scen_dict['cs'] = pcs_json.read(fh.read())

        with changedir(self.ta_exec_dir):
            self.logger.debug("Creating scenario from \"%s\"",
                              self.ta_exec_dir)
            scen = Scenario(scen_dict)

        if (not run_1_existed) and os.path.exists('run_1'):
            shutil.rmtree('run_1')
        return scen
Esempio n. 3
0
    def __init__(self, folder: str, ta_exec_dir: Union[str, None] = None):
        """Initialize scenario, runhistory and incumbent from folder, execute
        init-method of SMAC facade (so you could simply use SMAC-instances instead)

        Parameters
        ----------
        folder: string
            output-dir of this run
        ta_exec_dir: string
            if the execution directory for the SMAC-run differs from the cwd,
            there might be problems loading instance-, feature- or PCS-files
            in the scenario-object. since instance- and PCS-files are necessary,
            specify the path to the execution-dir of SMAC here
        """
        run_1_existed = os.path.exists('run_1')
        self.logger = logging.getLogger("cave.SMACrun.{}".format(folder))
        in_reader = InputReader()

        self.folder = folder
        self.logger.debug("Loading from %s", folder)

        split_folder = os.path.split(folder)
        self.logger.info(split_folder)
        if ta_exec_dir is None:
            ta_exec_dir = '.'

        self.scen_fn = os.path.join(folder, 'scenario.txt')
        self.rh_fn = os.path.join(folder, 'runhistory.json')
        self.traj_fn = os.path.join(folder, 'traj_aclib2.json')
        self.traj_old_fn = os.path.join(folder, 'traj_old.csv')

        # Create Scenario (disable output_dir to avoid cluttering)
        scen_dict = in_reader.read_scenario_file(self.scen_fn)
        scen_dict['output_dir'] = ""
        with changedir(ta_exec_dir):
            self.scen = Scenario(scen_dict)

        # Load runhistory and trajectory
        self.runhistory = RunHistory(average_cost)
        self.runhistory.update_from_json(self.rh_fn, self.scen.cs)
        self.traj = TrajLogger.read_traj_aclib_format(fn=self.traj_fn,
                                                      cs=self.scen.cs)

        incumbent = self.traj[-1]['incumbent']
        self.train_inst = self.scen.train_insts
        self.test_inst = self.scen.test_insts

        # Initialize SMAC-object
        super().__init__(scenario=self.scen, runhistory=self.runhistory)
        #restore_incumbent=incumbent)
        # TODO use restore, delete next line
        self.solver.incumbent = incumbent

        if (not run_1_existed) and os.path.exists('run_1'):
            shutil.rmtree('run_1')
Esempio n. 4
0
    def get_scenario(self):
        run_1_existed = os.path.exists('run_1')
        in_reader = InputReader()
        # Create Scenario (disable output_dir to avoid cluttering)
        scen_fn = os.path.join(self.folder, 'scenario.txt')
        scen_dict = in_reader.read_scenario_file(scen_fn)
        scen_dict['output_dir'] = ""
        with changedir(self.ta_exec_dir):
            self.logger.debug("Creating scenario from \"%s\"", self.ta_exec_dir)
            scen = Scenario(scen_dict)

        if (not run_1_existed) and os.path.exists('run_1'):
            shutil.rmtree('run_1')
        self.scen = scen
        return scen
Esempio n. 5
0
    def get_scenario(self, path, ta_exec_dir=None, out_path=None):
        run_1_existed = os.path.exists('run_1')
        if ta_exec_dir is None:
            ta_exec_dir = '.'
        in_reader = InputReader()
        # Create Scenario
        scen_fn = os.path.join(path, 'scenario.txt')
        scen_dict = in_reader.read_scenario_file(scen_fn)
        scen_dict['output_dir'] = out_path
        with changedir(ta_exec_dir):
            self.logger.debug("Creating scenario from \"%s\"", ta_exec_dir)
            scen = Scenario(scen_dict)

        if (not run_1_existed) and os.path.exists('run_1'):
            shutil.rmtree('run_1')
        return scen
Esempio n. 6
0
class Scenario(object):
    """
    Scenario contains the configuration of the optimization process and
    constructs a scenario object from a file or dictionary.

    All arguments set in the Scenario are set as attributes.

    """
    def __init__(self, scenario, cmd_args: dict = None, run_id: int = 1):
        """Constructor

        Parameters
        ----------
        scenario : str or dict
            If str, it will be interpreted as to a path a scenario file
            If dict, it will be directly to get all scenario related information
        cmd_args : dict
            Command line arguments that were not processed by argparse
        run_id: int
            Run ID will be used as suffix for output_dir
        """
        self.logger = logging.getLogger(self.__module__ + '.' +
                                        self.__class__.__name__)
        self.PCA_DIM = 7

        self.in_reader = InputReader()
        self.out_writer = OutputWriter()

        if type(scenario) is str:
            scenario_fn = scenario
            self.logger.info("Reading scenario file: %s" % (scenario_fn))
            scenario = self.in_reader.read_scenario_file(scenario_fn)
        elif type(scenario) is dict:
            scenario = copy.copy(scenario)
        else:
            raise TypeError(
                "Wrong type of scenario (str or dict are supported)")

        if cmd_args:
            scenario.update(cmd_args)

        self._arguments = {}
        self._groups = defaultdict(set)
        self._add_arguments()

        # Make cutoff mandatory if run_obj is runtime
        if scenario['run_obj'] == 'runtime':
            self._arguments['cutoff_time']['required'] = True

        # Parse arguments
        parsed_arguments = {}
        for key, value in self._arguments.items():
            arg_name, arg_value = self._parse_argument(key, scenario, **value)
            parsed_arguments[arg_name] = arg_value

        if len(scenario) != 0:
            raise ValueError('Could not parse the following arguments: %s' %
                             str(list(scenario.keys())))

        for group, potential_members in self._groups.items():
            n_members_in_scenario = 0
            for pm in potential_members:
                if pm in parsed_arguments:
                    n_members_in_scenario += 1

            if n_members_in_scenario != 1:
                raise ValueError('Exactly one of the following arguments must '
                                 'be specified in the scenario file: %s' %
                                 str(potential_members))

        for arg_name, arg_value in parsed_arguments.items():
            setattr(self, arg_name, arg_value)

        self._transform_arguments()

        if self.output_dir:
            self.output_dir += "_run%d" % (run_id)

        self.out_writer.write_scenario_file(self)

        self.logger.debug("Scenario Options:")
        for arg_name, arg_value in parsed_arguments.items():
            if isinstance(arg_value, (int, str, float)):
                self.logger.debug("%s = %s" % (arg_name, arg_value))

    def add_argument(self,
                     name: str,
                     help: str,
                     callback=None,
                     default=None,
                     dest: str = None,
                     required: bool = False,
                     mutually_exclusive_group: str = None,
                     choice=None):
        """Add argument to the scenario object.

        Parameters
        ----------
        name : str
            Argument name
        help : str
            Help text which can be displayed in the documentation.
        callback : callable, optional
            If given, the callback will be called when the argument is
            parsed. Useful for custom casting/typechecking.
        default : object, optional
            Default value if the argument is not given. Default to ``None``.
        dest : str
            Assign the argument to scenario object by this name.
        required : bool
            If True, the scenario will raise an error if the argument is not
            given.
        mutually_exclusive_group : str
            Group arguments with similar behaviour by assigning the same string
            value. The scenario will ensure that exactly one of the arguments is
            given. Is used for example to ensure that either a configuration
            space object or a parameter file is passed to the scenario. Can not
            be used together with ``required``.
        choice: list/set/tuple
            List of possible string for this argument
        """
        if not isinstance(required, bool):
            raise TypeError("Argument 'required' must be of type 'bool'.")
        if required is not False and mutually_exclusive_group is not None:
            raise ValueError("Cannot make argument '%s' required and add it to"
                             " a group of mutually exclusive arguments." %
                             name)
        if choice is not None and not isinstance(choice, (list, set, tuple)):
            raise TypeError('Choice must be of type list/set/tuple.')

        self._arguments[name] = {
            'default': default,
            'required': required,
            'help': help,
            'dest': dest,
            'callback': callback,
            'choice': choice
        }

        if mutually_exclusive_group:
            self._groups[mutually_exclusive_group].add(name)

    def _parse_argument(self,
                        name: str,
                        scenario: dict,
                        help: str,
                        callback=None,
                        default=None,
                        dest: str = None,
                        required: bool = False,
                        choice=None):
        """Search the scenario dict for a single allowed argument and parse it.

        Side effect: the argument is removed from the scenario dict if found.

        name : str
            Argument name, as specified in the Scenario class.
        scenario : dict
            Scenario dict as provided by the user or as parsed by the cli
            interface.
        help : str
            Help string of the argument
        callback : callable, optional (default=None)
            If given, will be called to transform the given argument.
        default : object, optional (default=None)
            Will be used as default value if the argument is not given by the
            user.
        dest : str, optional (default=None)
            Will be used as member name of the scenario.
        required : bool (default=False)
            If ``True``, the scenario will raise an Exception if the argument is
            not given.
        choice : list, optional (default=None)
            If given, the scenario checks whether the argument is in the
            list. If not, it raises an Exception.

        Returns
        -------
        str
            Member name of the attribute.
        object
            Value of the attribute.
        """
        normalized_name = name.lower().replace('-', '').replace('_', '')
        value = None

        # Allows us to pop elements in order to remove all parsed elements
        # from the dictionary
        for key in list(scenario.keys()):
            # Check all possible ways to spell an argument
            normalized_key = key.lower().replace('-', '').replace('_', '')
            if normalized_key == normalized_name:
                value = scenario.pop(key)

        if dest is None:
            dest = name.lower().replace('-', '_')

        if required is True:
            if value is None:
                raise ValueError('Required scenario argument %s not given.' %
                                 name)

        if value is None:
            value = default

        if value is not None and callable(callback):
            value = callback(value)

        if value is not None and choice:
            value = value.strip()
            if value not in choice:
                raise ValueError('Argument %s can only take a value in %s, '
                                 'but is %s' % (name, choice, value))

        return dest, value

    def _add_arguments(self):
        """TODO"""
        # Add allowed arguments
        self.add_argument(
            name='abort_on_first_run_crash',
            help="If true, *SMAC* will abort if the first run of "
            "the target algorithm crashes.",
            default=True,
            callback=_is_truthy)
        self.add_argument(name='always_race_default',
                          default=False,
                          help="Race new incumbents always against default "
                          "configuration.",
                          callback=_is_truthy,
                          dest="always_race_default")
        self.add_argument(
            name='algo',
            dest='ta',
            callback=shlex.split,
            help="Specifies the target algorithm call that *SMAC* "
            "will optimize. Interpreted as a bash-command.")
        self.add_argument(
            name='execdir',
            default='.',
            help="Specifies the path to the execution-directory.")
        self.add_argument(name='deterministic',
                          default=False,
                          help="If true, the optimization process will be "
                          "repeatable.",
                          callback=_is_truthy)
        self.add_argument(name='intensification_percentage',
                          default=0.5,
                          help="The fraction of time to be used on "
                          "intensification (versus choice of next "
                          "Configurations).",
                          callback=float)
        self.add_argument(name='paramfile',
                          help="Specifies the path to the "
                          "PCS-file.",
                          dest='pcs_fn',
                          mutually_exclusive_group='cs')
        self.add_argument(name='run_obj',
                          help="Defines what metric to optimize. When "
                          "optimizing runtime, *cutoff_time* is "
                          "required as well.",
                          required=True,
                          choice=['runtime', 'quality'])
        self.add_argument(name='overall_obj',
                          help="PARX, where X is an integer defining the "
                          "penalty imposed on timeouts (i.e. runtimes that "
                          "exceed the *cutoff-time*).",
                          default='par10')
        self.add_argument(name='cost_for_crash',
                          default=float(MAXINT),
                          help="Defines the cost-value for crashed runs "
                          "on scenarios with quality as run-obj.",
                          callback=float)
        self.add_argument(name='cutoff_time',
                          help="Maximum runtime, after which the "
                          "target algorithm is cancelled. **Required "
                          "if *run_obj* is runtime.**",
                          default=None,
                          dest='cutoff',
                          callback=float)
        self.add_argument(name='memory_limit',
                          help="Maximum available memory the target algorithm "
                          "can occupy before being cancelled.")
        self.add_argument(
            name='tuner-timeout',
            help="Maximum amount of CPU-time used for optimization.",
            default=numpy.inf,
            dest='algo_runs_timelimit',
            callback=float)
        self.add_argument(
            name='wallclock_limit',
            help="Maximum amount of wallclock-time used for optimization.",
            default=numpy.inf,
            callback=float)
        self.add_argument(
            name='always_race_default',
            help="Race new incumbents always against default configuration.",
            default=False,
            callback=_is_truthy,
            dest="always_race_default")
        self.add_argument(
            name='runcount_limit',
            help="Maximum number of algorithm-calls during optimization.",
            default=numpy.inf,
            callback=float,
            dest="ta_run_limit")
        self.add_argument(name='minR',
                          help="Minimum number of calls per configuration.",
                          default=1,
                          callback=int,
                          dest='minR')
        self.add_argument(name='maxR',
                          help="Maximum number of calls per configuration.",
                          default=2000,
                          callback=int,
                          dest='maxR')
        self.add_argument(
            name='instance_file',
            help="Specifies the file with the training-instances.",
            dest='train_inst_fn')
        self.add_argument(name='test_instance_file',
                          help="Specifies the file with the test-instances.",
                          dest='test_inst_fn')
        self.add_argument(
            name='feature_file',
            help="Specifies the file with the instance-features.",
            dest='feature_fn')
        self.add_argument(
            name='output_dir',
            help="Specifies the output-directory for all emerging "
            "files, such as logging and results.",
            default="smac3-output_%s" % (datetime.datetime.fromtimestamp(
                time.time()).strftime('%Y-%m-%d_%H:%M:%S_(%f)')))
        self.add_argument(
            name='input_psmac_dirs',
            default=None,
            help="For parallel SMAC, multiple output-directories "
            "are used.")
        self.add_argument(name='shared_model',
                          help="Whether to run SMAC in parallel mode.",
                          default=False,
                          callback=_is_truthy)
        self.add_argument(name='instances',
                          default=[[None]],
                          help=None,
                          dest='train_insts')
        self.add_argument(name='test_instances',
                          default=[[None]],
                          help=None,
                          dest='test_insts')
        self.add_argument(name='initial_incumbent',
                          default="DEFAULT",
                          help="DEFAULT is the default from the PCS.",
                          dest='initial_incumbent',
                          choice=['DEFAULT', 'RANDOM'])
        # instance name -> feature vector
        self.add_argument(name='features',
                          default={},
                          help=None,
                          dest='feature_dict')
        # ConfigSpace object
        self.add_argument(name='cs', help=None, mutually_exclusive_group='cs')

    def _transform_arguments(self):
        """TODO"""
        self.n_features = len(self.feature_dict)
        self.feature_array = None

        if self.overall_obj[:3] in ["PAR", "par"]:
            par_str = self.overall_obj[3:]
        elif self.overall_obj[:4] in ["mean", "MEAN"]:
            par_str = self.overall_obj[4:]
        # Check for par-value as in "par10"/ "mean5"
        if len(par_str) > 0:
            self.par_factor = int(par_str)
        else:
            self.logger.debug("No par-factor detected. Using 1 by default.")
            self.par_factor = 1

        # read instance files
        if self.train_inst_fn:
            if os.path.isfile(self.train_inst_fn):
                self.train_insts = self.in_reader.read_instance_file(
                    self.train_inst_fn)
            else:
                self.logger.error("Have not found instance file: %s" %
                                  (self.train_inst_fn))
                sys.exit(1)
        if self.test_inst_fn:
            if os.path.isfile(self.test_inst_fn):
                self.test_insts = self.in_reader.read_instance_file(
                    self.test_inst_fn)
            else:
                self.logger.error("Have not found test instance file: %s" %
                                  (self.test_inst_fn))
                sys.exit(1)

        self.instance_specific = {}

        def extract_instance_specific(instance_list):
            insts = []
            for inst in instance_list:
                if len(inst) > 1:
                    self.instance_specific[inst[0]] = " ".join(inst[1:])
                insts.append(inst[0])
            return insts

        self.train_insts = extract_instance_specific(self.train_insts)
        if self.test_insts:
            self.test_insts = extract_instance_specific(self.test_insts)

        self.train_insts = self._to_str_and_warn(l=self.train_insts)
        self.test_insts = self._to_str_and_warn(l=self.test_insts)

        # read feature file
        if self.feature_fn:
            if os.path.isfile(self.feature_fn):
                self.feature_dict = self.in_reader.read_instance_features_file(
                    self.feature_fn)[1]

        if self.feature_dict:
            self.feature_array = []
            for inst_ in self.train_insts:
                self.feature_array.append(self.feature_dict[inst_])
            self.feature_array = numpy.array(self.feature_array)
            self.n_features = self.feature_array.shape[1]

        # read pcs file
        if self.pcs_fn and os.path.isfile(self.pcs_fn):
            with open(self.pcs_fn) as fp:
                pcs_str = fp.readlines()
                try:
                    self.cs = pcs.read(pcs_str)
                except:
                    self.logger.debug(
                        "Could not parse pcs file with old format; trying new format next"
                    )
                    self.cs = pcs_new.read(pcs_str)
                self.cs.seed(42)
        elif self.pcs_fn:
            self.logger.error("Have not found pcs file: %s" % (self.pcs_fn))
            sys.exit(1)

        # you cannot set output dir to None directly
        # because None is replaced by default always
        if self.output_dir == "":
            self.output_dir = None
            self.logger.debug("Deactivate output directory.")
        else:
            self.logger.info("Output to %s" % (self.output_dir))

        if self.shared_model and self.input_psmac_dirs is None:
            # per default, we assume that
            # all psmac runs write to the same directory
            self.input_psmac_dirs = [self.output_dir]

    def __getstate__(self):
        d = dict(self.__dict__)
        del d['logger']
        return d

    def __setstate__(self, d):
        self.__dict__.update(d)
        self.logger = logging.getLogger(self.__module__ + '.' +
                                        self.__class__.__name__)

    def _to_str_and_warn(self, l: typing.List[typing.Any]):
        warn_ = False
        for i, e in enumerate(l):
            if e is not None and not isinstance(e, str):
                warn_ = True
                try:
                    l[i] = str(e)
                except ValueError:
                    raise ValueError("Failed to cast all instances to str")
        if warn_:
            self.logger.warn("All instances were casted to str.")
        return l

    def write_options_to_doc(self, path='scenario_options.rst'):
        """Writes the option-list to file for autogeneration in documentation.
        The list is created in doc/conf.py and read in doc/options.rst.

        Parameters
        ----------
        path: string
            Where to write to (relative to doc-folder since executed in conf.py)
        """
        exclude = ['cs', 'features', 'instances', 'test_instances']
        with open(path, 'w') as fh:
            for arg in sorted(self._arguments.keys()):
                if arg in exclude:
                    continue
                fh.write(":{}: ".format(arg))
                fh.write("{}".format(self._arguments[arg]['help']))
                if self._arguments[arg]['default']:
                    fh.write(" Default: {}.".format(
                        self._arguments[arg]['default']))
                if self._arguments[arg]['choice']:
                    fh.write(" Must be from: {}.".format(
                        self._arguments[arg]['choice']))
                fh.write("\n")
            fh.write("\n\n")
Esempio n. 7
0
class Scenario(object):
    '''
    main class of SMAC
    '''
    def __init__(self, scenario, cmd_args=None):
        """Construct scenario object from file or dictionary.

        Parameters
        ----------
        scenario : str or dict
            if str, it will be interpreted as to a path a scenario file
            if dict, it will be directly to get all scenario related information
        cmd_args : dict
            command line arguments that were not processed by argparse

        """
        self.logger = logging.getLogger("scenario")
        self.in_reader = InputReader()

        if type(scenario) is str:
            scenario_fn = scenario
            self.logger.info("Reading scenario file: %s" % (scenario_fn))
            scenario = self.in_reader.read_scenario_file(scenario_fn)
        elif type(scenario) is dict:
            pass
        else:
            raise TypeError(
                "Wrong type of scenario (str or dict are supported)")

        if cmd_args:
            scenario.update(cmd_args)

        self._arguments = {}
        self._add_arguments()

        # Parse arguments
        parsed_arguments = {}
        for key, value in self._arguments.items():
            arg_name, arg_value = self._parse_argument(key, scenario, **value)
            parsed_arguments[arg_name] = arg_value

        if len(scenario) != 0:
            raise ValueError('Could not parse the following arguments: %s' %
                             str(list(scenario.keys())))

        for arg_name, arg_value in parsed_arguments.items():
            setattr(self, arg_name, arg_value)

        self._transform_arguments()

    def add_argument(self,
                     name,
                     help,
                     callback=None,
                     default=None,
                     dest=None,
                     required=False):
        if not isinstance(required, bool):
            raise TypeError("Argument required must be of type 'bool'.")

        self._arguments[name] = {
            'default': default,
            'required': required,
            'help': help,
            'dest': dest,
            'callback': callback
        }

    def _parse_argument(self,
                        name,
                        scenario,
                        help,
                        callback=None,
                        default=None,
                        dest=None,
                        required=False):
        normalized_name = name.lower().replace('-', '').replace('_', '')
        value = None

        # Allows us to pop elements in order to remove all parsed elements
        # from the dictionary
        for key in list(scenario.keys()):
            # Check all possible ways to spell an argument
            normalized_key = key.lower().replace('-', '').replace('_', '')
            if normalized_key == normalized_name:
                value = scenario.pop(key)

        if dest is None:
            dest = name.lower().replace('-', '_')

        if required is True:
            if value is None:
                raise ValueError('Required argument %s not given.' % name)

        if value is None:
            value = default

        if value is not None and callable(callback):
            value = callback(value)

        return dest, value

    def _add_arguments(self):
        # Add allowed arguments
        self.add_argument(name='algo',
                          help=None,
                          dest='ta',
                          callback=lambda arg: shlex.split(arg))
        self.add_argument(name='execdir', default='.', help=None)
        self.add_argument(name='deterministic',
                          default="0",
                          help=None,
                          callback=lambda arg: arg in ["1", "true", True])
        self.add_argument(name='paramfile', help=None, dest='pcs_fn')
        self.add_argument(name='run_obj', help=None, default='runtime')
        self.add_argument(name='overall_obj', help=None, default='par10')
        self.add_argument(name='cutoff_time',
                          help=None,
                          default=None,
                          dest='cutoff',
                          callback=lambda arg: float(arg))
        self.add_argument(name='memory_limit', help=None)
        self.add_argument(name='tuner-timeout',
                          help=None,
                          default=numpy.inf,
                          dest='algo_runs_timelimit',
                          callback=lambda arg: float(arg))
        self.add_argument(name='wallclock_limit',
                          help=None,
                          default=numpy.inf,
                          callback=lambda arg: float(arg))
        self.add_argument(name='runcount_limit',
                          help=None,
                          default=numpy.inf,
                          callback=lambda arg: float(arg),
                          dest="ta_run_limit")
        self.add_argument(name='instance_file',
                          help=None,
                          dest='train_inst_fn')
        self.add_argument(name='test_instance_file',
                          help=None,
                          dest='test_inst_fn')
        self.add_argument(name='feature_file', help=None, dest='feature_fn')
        self.add_argument(name='output_dir',
                          help=None,
                          default="smac3-output_%s" %
                          (datetime.datetime.fromtimestamp(
                              time.time()).strftime('%Y-%m-%d_%H:%M:%S')))
        self.add_argument(name='shared_model',
                          help=None,
                          default='0',
                          callback=lambda arg: arg in ['1', 'true', True])
        self.add_argument(name='instances',
                          default=[[None]],
                          help=None,
                          dest='train_insts')
        self.add_argument(name='test_instances',
                          default=[[None]],
                          help=None,
                          dest='test_insts')
        # instance name -> feature vector
        self.add_argument(name='features',
                          default={},
                          help=None,
                          dest='feature_dict')
        self.add_argument(name='cs', help=None)  # ConfigSpace object

    def _transform_arguments(self):
        self.n_features = len(self.feature_dict)
        self.feature_array = None

        if self.overall_obj[:3] in ["PAR", "par"]:
            self.par_factor = int(self.overall_obj[3:])
        elif self.overall_obj[:4] in ["mean", "MEAN"]:
            self.par_factor = int(self.overall_obj[4:])
        else:
            self.par_factor = 1

        # read instance files
        if self.train_inst_fn:
            if os.path.isfile(self.train_inst_fn):
                self.train_insts = self.in_reader.read_instance_file(
                    self.train_inst_fn)
            else:
                self.logger.error("Have not found instance file: %s" %
                                  (self.train_inst_fn))
                sys.exit(1)
        if self.test_inst_fn:
            if os.path.isfile(self.test_inst_fn):
                self.test_insts = self.in_reader.read_instance_file(
                    self.test_inst_fn)
            else:
                self.logger.error("Have not found test instance file: %s" %
                                  (self.test_inst_fn))
                sys.exit(1)

        self.instance_specific = {}

        def extract_instance_specific(instance_list):
            insts = []
            for inst in instance_list:
                if len(inst) > 1:
                    self.instance_specific[inst[0]] = " ".join(inst[1:])
                insts.append(inst[0])
            return insts

        self.train_insts = extract_instance_specific(self.train_insts)
        if self.test_insts:
            self.test_insts = extract_instance_specific(self.test_insts)

        # read feature file
        if self.feature_fn:
            if os.path.isfile(self.feature_fn):
                self.feature_dict = self.in_reader.read_instance_features_file(
                    self.feature_fn)[1]

        if self.feature_dict:
            self.n_features = len(self.feature_dict[list(
                self.feature_dict.keys())[0]])
            self.feature_array = []
            for inst_ in self.train_insts:
                self.feature_array.append(self.feature_dict[inst_])
            self.feature_array = numpy.array(self.feature_array)

        # read pcs file
        if self.pcs_fn and os.path.isfile(self.pcs_fn):
            with open(self.pcs_fn) as fp:
                pcs_str = fp.readlines()
                self.cs = pcs.read(pcs_str)
                self.cs.seed(42)
        elif self.pcs_fn:
            self.logger.error("Have not found pcs file: %s" % (self.pcs_fn))
            sys.exit(1)

        self.logger.info("Output to %s" % (self.output_dir))