class ExecuteTARunHydra(ExecuteTARun):
    """Returns min(cost, cost_portfolio)
    """
    def __init__(self,
                 cost_oracle: typing.Mapping[str, float],
                 tae: typing.Type[ExecuteTARun] = ExecuteTARunOld,
                 **kwargs):
        '''
            Constructor
            
            Arguments
            ---------
            cost_oracle: typing.Mapping[str,float]
                cost of oracle per instance
        '''

        super().__init__(**kwargs)
        self.cost_oracle = cost_oracle
        if tae is ExecuteTARunAClib:
            self.runner = ExecuteTARunAClib(**kwargs)
        elif tae is ExecuteTARunOld:
            self.runner = ExecuteTARunOld(**kwargs)
        elif tae is ExecuteTAFuncDict:
            self.runner = ExecuteTAFuncDict(**kwargs)
        elif tae is ExecuteTAFuncArray:
            self.runner = ExecuteTAFuncArray(**kwargs)
        else:
            raise Exception('TAE not supported')

    def run(self, **kwargs):
        """ see ~smac.tae.execute_ta_run.ExecuteTARunOld for docstring
        """

        status, cost, runtime, additional_info = self.runner.run(**kwargs)
        inst = kwargs["instance"]
        try:
            oracle_perf = self.cost_oracle[inst]
        except KeyError:
            oracle_perf = None
        if oracle_perf is not None:
            if self.run_obj == "runtime":
                self.logger.debug("Portfolio perf: %f vs %f = %f", oracle_perf,
                                  runtime, min(oracle_perf, runtime))
                runtime = min(oracle_perf, runtime)
                cost = runtime
            else:
                self.logger.debug("Portfolio perf: %f vs %f = %f", oracle_perf,
                                  cost, min(oracle_perf, cost))
                cost = min(oracle_perf, cost)
            if oracle_perf < kwargs['cutoff'] and status is StatusType.TIMEOUT:
                status = StatusType.SUCCESS
        else:
            self.logger.error(
                "Oracle performance missing --- should not happen")

        return status, cost, runtime, additional_info
class ExecuteTARunHydra(SerialRunner):
    """Returns min(cost, cost_portfolio)
    """
    def __init__(self,
                 cost_oracle: typing.Mapping[str, float],
                 tae: typing.Type[SerialRunner] = ExecuteTARunOld,
                 **kwargs: typing.Any) -> None:
        '''
            Constructor

            Arguments
            ---------
            cost_oracle: typing.Mapping[str,float]
                cost of oracle per instance
        '''

        super().__init__(**kwargs)
        self.cost_oracle = cost_oracle
        if tae is ExecuteTARunAClib:
            self.runner = ExecuteTARunAClib(**kwargs)  # type: SerialRunner
        elif tae is ExecuteTARunOld:
            self.runner = ExecuteTARunOld(**kwargs)
        elif tae is ExecuteTAFuncDict:
            self.runner = ExecuteTAFuncDict(**kwargs)
        elif tae is ExecuteTAFuncArray:
            self.runner = ExecuteTAFuncArray(**kwargs)
        else:
            raise Exception('TAE not supported')

    def run(
        self,
        config: Configuration,
        instance: str,
        cutoff: typing.Optional[float] = None,
        seed: int = 12345,
        budget: typing.Optional[float] = None,
        instance_specific: str = "0"
    ) -> typing.Tuple[StatusType, float, float, typing.Dict]:
        """ see ~smac.tae.execute_ta_run.ExecuteTARunOld for docstring
        """

        if cutoff is None:
            raise ValueError('Cutoff of type None is not supported')

        status, cost, runtime, additional_info = self.runner.run(
            config=config,
            instance=instance,
            cutoff=cutoff,
            seed=seed,
            budget=budget,
            instance_specific=instance_specific,
        )
        if instance in self.cost_oracle:
            oracle_perf = self.cost_oracle[instance]
            if self.run_obj == "runtime":
                self.logger.debug("Portfolio perf: %f vs %f = %f", oracle_perf,
                                  runtime, min(oracle_perf, runtime))
                runtime = min(oracle_perf, runtime)
                cost = runtime
            else:
                self.logger.debug("Portfolio perf: %f vs %f = %f", oracle_perf,
                                  cost, min(oracle_perf, cost))
                cost = min(oracle_perf, cost)
            if oracle_perf < cutoff and status is StatusType.TIMEOUT:
                status = StatusType.SUCCESS
        else:
            self.logger.error(
                "Oracle performance missing --- should not happen")

        return status, cost, runtime, additional_info