def tringulation_search_bound_constantK(inter_par, xi, K, ind_min): ''' This function is the core of constant-K continuous search function. :param inter_par: Contains interpolation information w, v. :param xi: The union of xE(Evaluated points) and xU(Support points) :param K: Tuning parameter for constant-K, K = K*K0. K0 is the range of yE. :param ind_min: The correspoding index of minimum of yE. :return: The minimizer, xc, and minimum, yc, of continuous search function. ''' inf = 1e+20 n = xi.shape[0] # Delaunay Triangulation 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] # Search the minimum of the synthetic quadratic model Sc = np.zeros([np.shape(tri)[0]]) Scl = np.zeros([np.shape(tri)[0]]) for ii in range(np.shape(tri)[0]): # R2-circumradius, xc-circumcircle center R2, xc = Utils.circhyp(xi[:, tri[ii, :]], n) # x is the center of the current simplex x = np.dot(xi[:, tri[ii, :]], np.ones([n + 1, 1]) / (n + 1)) Sc[ii] = interpolation.interpolate_val( x, inter_par) - K * (R2 - np.linalg.norm(x - xc)**2) if np.sum(ind_min == tri[ii, :]): Scl[ii] = np.copy(Sc[ii]) else: Scl[ii] = inf # Global one t = np.min(Sc) ind = np.argmin(Sc) R2, xc = Utils.circhyp(xi[:, tri[ind, :]], n) x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1)) xm, ym = Constant_K_Search(x, inter_par, xc, R2, K) # Local one t = np.min(Scl) ind = np.argmin(Scl) R2, xc = Utils.circhyp(xi[:, tri[ind, :]], n) # Notice!! ind_min may have a problem as an index x = np.copy(xi[:, ind_min].reshape(-1, 1)) xml, yml = Constant_K_Search(x, inter_par, xc, R2, K) if yml < ym: xm = np.copy(xml) ym = np.copy(yml) xm = xm.reshape(-1, 1) ym = ym[0, 0] return xm, ym
def discrete_function_evaluation(self, x): ''' Evaluate the discrete search function value at support poitns. :param x: :return: ''' return (self.inter_par.inter_val(x) - min(self.yp))[0] / Utils.mindis( x, self.xE)[0]
def add_sup(xE, xU, ind_min): ''' To avoid duplicate values in support points for Delaunay Triangulation. :param xE: Evaluated points. :param xU: Support points. :param ind_min: The minimum point's index in xE. return: Combination of unique elements of xE and xU and the index of the minimum yp. ''' xmin = xE[:, ind_min] xs = np.hstack((xE, xU)) # Construct the concatenate of xE and xU and return the array that every column is unique x_unique = xs[:, 0].reshape(-1, 1) for x in xs.T: dis, _, _ = Utils.mindis(x.reshape(-1, 1), x_unique) if dis > 1e-5: x_unique = np.hstack((x_unique, x.reshape(-1, 1))) # Find the minimum point's index: ind_min _, ind_min_new, _ = Utils.mindis(xmin.reshape(-1, 1), x_unique) return x_unique, ind_min_new
def points_neighbers_find(x, xE, xU, Bin, Ain): ''' This function aims for checking whether it's activated iteration or inactivated. If activated: perform function evaluation. Else: add the point to support points. :param x: Minimizer of continuous search function. :param xE: Evaluated points. :param xU: Support points. :return: x, xE is unchanged. If success == 1: active constraint, evaluate x. Else: Add x to xU. ''' x = x.reshape(-1, 1) x1 = Utils.mindis(x, np.concatenate((xE, xU), axis=1))[2].reshape(-1, 1) active_cons = [] b = Bin - np.dot(Ain, x) for i in range(len(b)): if b[i][0] < 1e-3: active_cons.append(i + 1) active_cons = np.array(active_cons) active_cons1 = [] b = Bin - np.dot(Ain, x1) for i in range(len(b)): if b[i][0] < 1e-3: active_cons1.append(i + 1) active_cons1 = np.array(active_cons1) # Explain the following two criterias,both are actived constraints: # The first means that x is an interior point. # The second means that x and x1 have exactly the same constraints. if len(active_cons) == 0 or abs( min(ismember(active_cons, active_cons1)) - 1.0) < 1e-6: newadd = 1 success = 1 if xU.shape[1] != 0 and Utils.mindis(x, xU)[0] == 0: newadd = 0 # Point x Already exists in support points xU, x should be evaluated. else: success = 0 newadd = 0 xU = np.hstack((xU, x)) return x, xE, xU, success, newadd
def unevaluated_vertices_identification(xE, simplex): exist = 0 N = simplex.shape[1] for i in range(N): vertice = simplex[:, i].reshape(-1, 1) val, idx, x_nn = Utils.mindis(vertice, xE) if val == 0: # vertice exists in evaluated point set pass else: exist = 1 break return exist
def Constant_K_Search(simplex, inter_par, K, lb=[], ub=[]): n = simplex.shape[0] R2, xc = Utils.circhyp(simplex, n) x = np.dot(simplex, np.ones([n + 1, 1]) / (n + 1)) costfun = lambda x: Continuous_search_cost(x, inter_par, xc, R2, K)[0] costjac = lambda x: Continuous_search_cost(x, inter_par, xc, R2, K)[1] opt = {'disp': False} bnds = tuple([(0, 1) for i in range(int(n))]) res = optimize.minimize(costfun, x, jac=costjac, method='TNC', bounds=bnds, options=opt) x = res.x y = res.fun return x, y
def check_activated(x, xE, xU, Bin, Ain): # modified for Lambda Delta DOGS # inactive step completed # Add the new point to the set # xE: evaluation points. # xU: unevaluated points. xs, _ = add_sup(xE, xU, 1) # Find closest point to x del_general, index, x1 = Utils.mindis(x, xs) # Calculate the active constraints at x and x1 ind = np.where(np.dot(Ain, x) - Bin > -1e-4)[0] ind1 = np.where(np.dot(Ain, x1) - Bin > -1e-4)[0] if len(ind) == 0 or min(ismember(ind, ind1)) == 1: label = 1 else: label = 0 return label
def adaptivek_search_cost_snopt(x): x = x.reshape(-1, 1) folder = folder_path() var_opt = io.loadmat(folder + "/opt_info.mat") n = var_opt['n'][0, 0] xc = var_opt['xc'] R2 = var_opt['R2'][0, 0] y0 = var_opt['y0'][0, 0] nF = var_opt['nF'][0, 0] A = var_opt['A'] y_safe = var_opt['y_safe'] L_safe = var_opt['L_safe'][0, 0] # Initialize the output F and G. F = np.zeros(nF) method = var_opt['inter_par_method'][0] inter_par = interpolation.Inter_par(method=method) inter_par.w = var_opt['inter_par_w'] inter_par.v = var_opt['inter_par_v'] inter_par.xi = var_opt['inter_par_xi'] p = interpolation.interpolate_val(x, inter_par) e = R2 - np.linalg.norm(x - xc)**2 gp = interpolation.interpolate_grad(x, inter_par) ge = -2 * (x - xc) de = (1e-10 if abs(p - y0) < 1e-10 else p - y0) F[0] = -e / de # K0 = 0 because only at 1st iteration we only have 1 function evaluation. val, idx, x_nn = Utils.mindis(x, inter_par.xi) F[-1] = y_safe[idx] - L_safe * np.linalg.norm(x - x_nn) if n > 1: # nD data has n+1 simplex bounds. F[1:-1] = (np.dot( A, x)).T[0] # broadcast input array from (3,1) into shape (3). DM = -ge / de + e * gp / de**2 G = np.hstack( (DM.flatten(), (-L_safe * (x - x_nn) / np.linalg.norm(x - x_nn)).flatten())) return F, G
def lorenz_noise_eval(x, t): h = 0.001 ROOT = os.getcwd() file_name = 'points.mat' file_path = os.path.join(ROOT, file_name) data = io.loadmat(file_path) xE = data['xE'] index = Utils.mindis(x, xE)[1] points_eval_data_path = os.path.join(ROOT, 'AllPoints/pt' + str(index) + '.mat') points_eval_data = io.loadmat(points_eval_data_path) zs = points_eval_data['zs'][0] length = int(min((t / h), 1000)) xx = uq.data_moving_average(zs, length) sig = np.sqrt(uq.stationary_statistical_learning_reduced(xx, 18)[0]) return sig
def initial_calc1D(self, adogs): """ Plot the initial objective function together with the uncertainty of 1D parameter space. :return: """ adogs.func_prior_xE = np.linspace(adogs.physical_lb[0], adogs.physical_ub[0], self.size) adogs.func_prior_yE = np.zeros(adogs.func_prior_xE.shape[0]) adogs.func_prior_sigma = np.zeros(adogs.func_prior_xE.shape[0]) for i in range(self.size): adogs.func_prior_yE[i] = adogs.truth_eval(adogs.func_prior_xE[i], adogs.T0) adogs.func_prior_sigma[i] = adogs.sigma_eval( adogs.func_prior_xE[i], adogs.T0) * 2 # For the evaluated data point, the uncertainty has been reduced for i in range(adogs.xE.shape[0]): val, idx, xmin = Utils.mindis(adogs.xE[:, i], adogs.func_prior_xE) if val < 1e-10: adogs.func_prior_sigma[idx] = adogs.sigma[i]
def lorenz_func_eval(x, t): h = 0.001 ROOT = os.getcwd() file_name = 'points.mat' file_path = os.path.join(ROOT, file_name) if not os.path.exists(file_path): # First function evaluation, create data points and save it in file data = {'xE': x} index = 0 type = 'identify' io.savemat(file_path, data) else: data = io.loadmat(file_path) xE = data['xE'] val, idx, _ = Utils.mindis(x, xE) if val < 1e-6: # x has already been evaluated index = idx type = 'additional' else: index = xE.shape[1] type = 'identify' xE = np.hstack((xE, x)) data = {'xE': xE} io.savemat(file_path, data) l = lorenz.Lorenz(x, t, h, 23.57, index, type) l.lorenz_eval() # J, sig = l.main() # return J, sig return l.J
def constant_surrogate_solver(self): ''' Surrogate solver using constant K algorithm iteratively perform additional sampling/ mesh refinement/ identifying sampling. :return: ''' self.iter += 1 self.K0 = np.ptp(self.yE, axis=0) self.inter_par = interpolation.InterParams(self.xE) self.yp = self.inter_par.regressionparameterization( self.yE, self.sigma) # Calculate the discrete function. self.sd = np.amin( (self.yp, 2 * self.yE - self.yp), 0) - self.L * self.sigma ind_min = np.argmin(self.yp) self.yd = np.amin(self.sd) self.index_min_yd = np.argmin(self.sd) self.xd = np.copy(self.xE[:, self.index_min_yd].reshape(-1, 1)) self.yu = np.zeros(self.xU.shape[1]) if self.xU.shape[1] != 0: for ii in range(self.xU.shape[1]): self.yu[ii] = self.discrete_function_evaluation(self.xU[:, ii]) else: pass if self.xU.shape[1] != 0 and np.amin(self.yu) < np.min(self.yp): ind = np.argmin(self.yu) self.xc = np.copy(self.xU[:, ind].reshape(-1, 1)) self.yc = -np.inf self.xU = scipy.delete(self.xU, ind, 1) else: while 1: xs, ind_min = cartesian_grid.add_sup(self.xE, self.xU, ind_min) xc, self.yc, result = constantK.tringulation_search_bound_constantK( self.inter_par, xs, self.K * self.K0, ind_min) if self.inter_par.inter_val(xc) < min(self.yp): self.xc = np.round(xc * self.ms) / self.ms break else: self.xc = np.round(xc * self.ms) / self.ms if Utils.mindis(self.xc, self.xE)[0] < 1e-6: break self.xE, self.xU, success, newadd = cartesian_grid.points_neighbers_find( self.xc, self.xE, self.xU, self.Bin, self.Ain) if success == 1: break else: self.yu = np.hstack( (self.yu, self.discrete_function_evaluation(self.xc))) if self.xU.shape[1] != 0 and np.amin(self.yu) < np.min( self.yp): xc_discrete = self.discrete_function_evaluation(self.xc) if np.amin(self.yu) < xc_discrete: ind = np.argmin(self.yu) self.xc = np.copy(self.xU[:, ind].reshape(-1, 1)) self.yc = -np.inf self.xU = scipy.delete(self.xU, ind, 1) if self.yd < self.yc: self.iter_type = 'sdmin' self.T[self.index_min_yd] += self.dt self.yE[self.index_min_yd] = self.func_eval( self.xd, self.T[self.index_min_yd]) self.sigma[self.index_min_yd] = self.sigma_eval( self.xd, self.T[self.index_min_yd]) self.iteration_summary_matrix[self.iter] = { 'x': self.xd.tolist(), 'y': self.yE[self.index_min_yd], 'T': self.T[self.index_min_yd], 'sig': self.sigma[self.index_min_yd] } if self.T[self.index_min_yd] >= self.Tmax: # Function evaluation has reached the limit, refine the mesh # TODO refine the mesh here?????? # tODO or, directly goes to eval xc min? # TODO cuz xcmin is the initial evaluation, not expensive self.Tmax_reached = True else: self.Tmax_reached = False else: if Utils.mindis(self.xc, self.xE)[0] < 1e-6: self.iter_type = 'refine' self.K *= 2 self.ms *= 2 self.L += self.L0 else: self.iter_type = 'scmin' self.T = np.hstack((self.T, self.T0)) self.xE = np.hstack((self.xE, self.xc)) self.yE = np.hstack((self.yE, self.func_eval(self.xc, self.T0))) self.sigma = np.hstack( (self.sigma, self.sigma_eval(self.xc, self.T0))) self.iteration_summary_matrix[self.iter] = { 'x': self.xc.tolist(), 'y': self.yE[-1], 'T': self.T0, 'sig': self.sigma[-1] } if self.save_fig: self.iter_plot(self) if self.iter_summary: self.plot.summary_display(self)
interpolation_plot = 0 subplot_plot = 0 store_plot = 1 # The indicator to store ploting results as png. nff = 1 # Number of experiments # Algorithm choice: sc = "AdaptiveK" # The type of continuous search function alg_name = 'DDOGS/' # Calculate the Initial trinagulation points num_iter = 0 # Represents how many iteration the algorithm goes Nm = 8 # Initial mesh grid size L_refine = 0 # Initial refinement sign # Truth function fun, lb, ub, y0, xmin, fname = Utils.test_fun(fun_arg, n) func_eval = partial(Utils.fun_eval, fun, lb, ub) # safe constraints safe_fun, lb, ub, safe_name, L_safe = Utils.test_safe_fun(safe_fun_arg, n) safe_eval = partial(Utils.fun_eval, safe_fun, lb, ub) xU = Utils.bounds(np.zeros([n, 1]), np.ones([n, 1]), n) Ain = np.concatenate((np.identity(n), -np.identity(n)), axis=0) Bin = np.concatenate((np.ones((n, 1)), np.zeros((n, 1))), axis=0) regret = np.zeros((nff, iter_max)) estimate = np.zeros((nff, iter_max)) datalength = np.zeros((nff, iter_max)) mesh = np.zeros((nff, iter_max)) for ff in range(nff):
def __init__(self, bounds, func_eval, noise_eval, truth_eval, options, A=None, b=None): """ Alpha DOGS is an efficient optimization algorithm for time-averaged statistics. :param bounds : The physical bounds of the input for the test problem, e.g. lower bound = [0, 0, 0] while upper bound = [1, 1, 1] then bnds = np.hstack((np.zeros((3,1)), np.ones((3,1)))) :param func_eval : The objective function :param noise_eval : The function for noise evaluation :param truth_eval : The function to evaluate the truth values :param A : The linear constraints of parameter space :param b : The linear constraints of parameter space :param options : The options for alphaDOGS """ # n: The dimension of input parameter space self.n = bounds.shape[0] # physical lb & ub: Normalize the physical bounds self.physical_lb = bounds[:, 0].reshape(-1, 1) self.physical_ub = bounds[:, 1].reshape(-1, 1) # lb & ub: The normalized search bounds self.lb = np.zeros((self.n, 1)) self.ub = np.ones((self.n, 1)) # ms: The mesh size for each iteration. This is the initial definition. self.initial_mesh_size = options.get_option('Initial mesh size') self.ms = 2**self.initial_mesh_size self.num_mesh_refine = options.get_option('Number of mesh refinement') self.max_mesh_size = 2**(self.initial_mesh_size + self.num_mesh_refine) self.iter = 0 # Define the surrogate model if options.get_option('Constant surrogate') and options.get_option( 'Adaptive surrogate'): raise ValueError( 'Constant and Adaptive surrogate both activated. Set one to False then rerun code.' ) elif not options.get_option( 'Constant surrogate') and not options.get_option( 'Adaptive surrogate'): raise ValueError( 'Constant and Adaptive surrogate both inactivated. Set one to True then rerun code.' ) elif options.get_option('Constant surrogate'): self.surrogate_type = 'c' elif options.get_option('Adaptive surrogate'): self.surrogate_type = 'a' else: pass if self.surrogate_type == 'c': # Define the parameters for discrete and continuous constant search function self.L = options.get_option('Constant L') self.L0 = self.L self.K = options.get_option('Constant K') elif self.surrogate_type == 'a': self.y0 = options.get_option('Target value') # Define the linear constraints, Ax <= b. if A and b are None type, set them to be the box domain constraints. if (A and b) is None: self.Ain = np.concatenate( (np.identity(self.n), -np.identity(self.n)), axis=0) self.Bin = np.concatenate((np.ones( (self.n, 1)), np.zeros((self.n, 1))), axis=0) else: pass # Define the statistics for time length self.T0 = options.get_option('Initial time length') self.dt = options.get_option('Incremental time step') self.eval_times = options.get_option('Maximum evaluation times') self.Tmax = self.T0 + self.eval_times * self.dt self.Tmax_reached = None if options.get_option('Scipy solver') and options.get_option( 'Snopt solver'): raise ValueError('More than one optimization solver specified!') elif not options.get_option('Scipy solver') and not options.get_option( 'Snopt solver'): raise ValueError('No optimization solver specified!') elif options.get_option('Scipy solver'): self.solver_type = 'scipy' elif options.get_option('Snopt solver'): self.solver_type = 'snopy' else: pass # Initialize the function evaluation, noise sigma evaluation and truth function evaluation. # capsulate those three functions with physical bounds self.func_eval = partial(Utils.fun_eval, func_eval, self.physical_lb, self.physical_ub) self.sigma_eval = partial(Utils.fun_eval, noise_eval, self.physical_lb, self.physical_ub) self.truth_eval = partial(Utils.fun_eval, truth_eval, self.physical_lb, self.physical_ub) # Define the global optimum and its values if options.get_option('Global minimizer known'): self.xmin = Utils.normalize_bounds( options.get_option('Global minimizer'), self.physical_lb, self.physical_ub) self.y0 = options.get_option('Target value') else: self.xmin = None self.y0 = None # Define the iteration type for each sampling iteration. self.iter_type = None # Define the initial sites and their function evaluations if options.get_option('Initial sites known'): physical_initial_sites = options.get_option('Initial sites') # Normalize the bound self.xE = Utils.normalize_bounds(physical_initial_sites, self.physical_lb, self.physical_ub) else: self.xE = Utils.random_initial(self.n, 2 * self.n, self.ms, self.Ain, self.Bin, self.xU) if options.get_option('Initial function values') is not None: self.yE = options.get_option('Initial function values') self.T = self.T0 * np.ones(self.xE.shape[1], dtype=float) self.sigma = options.get_option('Initial funtion noise') else: # Compute the function values, time length, and noise level at initial sites self.yE = np.zeros(self.xE.shape[1]) self.T = self.T0 * np.ones(self.xE.shape[1], dtype=float) self.sigma = np.zeros(self.xE.shape[1]) for i in range(2 * self.n): self.yE[i] = self.func_eval(self.xE[:, i], self.T[i]) self.sigma[i] = self.sigma_eval(self.xE[:, i], self.T0) self.iteration_summary_matrix = {} # Define the initial support points self.xU = Utils.bounds(self.lb, self.ub, self.n) self.xU = Utils.unique_support_points(self.xU, self.xE) self.yu = None self.K0 = np.ptp(self.yE, axis=0) # Define the interpolation self.inter_par = None self.yp = None # Define the discrete search function self.sd = None # Define the minimizer of continuous search function, parameter to be evaluated, xc & yc. self.xc = None self.yc = None # Define the minimizer of discrete search function self.xd = None self.yd = None self.index_min_yd = None # Although it is stochastic, just display the behavior instead of the actual data to show the trend. # Define the name of directory to store the figures self.algorithm_name = options.solverName # ==== Plot section here ==== self.plot = plot.PlotClass() # Define the parameter to save image or no, and what format to save for images self.save_fig = options.get_option('Plot saver') self.fig_format = options.get_option('Figure format') # Generate the folder path self.func_path = options.get_option( 'Objective function name') # Function folder, e.g. Lorenz self.current_path = None # Directory path self.plot_folder = None # Plot storage folder self.folder_path_generator() # Determine the folder paths above self.func_name = options.get_option( 'Objective function name' ) # Define the name of the function called. # All the prior function values should be provided by user, instead of solver calculating those values. # Generate the plot of test function self.func_initial_prior = True # The objective function values are stored in func_prior_yE # for the future iteration, just change the point of func_prior_sigma that is close to the evaluated point self.func_prior_xE_2DX = None self.func_prior_xE_2DY = None self.func_prior_xE_2DZ = None if options.get_option('Function prior file path') is not None: self.func_prior_file_name = options.get_option( 'Function prior file path') data = io.loadmat(self.func_prior_file_name) # The prior data must have the following keyword self.func_prior_xE = data['x'] self.func_prior_yE = data['y'][0] self.func_prior_sigma = data['sigma'][0] * 2 if self.n == 1: # Define the range of plot in y-axis self.plot_ylow = np.min(self.func_prior_yE) * 2 self.plot_yupp = np.max(self.func_prior_yE) * 2 else: self.func_prior_file_name = None if options.get_option('Function evaluation cheap') and self.n < 3: if self.n == 1: self.plot.initial_calc1D(self) elif self.n == 2: self.plot.initial_calc2D(self) else: pass if self.n == 1: # Define the range of plot in y-axis self.plot_ylow = np.min(self.func_prior_yE) * 2 self.plot_yupp = np.max(self.func_prior_yE) * 2 else: self.func_initial_prior = False self.func_prior_xE = None self.func_prior_yE = None # Define the range of plot in y-axis self.plot_ylow = np.min(self.yE) * 2 self.plot_yupp = np.max(self.yE) * 2 print( 'Function evaluation is expensive and no file that contains prior function values information ' 'is found.') if self.n >= 3: print( 'Parameter space dimenion > 3, the plot for each iteration is unavailable.' ) if self.save_fig and self.func_initial_prior: if self.n == 1: self.initial_plot = self.plot.initial_plot1D self.iter_plot = self.plot.plot1D elif self.n == 2: self.initial_plot = self.plot.initial_plot2D self.iter_plot = self.plot.plot2D else: self.initial_plot = None print( "Parameter space higher than 2, set 'Plot saver' to be False." ) self.initial_plot(self) self.iter_summary = options.get_option('Iteration summary') self.optm_summary = options.get_option('Optimization summary')
def continuous_search_plot1D(self, adogs): ''' Plot the continuous search function. :return: ''' xU = Utils.bounds(adogs.lb, adogs.ub, adogs.n) if adogs.iter_type == 'scmin' and Utils.mindis(adogs.xc, xU)[0] > 1e-6: xi = np.hstack((adogs.xE[:, :-1], adogs.xU)) else: xi = np.hstack((adogs.xE, adogs.xU)) 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) num_plot_points = 2000 xe_plot = np.zeros((tri.shape[0], num_plot_points)) e_plot = np.zeros((tri.shape[0], num_plot_points)) sc_plot = np.zeros((tri.shape[0], num_plot_points)) for ii in range(len(tri)): simplex_range = np.copy(xi[:, tri[ii, :]]) # Discretized mesh grid on x direction in one simplex x = np.linspace(simplex_range[0, 0], simplex_range[0, 1], num_plot_points) # Circumradius and circumcenter for current simplex R2, xc = Utils.circhyp(xi[:, tri[ii, :]], adogs.n) for jj in range(len(x)): # Interpolation p(x) p = adogs.inter_par.inter_val(x[jj]) # Uncertainty function e(x) e_plot[ii, jj] = (R2 - np.linalg.norm(x[jj] - xc)**2) # Continuous search function s(x) sc_plot[ii, jj] = p - adogs.K * adogs.K0 * e_plot[ii, jj] xe_plot[ii, :] = np.copy(x) for i in range(len(tri)): # Plot the uncertainty function e(x) # plt.plot(xe_plot[i, :], e_plot[i, :] - 5.5, c='g', label=r'$e(x)$') # Plot the continuous search function sc(x) plt.plot(xe_plot[i, :], sc_plot[i, :], 'r--', zorder=20, label=r'$S_c(x)$') yc_min = sc_plot.flat[np.abs(xe_plot - adogs.xc).argmin()] plt.scatter(adogs.xc, yc_min, c=(1, 0.769, 0.122), marker='D', zorder=15, label=r'min $S_c(x)$')
def continuous_search_1d_plot(xE, fun_eval): ''' Given evaluated points set xE, and the objective function. Plot the interpolation, uncertainty function and continuous search function. :param xE: evaluated points set xE :param fun_eval: obj function :return: ''' N = xE.shape[1] yE = np.zeros(N) for i in range(N): yE[i] = fun_eval(xE[:, i]) inter_par = interpolation.Inter_par(method='NPS') inter_par, _ = interpolation.interpolateparameterization(xE, yE, inter_par) x = np.linspace(0, 1, 1000) y, yp = np.zeros(x.shape), np.zeros(x.shape) for i in range(x.shape[0]): y[i] = fun_eval(x[i]) yp[i] = interpolation.interpolate_val(x[i], inter_par) xi = np.copy(xE) 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) xe = np.copy(xi) xe_plot = np.zeros((tri.shape[0], 2000)) e_plot = np.zeros((tri.shape[0], 2000)) sc_plot = np.zeros((tri.shape[0], 2000)) n = xE.shape[0] K = 3 for ii in range(len(tri)): temp_x = np.copy(xi[:, tri[ii, :]]) x_ = np.linspace(temp_x[0, 0], temp_x[0, 1], 2000) temp_Sc = np.zeros(len(x_)) temp_e = np.zeros(len(x_)) p = np.zeros(len(x_)) R2, xc = Utils.circhyp(xi[:, tri[ii, :]], n) for jj in range(len(x_)): p[jj] = interpolation.interpolate_val(x_[jj], inter_par) temp_e[jj] = (R2 - np.linalg.norm(x_[jj] - xc)**2) temp_Sc[jj] = p[jj] - K * temp_e[jj] e_plot[ii, :] = temp_e xe_plot[ii, :] = x_ sc_plot[ii, :] = temp_Sc sc_min = np.min(sc_plot, axis=1) index_r = np.argmin(sc_min) index_c = np.argmin(sc_plot[index_r, :]) sc_min_x = xe_plot[index_r, index_c] sc_min = min(np.min(sc_plot, axis=1)) plt.figure() plt.plot(x, y, c='k') plt.plot(x, yp, c='b') for i in range(len(tri)): plt.plot(xe_plot[i, :], sc_plot[i, :], c='r') plt.plot(xe_plot[i, :], 3 * e_plot[i, :] - 2.3, c='g') plt.scatter(xE, yE, c='b', marker='s') plt.scatter(sc_min_x, sc_min, c='r', marker='s') plt.ylim(-2.5, 2) # plt.gca().axes.get_yaxis().set_visible(False) plt.show() return
def safe_continuous_constantK_search_1d_plot(xE, xU, fun_eval, safe_eval, L_safe, K, xc_min, Nm): ''' Given evaluated points set xE, and the objective function. Plot the interpolation, uncertainty function and continuous search function. :param xE: :param xU: :param fun_eval: :param safe_eval: :param L_safe: :param K: :param xc_min: :param Nm: :return: ''' N = xE.shape[1] yE = np.zeros(N) for i in range(N): yE[i] = fun_eval(xE[:, i]) inter_par = interpolation.Inter_par(method='NPS') inter_par, _ = interpolation.interpolateparameterization(xE, yE, inter_par) x = np.linspace(0, 1, 1000) y, yp = np.zeros(x.shape), np.zeros(x.shape) for i in range(x.shape[0]): y[i] = fun_eval(x[i]) yp[i] = interpolation.interpolate_val(x[i], inter_par) xi = np.hstack((xE, xU)) 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) xe_plot = np.zeros((tri.shape[0], 2000)) e_plot = np.zeros((tri.shape[0], 2000)) sc_plot = np.zeros((tri.shape[0], 2000)) n = xE.shape[0] for ii in range(len(tri)): temp_x = np.copy(xi[:, tri[ii, :]]) simplex = xi[:, tri[ii, :]] # Determine if the boundary corner exists or not in simplex exist = 0 for i in range(simplex.shape[1]): vertice = simplex[:, i].reshape(-1, 1) val, _, _ = Utils.mindis(vertice, xE) if val == 0: pass else: exist = 1 break x_ = np.linspace(temp_x[0, 0], temp_x[0, 1], 2000) temp_Sc = np.zeros(len(x_)) temp_e = np.zeros(len(x_)) p = np.zeros(len(x_)) R2, xc = Utils.circhyp(xi[:, tri[ii, :]], n) for jj in range(len(x_)): p[jj] = interpolation.interpolate_val(x_[jj], inter_par) if exist == 0: temp_e[jj] = (R2 - np.linalg.norm(x_[jj] - xc)**2) else: val, _, _ = Utils.mindis(x_[jj], xE) temp_e[jj] = val**(2) # val, idx, vertex = Utils.mindis(x_[jj], xE) # c = 0.1 # temp_e[jj] = (val + c) ** (1/2) - c ** (1/2) temp_Sc[jj] = p[jj] - K * temp_e[jj] e_plot[ii, :] = temp_e xe_plot[ii, :] = x_ sc_plot[ii, :] = temp_Sc # The minimizer of continuous search must be subject to safe constraints. # sc_min = np.min(sc_plot, axis=1) # index_r = np.argmin(sc_min) # index_c = np.argmin(sc_plot[index_r, :]) # sc_min_x = xe_plot[index_r, index_c] # sc_min = min(np.min(sc_plot, axis=1)) safe_plot = {} ## plot the safe region for ii in range(xE.shape[1]): y_safe = safe_eval(xE[:, ii]) safe_index = [] y_safe_plot = [] safe_eval_lip = lambda x: y_safe - L_safe * np.sqrt( np.dot((x - xE[:, ii]).T, x - xE[:, ii])) for i in range(x.shape[0]): safe_val = safe_eval_lip(x[i]) y_safe_plot.append(safe_val[0]) if safe_val > 0: safe_index.append(i) name = str(ii) safe_plot[name] = [safe_index, y_safe_plot] # ================== First plot ================= fig = plt.figure() plt.subplot(2, 1, 1) # plot the essentials for DeltaDOGS plt.plot(x, y, c='k') plt.plot(x, yp, c='b') for i in range(len(tri)): if i == 0 or i == len(tri) - 1: amplify_factor = 3 else: amplify_factor = 50 plt.plot(xe_plot[i, :], sc_plot[i, :], c='r') plt.plot(xe_plot[i, :], amplify_factor * e_plot[i, :] - 5.5, c='g') plt.scatter(xE, yE, c='b', marker='s') yc_min = sc_plot.flat[np.abs(xe_plot - xc_min).argmin()] plt.scatter(xc_min, yc_min, c='r', marker='^') # plot the safe region in cyan xlow, xupp = safe_region_plot(x, safe_plot) y_vertical = np.linspace(-2, 2, 100) xlow_y_vertical = xlow * np.ones(100) xupp_y_vertical = xupp * np.ones(100) plt.plot(xlow_y_vertical, y_vertical, color='cyan', linestyle='--') plt.plot(xupp_y_vertical, y_vertical, color='cyan', linestyle='--') plt.ylim(-6.5, 3.5) plt.gca().axes.get_yaxis().set_visible(False) # ================== Second plot ================= plt.subplot(2, 1, 2) y_safe_all = np.zeros(x.shape) for i in range(x.shape[0]): y_safe_all[i] = safe_eval(x[i]) plt.plot(x, y_safe_all) zero_indicator = np.zeros(x.shape) plt.plot(x, zero_indicator, c='k') x_scatter = np.hstack((xE, xc_min)) y_scatter = np.zeros(x_scatter.shape[1]) for i in range(x_scatter.shape[1]): ind = np.argmin(np.abs(x_scatter[:, i] - x)) y_scatter[i] = y_safe_all[ind] plt.scatter(x_scatter[:, :-1][0], y_scatter[:-1], c='b', marker='s') plt.scatter(x_scatter[:, -1], y_scatter[-1], c='r', marker='^') # plot the safe region xlow, xupp = safe_region_plot(x, safe_plot) low_idx = np.argmin(np.abs(xlow - x)) upp_idx = np.argmin(np.abs(xupp - x)) ylow_vertical = np.linspace(y_safe_all[low_idx], 2, 100) yupp_vertical = np.linspace(y_safe_all[upp_idx], 2, 100) xlow_y_vertical = xlow * np.ones(100) xupp_y_vertical = xupp * np.ones(100) plt.plot(xlow_y_vertical, ylow_vertical, color='cyan', linestyle='--') plt.plot(xupp_y_vertical, yupp_vertical, color='cyan', linestyle='--') plt.ylim(-1, 2.2) plt.gca().axes.get_yaxis().set_visible(False) # plt.show() current_path = os.path.dirname( os.path.abspath(inspect.getfile(inspect.currentframe()))) plot_folder = current_path[:-5] + "/plot/DDOGS/0" num_iter = xE.shape[1] - 1 + math.log(Nm / 8, 2) plt.savefig(plot_folder + '/pic' + str(int(num_iter)) + '.png', format='png', dpi=250) plt.close(fig) return
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
def tringulation_search_bound(inter_par, xi, y0, K0, ind_min): inf = 1e+20 n = xi.shape[0] xm, ym = interpolation.inter_min(xi[:, ind_min], inter_par) sc_min = inf # cse=1 if ym > y0: ym = inf # cse =2 # construct Deluanay tringulation 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 = 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 != np.inf: if R2 < inf: # initialze 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 # Global one if np.min(Sc) < 0: func = 'p' # The minimum of Sc is negative, minimize p(x) instead. Scp = np.zeros(tri.shape[0]) Scpl = 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) if np.sum(ind_min == tri[ii, :]): Scpl[ii] = np.copy(Scp[ii]) else: Scpl[ii] = inf else: Scpl[ii] = inf Scp[ii] = inf # Globally minimize p(x) ind = np.argmin(Scp) x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1)) simplex_bnds = Utils.search_bounds(xi[:, tri[ind, :]]) xm, ym = AdaptiveK_Search_p(x, inter_par, simplex_bnds) # Locally minimize p(x) ind = np.argmin(Scpl) x = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1)) simplex_bnds = Utils.search_bounds(xi[:, tri[ind, :]]) xml, yml = AdaptiveK_Search_p(x, inter_par, simplex_bnds) else: func = 'sc' # Minimize sc(x). # 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 = np.dot(xi[:, tri[ind, :]], np.ones([n + 1, 1]) / (n + 1)) simplex_bnds = Utils.search_bounds(xi[:, tri[ind, :]]) xm, ym = Adaptive_K_Search(x, inter_par, xc, R2, y0, K0, simplex_bnds) # 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)) simplex_bnds = Utils.search_bounds(xi[:, tri[ind, :]]) xml, yml = Adaptive_K_Search(x, inter_par, xc, R2, y0, K0, simplex_bnds) if yml < ym: xm = np.copy(xml) ym = np.copy(yml) result = 'local' else: result = 'glob' xm = xm.reshape(-1, 1) ym = ym[0, 0] return xm, ym, result, func
def vertex_find(A, b, lb, ub): ''' Find the vertices of a simplex; Ax<b: Linear constraints; lb<x<ub: actual constraints; Attension: Do not try to include lb&ub inside A&b matrix. Example: A = np.array([[-1, 1],[1, -1]]) b = np.array([[0.5], [0.5]]) lb = np.zeros((2, 1)) ub = np.ones((2, 1)) :param A: :param b: :param lb: :param ub: :return: ''' if A.shape[0] == 0 and b.shape[0] == 0: if len(lb) != 0 and len(ub) != 0: Vertex = Utils.bounds(lb, ub, len(lb)) else: Vertex = [] raise ValueError('All inputs A, b, lb and ub have dimension 0.') else: if len(lb) != 0: Vertex = np.matrix([[], []]) m = A.shape[0] n = A.shape[1] if m == 0: Vertex = Utils.bounds(lb, ub, len(lb)) else: for r in range(min(n, m) + 1): from itertools import combinations nlist = np.arange(1, m + 1) C = np.array([list(c) for c in combinations(nlist, r)]) nlist2 = np.arange(1, n + 1) D = np.array([list(d) for d in combinations(nlist2, n - r)]) if r == 0: F = Utils.bounds(lb, ub, n) for kk in range(F.shape[1]): x = np.copy(F[:, kk]).reshape(-1, 1) if np.all(np.dot(A, x) - b < 0): Vertex = np.column_stack((Vertex, x)) else: for ii in range(len(C)): index_A = np.copy(C[ii]) v1 = np.arange(1, m + 1) index_A_C = np.setdiff1d(v1, index_A) A1 = np.copy(A[index_A - 1, :]) b1 = np.copy(b[index_A - 1]) for jj in range(len(D)): index_B = np.copy(D[jj]) v2 = np.arange(1, n + 1) index_B_C = np.setdiff1d(v2, index_B) if len(index_B) != 0 and len(index_B_C) != 0: F = Utils.bounds(lb[index_B - 1], ub[index_B - 1], n - r) A11 = np.copy(A1[:, index_B - 1]) A12 = np.copy(A1[:, index_B_C - 1]) for kk in range(F.shape[1]): A11 = np.copy(A1[:, index_B - 1]) A12 = np.copy(A1[:, index_B_C - 1]) xd = np.linalg.lstsq(A12, b1 - np.dot(A11, F[:, kk].reshape(-1, 1)), rcond=None)[0] x = np.zeros((n, 1)) x[index_B - 1] = np.copy(F[:, kk]) x[index_B_C - 1] = np.copy(xd) if r == m or (np.dot(A[index_A_C - 1, :], x) - b[index_A_C - 1]).min() < 0: if (x - ub).max() < 1e-6 and (x - lb).min() > -1e-6 and Utils.mindis(x, Vertex)[0] > 1e-6: Vertex = np.column_stack((Vertex, x)) else: m = A.shape[0] n = A.shape[1] from itertools import combinations nlist = np.arange(1, m + 1) C = np.array([list(c) for c in combinations(nlist, n)]) Vertex = np.empty(shape=[n, 0]) for ii in range(len(C)): index_A = np.copy(C[ii]) v1 = np.arange(1, m + 1) index_A_C = np.setdiff1d(v1, index_A) A1 = np.copy(A[index_A - 1, :]) b1 = np.copy(b[index_A - 1]) A2 = np.copy(A[index_A_C - 1]) b2 = np.copy(b[index_A_C - 1]) x = np.linalg.lstsq(A1, b1, rcond=None)[0] if (np.dot(A2, x) - b2).max() < 1e-6: Vertex = np.column_stack((Vertex, x)) # cant plot Vertex directly. must transform it into np.array. return np.array(Vertex)
def triangulation_search_bound_snopt(inter_par, xi, K, ind_min, y_safe, L_safe): # reddir is a vector inf = 1e+20 n = xi.shape[0] # The dimension of the reduced model. xE = inter_par.xi # 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)) exist = unevaluated_vertices_identification(xE, xi[:, tri[ii, :]]) if exist == 0: Sc[ii] = interpolation.interpolate_val( x, inter_par) - K * (R2 - np.linalg.norm(x - xc)**2) else: val, idx, x_nn = Utils.mindis(x, xE) Sc[ii] = interpolation.interpolate_val(x, inter_par) - K * val**2 # discrete min # val, idx, vertex = Utils.mindis(x, xE) # c = 0.1 # e = (val + c) ** (1/2) - c ** (1/2) # Sc[ii] = interpolation.interpolate_val(x, inter_par) - K * e if np.sum(ind_min == tri[ii, :]): Scl[ii] = np.copy(Sc[ii]) else: Scl[ii] = inf else: Scl[ii] = inf Sc[ii] = inf # Global one, the minimum of Sc has the minimum value of all circumcenters. ind = np.argmin(Sc) xm, ym = constantk_search_snopt_min(xi[:, tri[ind, :]], inter_par, K, y_safe, L_safe) # Local one ind = np.argmin(Scl) xml, yml = constantk_search_snopt_min(xi[:, tri[ind, :]], inter_par, K, y_safe, L_safe) if yml < ym: xm = np.copy(xml) ym = np.copy(yml) result = 'local' else: result = 'glob' return xm, ym, result
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