Beispiel #1
0
def efficientsamp(kriglist, ypar, npop=300):
    nvar = len(kriglist[0].KrigInfo["ub"])
    templst = []
    for ij in range(np.size(ypar, 0)):
        idx = np.where((kriglist[0].KrigInfo["y"] == ypar[ij, 0])
                       & (kriglist[1].KrigInfo["y"] == ypar[ij, 1]))[0][0]
        templst.append(idx)

    initialization = kriglist[0].KrigInfo["X_norm"][templst, :] / 2 + 0.5

    if initialization.ndim == 1:
        samplenorm = np.random.normal(
            initialization,
            np.std(kriglist[0].KrigInfo['X_norm'], 0) * 0.2, (npop, nvar))
    else:
        n_init = np.size(initialization, 0)
        nbatch = int(npop / n_init)
        samplenorm = np.zeros((npop, nvar))
        for ij in range(n_init - 1):
            samplenorm[ij * nbatch:(ij + 1) * nbatch, :] = np.random.normal(
                initialization[ij, :],
                np.std(kriglist[0].KrigInfo['X_norm'], 0) * 0.2,
                (nbatch, nvar))
        samplenorm[(ij + 1) * nbatch:, :] = np.random.normal(
            initialization[(ij + 1), :],
            np.std(kriglist[0].KrigInfo['X_norm'], 0) * 0.2,
            (np.size(samplenorm[(ij + 1) * nbatch:, :], 0), nvar))
        samplenorm[samplenorm < 0] = 0
        samplenorm[samplenorm > 1] = 1

    init_seed = realval(kriglist[0].KrigInfo["lb"], kriglist[0].KrigInfo["ub"],
                        samplenorm)
    return init_seed
Beispiel #2
0
def mcpopgen(
    lb=None,
    ub=None,
    n_order=6,
    n_coeff=1,
    type="random",
    ndim=2,
    stddev=1,
    mean=0,
    rand_seed=None,
):
    if rand_seed is not None:
        np.random.seed(rand_seed)
    nmc = int(n_coeff * 10**n_order)
    if type.lower() == "normal" or type.lower() == "gaussian":
        pop = stddev * np.random.randn(nmc, ndim) + mean
    elif type.lower() == "lognormal":
        var = stddev**2
        sigma = np.sqrt(np.log(var / (mean**2) + 1))
        mu = np.log((mean**2) / np.sqrt(var + mean**2))
        pop = np.exp(sigma * np.random.randn(nmc, ndim) + mu)
    elif type.lower() == "gumbel":
        beta = (stddev / np.pi) * np.sqrt(6)
        pop = np.random.gumbel(mean, beta, (nmc, ndim))
    elif type.lower() == "random":
        if lb.any() == None or ub.any() == None:
            raise ValueError("type 'random' is selected, please input lower "
                             "bound and upper bound value")
        else:
            pop = realval(lb, ub, np.random.rand(nmc, len(lb)))
    else:
        raise ValueError("Monte Carlo sampling type not supported")
    return pop
def efficientsamp(kriglist, y_par, n_pop=300, std_scale=0.2):
    """Effective Non-Dominated Sampling

    Generate an n_pop-sized population of samples using a normal
    distribution around the current n-objective Pareto solutions.

    Args:
        kriglist ([KrigInfo]): A list containing Kriging KrigInfo
            from which to get the current decision variables 'X_norm',
            and bounds 'ub' and 'lb'.
        y_par (np.ndarray): [n_par, n_obj] Current Pareto front.
        n_pop (int, optional): The number of samples to generate.
            Defaults to 300.
        std_scale (numeric, optional) The standard deviation scaling
            factor. Defaults to 0.2.

    Returns:
        init_seed (np.ndarray): [n_pop, n_dv] Array of samples.
    """
    # Stack objective values into same shape as y_par
    objs = np.hstack([k.KrigInfo["y"] for k in kriglist])
    mask = (objs[:, None] == y_par).all(-1).any(-1)  # mask of matching rows
    # assert (objs[mask] == y_par).all()
    idx = np.where(mask)[0]  # indices of matching rows
    initialization = kriglist[0].KrigInfo["X_norm"][idx, :] / 2 + 0.5

    n_var = len(kriglist[0].KrigInfo["ub"])
    std_s = np.std(kriglist[0].KrigInfo['X_norm'], 0) * std_scale
    if initialization.ndim == 1:
        samplenorm = np.random.normal(initialization, std_s, (n_pop, n_var))
    else:
        n_init = np.size(initialization, 0)
        n_batch = int(n_pop / n_init)
        samplenorm = np.zeros((n_pop, n_var))
        for ij in range(n_init - 1):
            dist = np.random.normal(initialization[ij, :], std_s,
                                    (n_batch, n_var))
            samplenorm[ij * n_batch:(ij + 1) * n_batch, :] = dist
        n_remain = np.size(samplenorm[(ij + 1) * n_batch:, :], 0)
        dist = np.random.normal(initialization[(ij + 1), :], std_s,
                                (n_remain, n_var))
        samplenorm[(ij + 1) * n_batch:, :] = dist
        samplenorm[samplenorm < 0] = 0
        samplenorm[samplenorm > 1] = 1

    init_seed = realval(kriglist[0].KrigInfo["lb"], kriglist[0].KrigInfo["ub"],
                        samplenorm)
    return init_seed
Beispiel #4
0
def run_single_opt(krigobj, soboInfo, krigconstlist=None, cheapconstlist=None):
    """
   Run the optimization of multi-objective acquisition function to find the next sampling point.

   Args:
     krigobj (object): Kriging object.
     soboInfo (dict): A structure containing necessary information for Bayesian optimization.
     krigconstlist (list): List of Kriging object for constraints. Defaults to None.
     cheapconstlist (list): List of constraints function. Defaults to None.
            Expected output of the constraint functions is 1 if the constraint is satisfied and 0 if not.
            The constraint functions MUST have an input of x (the decision variable to be evaluated)

   Returns:
     xnext (nparray): Suggested next sampling point as discovered by the optimization of the acquisition function
     fnext (nparray): Optimized acquisition function

   The available optimizers for the acquisition function are 'cmaes', 'lbfgsb', 'cobyla'.
   Note that this function runs for both unconstrained and constrained single-objective Bayesian optimization.
   """
    acquifuncopt = soboInfo["acquifuncopt"]
    acquifunc = soboInfo["acquifunc"]

    if acquifunc.lower() == 'parego':
        acquifunc = soboInfo['paregoacquifunc']
    else:
        pass

    if acquifuncopt.lower() == 'cmaes':
        Xrand = realval(
            krigobj.KrigInfo["lb"], krigobj.KrigInfo["ub"],
            np.random.rand(soboInfo["nrestart"], krigobj.KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[soboInfo["nrestart"], krigobj.KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[soboInfo["nrestart"]])
        sigmacmaes = 1  # np.mean((KrigNewMultiInfo["ub"] - KrigNewMultiInfo["lb"]) / 6)
        for im in range(0, soboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                xnextcand[im, :], es = cma.fmin2(krigobj.predict,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(acquifunc))
                fnextcand[im] = es.result[1]
            else:  # For constrained problem
                xnextcand[im, :], es = cma.fmin2(singleconstfun,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(krigobj, acquifunc,
                                                       krigconstlist,
                                                       cheapconstlist))
                fnextcand[im] = es.result[1]
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    elif acquifuncopt.lower() == 'lbfgsb':
        Xrand = realval(
            krigobj.KrigInfo["lb"], krigobj.KrigInfo["ub"],
            np.random.rand(soboInfo["nrestart"], krigobj.KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[soboInfo["nrestart"], krigobj.KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[soboInfo["nrestart"]])
        lbfgsbbound = np.hstack((krigobj.KrigInfo["lb"].reshape(-1, 1),
                                 krigobj.KrigInfo["ub"].reshape(-1, 1)))
        for im in range(0, soboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = minimize(krigobj.predict,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(acquifunc))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
            else:  # For constrained problem (on progress)
                res = minimize(singleconstfun,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(krigobj, acquifunc, krigconstlist,
                                     cheapconstlist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    elif acquifuncopt.lower() == 'diff_evo':
        xnextcand = np.zeros(
            shape=[soboInfo["nrestart"], krigobj.KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[soboInfo["nrestart"]])
        optimbound = np.hstack((krigobj.KrigInfo["lb"].reshape(-1, 1),
                                krigobj.KrigInfo["ub"].reshape(-1, 1)))
        for im in range(0, soboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = differential_evolution(krigobj.predict,
                                             optimbound,
                                             args=(acquifunc, ))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
            else:
                res = differential_evolution(singleconstfun,
                                             optimbound,
                                             args=(krigobj, acquifunc,
                                                   krigconstlist,
                                                   cheapconstlist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    elif acquifuncopt.lower() == 'cobyla':
        Xrand = realval(
            krigobj.KrigInfo["lb"], krigobj.KrigInfo["ub"],
            np.random.rand(soboInfo["nrestart"], krigobj.KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[soboInfo["nrestart"], krigobj.KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[soboInfo["nrestart"]])
        optimbound = []
        for i in range(len(krigobj.KrigInfo["ub"])):
            optimbound.append(lambda x, krigobj, aa, bb, cc, itemp=i: x[itemp]
                              - krigobj.KrigInfo["lb"][itemp])
            optimbound.append(lambda x, krigobj, aa, bb, cc, itemp=i: krigobj.
                              KrigInfo["ub"][itemp] - x[itemp])
        for im in range(0, soboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = fmin_cobyla(krigobj.predict,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(acquifunc))
                xnextcand[im, :] = res
                fnextcand[im] = krigobj.predict(res, acquifunc)
            else:
                res = fmin_cobyla(singleconstfun,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(krigobj, acquifunc, krigconstlist,
                                        cheapconstlist))
                xnextcand[im, :] = res
                fnextcand[im] = singleconstfun(res, krigobj, acquifunc,
                                               krigconstlist, cheapconstlist)
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    return (xnext, fnext)
Beispiel #5
0
def run_multi_opt(kriglist,
                  moboInfo,
                  ypar,
                  krigconstlist=None,
                  cheapconstlist=None):
    """
    Run the optimization of multi-objective acquisition function to find the next sampling point.

    Args:
      kriglist (list): A list containing Kriging instances.
      moboInfo (dict): A structure containing necessary information for Bayesian optimization.
      ypar (nparray): Array contains the current non-dominated solutions.
      krigconstlist (list): List of Kriging object for constraints. Defaults to None.
      cheapconstlist (list): List of constraints function. Defaults to None.
            Expected output of the constraint functions is 1 if the constraint is satisfied and 0 if not.
            The constraint functions MUST have an input of x (the decision variable to be evaluated)

    Returns:
      xnext (nparray): Suggested next sampling point as discovered by the optimization of the acquisition function
      fnext (nparray): Optimized acquisition function

    The available optimizers for the acquisition function are 'cmaes', 'lbfgsb', 'cobyla'.
    Note that this function runs for both unconstrained and constrained single-objective Bayesian optimization.
    """
    acquifuncopt = moboInfo["acquifuncopt"]
    acquifunc = moboInfo["acquifunc"]

    if acquifunc.lower() == 'ehvi':
        acqufunhandle = ehvicalc
    else:
        raise ValueError("Acquisition function handle is not available")

    if acquifuncopt.lower() == 'cmaes':
        Xrand = realval(
            kriglist[0].KrigInfo["lb"], kriglist[0].KrigInfo["ub"],
            np.random.rand(moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[moboInfo["nrestart"]])
        sigmacmaes = 1  # np.mean((KrigNewMultiInfo["ub"] - KrigNewMultiInfo["lb"]) / 6)
        for im in range(0, moboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                xnextcand[im, :], es = cma.fmin2(acqufunhandle,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(ypar, moboInfo,
                                                       kriglist))
                fnextcand[im] = es.result[1]
            else:  # For constrained problem
                xnextcand[im, :], es = cma.fmin2(multiconstfun,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(ypar, kriglist,
                                                       moboInfo, krigconstlist,
                                                       cheapconstlist))
                fnextcand[im] = es.result[1]
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    elif acquifuncopt.lower() == 'ga':
        if krigconstlist is None and cheapconstlist is None:
            templst = []
            if moboInfo['ehvisampling'] == 'efficient':
                for ij in range(np.size(ypar, 0)):
                    idx = np.where(
                        (kriglist[0].KrigInfo["y"] == ypar[ij, 0])
                        & (kriglist[1].KrigInfo["y"] == ypar[ij, 1]))[0][0]
                    templst.append(idx)

                init_seed = kriglist[0].KrigInfo["X_norm"][
                    templst, :] / 2 + 0.5
            else:
                init_seed = None

            xnext, fnext, _ = uncGA(acqufunhandle,
                                    lb=kriglist[0].KrigInfo["lb"],
                                    ub=kriglist[0].KrigInfo["ub"],
                                    args=(ypar, moboInfo, kriglist),
                                    initialization=init_seed)

        else:
            templst = []
            if moboInfo['ehvisampling'] == 'efficient':
                for ij in range(np.size(ypar, 0)):
                    idx = np.where(
                        (kriglist[0].KrigInfo["y"] == ypar[ij, 0])
                        & (kriglist[1].KrigInfo["y"] == ypar[ij, 1]))[0][0]
                    templst.append(idx)

                init_seed = kriglist[0].KrigInfo["X_norm"][
                    templst, :] / 2 + 0.5
            else:
                init_seed = None

            xnext, fnext, _ = uncGA(multiconstfun,
                                    lb=kriglist[0].KrigInfo["lb"],
                                    ub=kriglist[0].KrigInfo["ub"],
                                    args=(ypar, kriglist, moboInfo,
                                          krigconstlist, cheapconstlist),
                                    initialization=init_seed)

    elif acquifuncopt.lower() == 'lbfgsb':
        Xrand = realval(
            kriglist[0].KrigInfo["lb"], kriglist[0].KrigInfo["ub"],
            np.random.rand(moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[moboInfo["nrestart"]])
        lbfgsbbound = np.hstack((kriglist[0].KrigInfo["lb"].reshape(-1, 1),
                                 kriglist[0].KrigInfo["ub"].reshape(-1, 1)))
        for im in range(0, moboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = minimize(acqufunhandle,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(ypar, moboInfo, kriglist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
            else:  # For constrained problem
                res = minimize(multiconstfun,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(ypar, kriglist, moboInfo, krigconstlist,
                                     cheapconstlist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    elif acquifuncopt.lower() == 'diff_evo':
        if moboInfo['ehvisampling'] == 'efficient':
            init_seed = efficientsamp(kriglist, ypar, npop=300)
        else:
            init_seed = 'latinhypercube'

        optimbound = np.hstack((kriglist[0].KrigInfo["lb"].reshape(-1, 1),
                                kriglist[0].KrigInfo["ub"].reshape(-1, 1)))
        if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
            res = differential_evolution(acqufunhandle,
                                         optimbound,
                                         init=init_seed,
                                         args=(ypar, moboInfo, kriglist))
            xnext = res.x
            fnext = res.fun
        else:
            res = differential_evolution(multiconstfun,
                                         optimbound,
                                         init=init_seed,
                                         args=(ypar, kriglist, moboInfo,
                                               krigconstlist, cheapconstlist))
            xnext = res.x
            fnext = res.fun

    elif acquifuncopt.lower() == 'cobyla':
        Xrand = realval(
            kriglist[0].KrigInfo["lb"], kriglist[0].KrigInfo["ub"],
            np.random.rand(moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]))
        xnextcand = np.zeros(
            shape=[moboInfo["nrestart"], kriglist[0].KrigInfo["nvar"]])
        fnextcand = np.zeros(shape=[moboInfo["nrestart"]])
        optimbound = []
        for i in range(len(kriglist[0].KrigInfo["ub"])):
            optimbound.append(lambda x, cc, kriglist, dd, aa, bb, itemp=i: x[
                itemp] - kriglist[0].KrigInfo["lb"][itemp])
            optimbound.append(lambda x, cc, kriglist, dd, aa, bb, itemp=i:
                              kriglist[0].KrigInfo["ub"][itemp] - x[itemp])
        for im in range(0, moboInfo["nrestart"]):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = fmin_cobyla(acqufunhandle,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(ypar, moboInfo, kriglist))
                xnextcand[im, :] = res
                fnextcand[im] = acqufunhandle(res, ypar, moboInfo, kriglist)
            else:
                res = fmin_cobyla(multiconstfun,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(ypar, kriglist, moboInfo,
                                        krigconstlist, cheapconstlist))
                xnextcand[im, :] = res
                fnextcand[im] = multiconstfun(res, ypar, kriglist, moboInfo,
                                              krigconstlist, cheapconstlist)
        I = np.argmin(fnextcand)
        xnext = xnextcand[I, :]
        fnext = fnextcand[I]

    return xnext, fnext
def run_single_opt(krigobj,
                   soboInfo,
                   krigconstlist=None,
                   cheapconstlist=None,
                   pool=None):
    """
    Optimize the single-objective acquisition function to find the next
    sampling point.

    The available optimizers for the acquisition functions are:
        'cmaes', 'lbfgsb', 'diff_evo', 'cobyla'

    Note that this function runs for both unconstrained and constrained
    single-objective Bayesian optimization.

    Args:
        krigobj (kriging_model.Kriging): Objective Kriging instance.
        soboInfo (dict): A structure containing necessary information
            for Bayesian optimization.
        krigconstlist ([kriging_model.Kriging], optional): Kriging
            instances for constraints. Defaults to None.
        cheapconstlist ([func], optional): Constraint functions.
            Defaults to None. Expected output of the constraint
            functions is 1 if satisfied and 0 if not.
            The constraint functions MUST have an input of x (the
            decision variable to be evaluated).
        pool (mp.Pool, optional): An existing mp.Pool instance can be
            specified and passed to solvers/acquisition functions for
            multiprocessing, if supported. Default is None.
    Returns:
        xnext (np.ndarray): n_dv-len array of suggested next sampling
            point as discovered by the optimization of the acquisition
            function.
        fnext (np.ndarray): n_obj-len array of  optimized acquisition
            function fitness metrics.
    """
    acquifuncopt = soboInfo["acquifuncopt"]
    acquifunc = soboInfo["acquifunc"]

    if acquifunc.lower() == 'parego':
        acquifunc = soboInfo['paregoacquifunc']
    else:
        # Seems like string is passed stright to prediction.prediction
        pass

    n_restart = soboInfo["nrestart"]
    n_var = krigobj.KrigInfo["nvar"]
    low_bound = krigobj.KrigInfo["lb"]
    up_bound = krigobj.KrigInfo["ub"]

    xnextcand = np.zeros(shape=[n_restart, n_var])
    fnextcand = np.zeros(shape=[n_restart])

    if acquifuncopt.lower() == 'cmaes':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))
        sigmacmaes = 1  # np.mean((KrigNewMultiInfo["ub"] - KrigNewMultiInfo["lb"]) / 6)
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                xnextcand[im, :], es = cma.fmin2(krigobj.predict,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(acquifunc))
                fnextcand[im] = es.result[1]
            else:  # For constrained problem
                xnextcand[im, :], es = cma.fmin2(singleconstfun,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(krigobj, acquifunc,
                                                       krigconstlist,
                                                       cheapconstlist))
                fnextcand[im] = es.result[1]

    elif acquifuncopt.lower() == 'lbfgsb':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))

        lbfgsbbound = np.hstack(
            (low_bound.reshape(-1, 1), up_bound.reshape(-1, 1)))
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = minimize(krigobj.predict,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(acquifunc))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
            else:  # For constrained problem (on progress)
                res = minimize(singleconstfun,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(krigobj, acquifunc, krigconstlist,
                                     cheapconstlist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun

    elif acquifuncopt.lower() == 'diff_evo':
        if 'de_kwargs' in soboInfo:
            de_kwargs = soboInfo['de_kwargs']
        else:
            de_kwargs = {}

        de_kwargs['init'] = de_kwargs.get('init', 'latinhypercube')

        optimbound = list(zip(low_bound, up_bound))
        de_args = (singleconstfun, optimbound)
        if 'constraints' in de_kwargs:
            cheapconstlist = None  # DE handles cheap constraint functions directly
        args = (krigobj, acquifunc, krigconstlist, cheapconstlist, None, 'inf')
        de_kwargs['args'] = args

        if pool is not None:
            workers = pool.map
            # TODO: Check - we shouldn't need this fix anymore
            # # If MP, set n_cpu to 1 to stop pool in EHVI - pass in existing pool
            # soboInfo['n_cpu'] = 1
        else:
            workers = 1  # Default DE flag

        for im in range(n_restart):
            r_t = time.time()

            res = differential_evolution(*de_args,
                                         **de_kwargs,
                                         workers=workers)

            xnextcand[im, :] = res.x
            fnextcand[im] = res.fun
            print_res(r_t,
                      res.fun,
                      res.x,
                      success=res.success,
                      msg=res.message,
                      n_eval=res.nfev,
                      n_gen=res.nit,
                      i_restart=im,
                      n_restart=n_restart)

    elif acquifuncopt.lower() == 'cobyla':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))

        optimbound = []
        for i in range(len(up_bound)):
            optimbound.append(lambda x, krigobj, aa, bb, cc, itemp=i: x[itemp]
                              - krigobj.KrigInfo["lb"][itemp])
            optimbound.append(lambda x, krigobj, aa, bb, cc, itemp=i: krigobj.
                              KrigInfo["ub"][itemp] - x[itemp])
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = fmin_cobyla(krigobj.predict,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(acquifunc))
                xnextcand[im, :] = res
                fnextcand[im] = krigobj.predict(res, acquifunc)
            else:
                res = fmin_cobyla(singleconstfun,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(krigobj, acquifunc, krigconstlist,
                                        cheapconstlist))
                xnextcand[im, :] = res
                fnextcand[im] = singleconstfun(res, krigobj, acquifunc,
                                               krigconstlist, cheapconstlist)

    I = np.argmin(fnextcand)
    xnext = xnextcand[I, :]
    fnext = fnextcand[I]

    return (xnext, fnext)
def run_multi_opt(kriglist,
                  moboInfo,
                  ypar,
                  krigconstlist=None,
                  cheapconstlist=None,
                  pool=None):
    """
    Optimize the multi-objective acquisition function to find the next
    sampling point.

    The available optimizers for the acquisition functions are:
        'ga', 'diff_evo', 'cmaes', 'lbfgsb', 'cobyla'

    Note that this function runs for both unconstrained and constrained
    multi-objective Bayesian optimization.

    Args:
        kriglist ([kriging_model.Kriging]): n_obj-len list of objective
            Kriging instances.
        moboInfo (dict): A structure containing necessary information
            for Bayesian optimization.
        ypar (np.ndarray): [n_par, n_obj] Current Pareto front
            solutions.
        krigconstlist ([kriging_model.Kriging], optional): Kriging
            instances for constraints. Defaults to None.
        cheapconstlist ([func], optional): Constraint functions.
            Defaults to None. Expected output of the constraint
            functions is 1 if satisfied and 0 if not.
            The constraint functions MUST have an input of x (the
            decision variable to be evaluated).
        pool (mp.Pool, optional): An existing mp.Pool instance can be
            specified and passed to solvers/acquisition functions for
            multiprocessing, if supported. Default is None.

    Returns:
        xnext (np.ndarray): n_dv-len array of suggested next sampling
            point as discovered by the optimization of the acquisition
            function.
        fnext (np.ndarray): n_obj-len array of  optimized acquisition
            function fitness metrics.
    """
    acquifuncopt = moboInfo["acquifuncopt"]
    acquifunc = moboInfo["acquifunc"]

    if acquifunc.lower() == 'ehvi':
        acqufunhandle = ehvicalc
    elif acquifunc.lower() == 'ehvi_vec':
        acqufunhandle = ehvicalc_vec
    elif acquifunc.lower() == 'ehvi_kmac3d':
        acqufunhandle = ehvicalc_kmac3d
    else:
        raise ValueError(
            f"Acquisition function handle {acquifunc} is not available")

    n_restart = moboInfo["nrestart"]
    n_var = kriglist[0].KrigInfo["nvar"]
    low_bound = kriglist[0].KrigInfo["lb"]
    up_bound = kriglist[0].KrigInfo["ub"]

    # n_restart length array for KB solutions
    xnextcand = np.zeros(shape=[n_restart, n_var])
    fnextcand = np.zeros(shape=[n_restart])

    if acquifuncopt.lower() == 'cmaes':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))

        sigmacmaes = 1  # np.mean((KrigNewMultiInfo["ub"] - KrigNewMultiInfo["lb"]) / 6)
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                xnextcand[im, :], es = cma.fmin2(acqufunhandle,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(ypar, moboInfo,
                                                       kriglist))
                fnextcand[im] = es.result[1]
            else:  # For constrained problem
                xnextcand[im, :], es = cma.fmin2(multiconstfun,
                                                 Xrand[im, :],
                                                 sigmacmaes, {
                                                     'verb_disp': 0,
                                                     'verbose': -9
                                                 },
                                                 args=(ypar, kriglist,
                                                       moboInfo, krigconstlist,
                                                       cheapconstlist))
                fnextcand[im] = es.result[1]

    elif acquifuncopt.lower() == 'ga':
        # Load SciPy DE settings from de_kwargs dict
        if 'ga_kwargs' in moboInfo:
            ga_kwargs = moboInfo['ga_kwargs']
        else:
            ga_kwargs = {}

        # TODO Redefine 'ehvisampling' to pass in n_pop and std_scale too - maybe dict?
        if moboInfo['ehvisampling'] == 'efficient':
            init_seed = efficientsamp(kriglist, ypar)
        else:
            init_seed = None

        func = multiconstfun
        args = (ypar, kriglist, moboInfo, krigconstlist, cheapconstlist)

        for im in range(n_restart):
            r_t = time.time()
            x, metric, _ = uncGA2(func,
                                  lb=low_bound,
                                  ub=up_bound,
                                  args=args,
                                  **ga_kwargs,
                                  initialization=init_seed,
                                  pool=pool)

            xnextcand[im, :] = x
            fnextcand[im] = metric
            # TODO: Fill more outputs - maybe have a general results class like SciPY results object
            print_res(r_t,
                      metric,
                      x,
                      n_gen=_[-1, 0],
                      i_restart=im,
                      n_restart=n_restart)

    elif acquifuncopt.lower() == 'lbfgsb':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))

        lbfgsbbound = np.hstack(
            (low_bound.reshape(-1, 1), up_bound.reshape(-1, 1)))
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = minimize(acqufunhandle,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(ypar, moboInfo, kriglist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun
            else:  # For constrained problem
                res = minimize(multiconstfun,
                               Xrand[im, :],
                               method='L-BFGS-B',
                               bounds=lbfgsbbound,
                               args=(ypar, kriglist, moboInfo, krigconstlist,
                                     cheapconstlist))
                xnextcand[im, :] = res.x
                fnextcand[im] = res.fun

    elif acquifuncopt.lower() == 'diff_evo':
        # Load SciPy DE settings from de_kwargs dict
        if 'de_kwargs' in moboInfo:
            de_kwargs = moboInfo['de_kwargs']
        else:
            de_kwargs = {}

        # Set ENDS or DE sample init, if specified. Else, default to 'latinhypercube'
        if moboInfo['ehvisampling'] == 'efficient':
            n_pop_factor = de_kwargs.get('popsize', 10)
            n_var = n_var
            n_pop = n_var * n_pop_factor
            de_kwargs['init'] = efficientsamp(kriglist, ypar, n_pop=n_pop)
        else:
            de_kwargs['init'] = de_kwargs.get('init', 'latinhypercube')

        optimbound = list(zip(low_bound, up_bound))
        de_args = (multiconstfun, optimbound)
        if 'constraints' in de_kwargs:
            cheapconstlist = None  # DE handles cheap constraint functions directly
        # Can't pass pool to acqufunc (child process)
        args = (ypar, kriglist, moboInfo, krigconstlist, cheapconstlist, None,
                'inf')
        de_kwargs['args'] = args

        if pool is not None:
            workers = pool.map
            # TODO: Check - we shouldn't need this fix anymore
            # # If MP, set n_cpu to 1 to stop pool in EHVI - pass in existing pool
            # moboInfo['n_cpu'] = 1
        else:
            workers = 1  # Default DE flag

        for im in range(n_restart):
            r_t = time.time()

            res = differential_evolution(*de_args,
                                         **de_kwargs,
                                         workers=workers)

            xnextcand[im, :] = res.x
            fnextcand[im] = res.fun
            print_res(r_t,
                      res.fun,
                      res.x,
                      success=res.success,
                      msg=res.message,
                      n_eval=res.nfev,
                      n_gen=res.nit,
                      i_restart=im,
                      n_restart=n_restart)

    elif acquifuncopt.lower() == 'cobyla':
        Xrand = realval(low_bound, up_bound, np.random.rand(n_restart, n_var))

        optimbound = []
        for i in range(len(up_bound)):
            optimbound.append(lambda x, cc, kriglist, dd, aa, bb, itemp=i: x[
                itemp] - kriglist[0].KrigInfo["lb"][itemp])
            optimbound.append(lambda x, cc, kriglist, dd, aa, bb, itemp=i:
                              kriglist[0].KrigInfo["ub"][itemp] - x[itemp])
        for im in range(0, n_restart):
            if krigconstlist is None and cheapconstlist is None:  # For unconstrained problem
                res = fmin_cobyla(acqufunhandle,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(ypar, moboInfo, kriglist))
                xnextcand[im, :] = res
                fnextcand[im] = acqufunhandle(res, ypar, moboInfo, kriglist)
            else:
                res = fmin_cobyla(multiconstfun,
                                  Xrand[im, :],
                                  optimbound,
                                  rhobeg=0.5,
                                  rhoend=1e-4,
                                  args=(ypar, kriglist, moboInfo,
                                        krigconstlist, cheapconstlist))
                xnextcand[im, :] = res
                fnextcand[im] = multiconstfun(res, ypar, kriglist, moboInfo,
                                              krigconstlist, cheapconstlist)

    elif acquifuncopt.lower() == 'fcmaes':
        # Delayed import as fcmaes is not installed by default
        import fcmaes.advretry
        import fcmaes.optimizer
        # Load fast-cmaes settings from fc_kwargs dict, if present
        fc_kwargs = moboInfo.get('fc_kwargs', {})
        fc_kwargs['max_evaluations'] = fc_kwargs.get('max_evaluations', 1500)
        fc_kwargs['popsize'] = fc_kwargs.get('popsize', 31)
        fc_kwargs['stop_fitness'] = fc_kwargs.get('stop_fitness', -np.inf)
        optimbound = list(zip(low_bound, up_bound))

        args = (ypar, kriglist, moboInfo, krigconstlist, cheapconstlist, None,
                'inf')
        func = PackagedFunc(multiconstfun, args)
        logger = fc_kwargs.get('logger', None)
        if isinstance(logger, str):
            logger = fcmaes.optimizer.logger(logger)
        elif isinstance(logger, bool):
            if logger:
                logger = fcmaes.optimizer.logger()

        optimizer = fcmaes.optimizer.de_cma(
            max_evaluations=fc_kwargs['max_evaluations'],
            popsize=fc_kwargs['popsize'],
            stop_fitness=fc_kwargs['stop_fitness'])

        for im in range(n_restart):
            r_t = time.time()
            res = fcmaes.advretry.minimize(func.eval,
                                           optimbound,
                                           optimizer=optimizer,
                                           logger=logger,
                                           **fc_kwargs)

            xnextcand[im, :] = res.x
            fnextcand[im] = res.fun
            print_res(r_t,
                      res.fun,
                      res.x,
                      success=res.success,
                      n_eval=res.nfev,
                      i_restart=im,
                      n_restart=n_restart)

    else:
        msg = f"Requested acquifuncopt '{acquifuncopt}' is not available."
        raise NotImplementedError(msg)

    I = np.argmin(fnextcand)
    xnext = xnextcand[I, :]
    fnext = fnextcand[I]

    return xnext, fnext