Exemplo n.º 1
0
def constantk_search_snopt_min(simplex, inter_par, K, y_safe, L_safe):
    '''
    The function F is composed as:  1st        - objective
                                    2nd to nth - simplex bounds
                                    n+1 th ..  - safe constraints
    :param x0        :     The mass-center of delaunay simplex
    :param inter_par :
    :param xc        :
    :param R2:
    :param y0:
    :param K0:
    :param A_simplex:
    :param b_simplex:
    :param lb_simplex:
    :param ub_simplex:
    :param y_safe:
    :param L_safe:
    :return:
    '''
    xE = inter_par.xi
    n = xE.shape[0]

    # Determine if the boundary corner exists in simplex, if boundary corner detected:
    # e(x) = || x - x' ||^2_2
    # else, e(x) is the regular uncertainty function.
    exist = unevaluated_vertices_identification(xE, simplex)

    # -------  ADD THE FOLLOWING LINE WHEN DEBUGGING --------
    # simplex = xi[:, tri[ind, :]]
    # -------  ADD THE FOLLOWING LINE WHEN DEBUGGING --------

    # Find the minimizer of the search fucntion in a simplex using SNOPT package.
    R2, xc = Utils.circhyp(simplex, n)
    # x is the center of this simplex
    x = np.dot(simplex, np.ones([n + 1, 1]) / (n + 1))

    # First find minimizer xr on reduced model, then find the 2D point corresponding to xr. Constrained optm.
    A_simplex, b_simplex = Utils.search_simplex_bounds(simplex)
    lb_simplex = np.min(simplex, axis=1)
    ub_simplex = np.max(simplex, axis=1)

    inf = 1.0e+20

    m = n + 1  # The number of constraints which is determined by the number of simplex boundaries.
    assert m == A_simplex.shape[0], 'The No. of simplex constraints is wrong'

    # TODO: multiple safe constraints in future.
    # nF: The number of problem functions in F(x), including the objective function, linear and nonlinear constraints.
    # ObjRow indicates the number of objective row in F(x).
    ObjRow = 1

    # solve for constrained minimization of safe learning within each open ball of the vertices of simplex.
    # Then choose the one with the minimum continuous function value.
    x_solver = np.empty(shape=[n, 0])
    y_solver = []

    for i in range(n + 1):

        vertex = simplex[:, i].reshape(-1, 1)
        # First find the y_safe[vertex]:
        val, idx, x_nn = Utils.mindis(vertex, xE)
        if val > 1e-10:
            # This vertex is a boundary corner point. No safe-guarantee, we do not optimize around support points.
            continue
        else:
            # TODO: multiple safe constraints in future.
            safe_bounds = y_safe[idx]

            if n > 1:
                # The first function in F(x) is the objective function, the rest are m simplex constraints.
                # The last part of functions in F(x) is the safe constraints.
                # In high dimension, A_simplex make sure that linear_derivative_A won't be all zero.
                nF = 1 + m + 1  # the last 1 is the safe constraint.
                Flow = np.hstack((-inf, b_simplex.T[0], -safe_bounds))
                Fupp = inf * np.ones(nF)

                # The lower and upper bounds of variables x.
                xlow = np.copy(lb_simplex)
                xupp = np.copy(ub_simplex)

                # For the nonlinear components, enter any nonzero value in G to indicate the location
                # of the nonlinear derivatives (in this case, 2).

                # A must be properly defined with the correct derivative values.
                linear_derivative_A = np.vstack((np.zeros(
                    (1, n)), A_simplex, np.zeros((1, n))))
                nonlinear_derivative_G = np.vstack((2 * np.ones(
                    (1, n)), np.zeros((m, n)), 2 * np.ones((1, n))))

            else:

                # For 1D problem, the simplex constraint is defined in x bounds.
                # TODO multiple safe cons.
                # 2 = 1 obj + 1 safe con. Plus one redundant constraint to make matrix A suitable.
                nF = 2 + 1
                Flow = np.array([-inf, -safe_bounds, -inf])
                Fupp = np.array([inf, inf, inf])
                xlow = np.min(simplex) * np.ones(n)
                xupp = np.max(simplex) * np.ones(n)

                linear_derivative_A = np.vstack((np.zeros(
                    (1, n)), np.zeros((1, n)), np.ones((1, n))))
                nonlinear_derivative_G = np.vstack((2 * np.ones(
                    (2, n)), np.zeros((1, n))))

            x0 = x.T[0]

            # -------  ADD THE FOLLOWING LINE WHEN DEBUGGING --------
            # cd dogs
            # -------  ADD THE FOLLOWING LINE WHEN DEBUGGING --------

            save_opt_for_snopt_ck(n, nF, inter_par, xc, R2, K, A_simplex,
                                  L_safe, vertex, exist)

            # Since adaptiveK using ( p(x) - f0 ) / e(x), the objective function is nonlinear.
            # The constraints are generated by simplex bounds, all linear.

            options = SNOPT_options()
            options.setOption('Infinite bound', inf)
            options.setOption('Verify level', 3)
            options.setOption('Verbose', False)
            options.setOption('Print level', -1)
            options.setOption('Scale option', 2)
            options.setOption('Print frequency', -1)
            options.setOption('Summary', 'No')

            result = snopta(dogsobj,
                            n,
                            nF,
                            x0=x0,
                            name='DeltaDOGS_snopt',
                            xlow=xlow,
                            xupp=xupp,
                            Flow=Flow,
                            Fupp=Fupp,
                            ObjRow=ObjRow,
                            A=linear_derivative_A,
                            G=nonlinear_derivative_G,
                            options=options)

            x_solver = np.hstack((x_solver, result.x.reshape(-1, 1)))
            y_solver.append(result.objective)

    y_solver = np.array(y_solver)
    y = np.min(y_solver)
    x = x_solver[:, np.argmin(y_solver)].reshape(-1, 1)

    return x, y
Exemplo n.º 2
0
def triangulation_search_bound_snopt(inter_par, xi, y0, ind_min, y_safe,
                                     L_safe):
    # reddir is a vector
    inf = 1e+20
    n = xi.shape[0]  # The dimension of the reduced model.

    # 0: Build up the Delaunay triangulation based on reduced subspace.
    if n == 1:
        sx = sorted(range(xi.shape[1]), key=lambda x: xi[:, x])
        tri = np.zeros((xi.shape[1] - 1, 2))
        tri[:, 0] = sx[:xi.shape[1] - 1]
        tri[:, 1] = sx[1:]
        tri = tri.astype(np.int32)
    else:
        options = 'Qt Qbb Qc' if n <= 3 else 'Qt Qbb Qc Qx'
        tri = Delaunay(xi.T, qhull_options=options).simplices
        keep = np.ones(len(tri), dtype=bool)
        for i, t in enumerate(tri):
            if abs(np.linalg.det(np.hstack(
                (xi.T[t], np.ones([1, n + 1]).T)))) < 1E-15:
                keep[i] = False  # Point is coplanar, we don't want to keep it
        tri = tri[keep]
    # Sc contains the continuous search function value of the center of each Delaunay simplex

    # 1: Identify the minimizer of adaptive K continuous search function
    Sc = np.zeros([np.shape(tri)[0]])
    Scl = np.zeros([np.shape(tri)[0]])
    for ii in range(np.shape(tri)[0]):
        R2, xc = Utils.circhyp(xi[:, tri[ii, :]], n)
        if R2 < inf:
            # initialize with body center of each simplex
            x = np.dot(xi[:, tri[ii, :]], np.ones([n + 1, 1]) / (n + 1))
            Sc[ii] = (interpolation.interpolate_val(x, inter_par) -
                      y0) / (R2 - np.linalg.norm(x - xc)**2)
            if np.sum(ind_min == tri[ii, :]):
                Scl[ii] = np.copy(Sc[ii])
            else:
                Scl[ii] = inf
        else:
            Scl[ii] = inf
            Sc[ii] = inf

    if np.min(Sc) < 0:
        func = 'p'
        # The minimum of Sc is negative, minimize p(x) instead.
        Scp = np.zeros(tri.shape[0])
        for ii in range(tri.shape[0]):
            x = np.dot(xi[:, tri[ii, :]], np.ones([n + 1, 1]) / (n + 1))
            Scp[ii] = interpolation.interpolate_val(x, inter_par)
        # Globally minimize p(x)
        ind = np.argmin(Scp)
        x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1))
        xm, ym = adaptiveK_p_snopt_min(x, inter_par, y_safe, L_safe)
        result = 'glob'
    else:
        func = 'sc'
        # Global one, the minimum of Sc has the minimum value of all circumcenters.

        ind = np.argmin(Sc)
        R2, xc = Utils.circhyp(xi[:, tri[ind, :]], n)
        # x is the center of this simplex
        x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1))

        # First find minimizer xr on reduced model, then find the 2D point corresponding to xr. Constrained optm.
        A_simplex, b_simplex = Utils.search_simplex_bounds(xi[:, tri[ind, :]])
        lb_simplex = np.min(xi[:, tri[ind, :]], axis=1)
        ub_simplex = np.max(xi[:, tri[ind, :]], axis=1)

        xm, ym = adaptiveK_search_snopt_min(x, inter_par, xc, R2, y0, K0,
                                            A_simplex, b_simplex, lb_simplex,
                                            ub_simplex, y_safe, L_safe)
        # Local one

        ind = np.argmin(Scl)
        R2, xc = Utils.circhyp(xi[:, tri[ind, :]], n)
        x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1))

        A_simplex, b_simplex = Utils.search_simplex_bounds(xi[:, tri[ind, :]])
        lb_simplex = np.min(xi[:, tri[ind, :]], axis=1)
        ub_simplex = np.max(xi[:, tri[ind, :]], axis=1)
        xml, yml = adaptiveK_search_snopt_min(x, inter_par, xc, R2, y0, K0,
                                              A_simplex, b_simplex, lb_simplex,
                                              ub_simplex, y_safe, L_safe)
        if yml < ym:
            xm = np.copy(xml)
            ym = np.copy(yml)
            result = 'local'
        else:
            result = 'glob'
    return xm, ym, result, func