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
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