def make_grad_convolve_0(ans, in0, in1, mode='full'): if mode == 'full': return lambda g: convolve(g, flipud(in1), mode='valid') elif mode == 'same': return lambda g: flipud(convolve(flipud(g), in1, mode='same')) elif mode == 'valid': return lambda g: convolve(g, flipud(in1), mode='full') else: raise Exception("Unrecognized mode {0}".format(mode))
def make_grad_convolve_1(ans, in0, in1, mode='full'): if mode == 'full': return lambda g: convolve(g, flipud(in0), mode='valid') elif mode == 'same': idxs = get_same_slice(in0.shape[0], in1.shape[0]) return lambda g: convolve(g, flipud(in0), mode='full')[idxs] elif mode == 'valid': return lambda g: convolve(flipud(in0), g, mode='valid') else: raise Exception("Unrecognized mode {0}".format(mode))
def get_sharp_TE_airfoil(self): # Returns a version of the airfoil with a sharp trailing edge. upper_original_coors = self.upper_coordinates() # Note: includes leading edge point, be careful about duplicates lower_original_coors = self.lower_coordinates() # Note: includes leading edge point, be careful about duplicates # Find data about the TE # Get the scale factor x_mcl = self.mcl_coordinates[:,0] x_max = np.max(x_mcl) x_min = np.min(x_mcl) scale_factor = (x_mcl - x_min) / (x_max - x_min) # linear contraction # Do the contraction upper_minus_mcl_adjusted = self.upper_minus_mcl - self.upper_minus_mcl[-1,:] * np.expand_dims(scale_factor,1) # Recreate coordinates upper_coordinates_adjusted = np.flipud(self.mcl_coordinates + upper_minus_mcl_adjusted) lower_coordinates_adjusted = self.mcl_coordinates - upper_minus_mcl_adjusted coordinates = np.vstack(( upper_coordinates_adjusted[:-1,:], lower_coordinates_adjusted )) # Make a new airfoil with the coordinates name = self.name + ", with sharp TE" new_airfoil = Airfoil(name=name, coordinates=coordinates, repanel=False) return new_airfoil
def populate_mcl_coordinates(self): # Populates self.mcl_coordinates, a Nx2 list of the airfoil's mean camber line coordinates. # Ordered from the leading edge to the trailing edge. # # Also populates self.upper_minus_mcl and self.lower_minus mcl, which are Nx2 lists of the vectors needed to # go from the mcl coordinates to the upper and lower surfaces, respectively. Both listed leading-edge to trailing-edge. # # Also populates self.thickness, a Nx2 list of the thicknesses at the mcl_coordinates x-points. upper = np.flipud(self.upper_coordinates()) lower = self.lower_coordinates() mcl_coordinates = (upper + lower) / 2 self.mcl_coordinates = mcl_coordinates self.upper_minus_mcl = upper - self.mcl_coordinates # self.lower_minus_mcl = -self.upper_minus_mcl thickness = np.sqrt( np.sum( np.power(self.upper_minus_mcl, 2), axis = 1 ) ) * 2 self.thickness = np.column_stack((self.mcl_coordinates[:,0],thickness))
def draw_2d(g,steplength,max_steps,w_inits,num_samples,**kwargs): wmin = -3.1 wmax = 3.1 if 'wmin' in kwargs: wmin = kwargs['wmin'] if 'wmax' in kwargs: wmax = kwargs['wmax'] # initialize figure fig = plt.figure(figsize = (9,4)) artist = fig # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 3, width_ratios=[1,4,1]) ax1 = plt.subplot(gs[0]); ax1.axis('off') ax3 = plt.subplot(gs[2]); ax3.axis('off') ax = plt.subplot(gs[1]); # generate function for plotting on each slide w_plot = np.linspace(wmin,wmax,500) g_plot = [g(s) for s in w_plot] g_range = max(g_plot) - min(g_plot) ggap = g_range*0.1 width = 30 #### loop over all initializations, run gradient descent algorithm for each and plot results ### for j in range(len(w_inits)): # get next initialization w_init = w_inits[j] # run grad descent for this init func = g pt_history,eval_history = random_local_search_2d(func,w_init,max_steps,num_samples,steplength) # colors for points --> green as the algorithm begins, yellow as it converges, red at final point s = np.linspace(0,1,len(pt_history[:round(len(eval_history)/2)])) s.shape = (len(s),1) t = np.ones(len(eval_history[round(len(eval_history)/2):])) t.shape = (len(t),1) s = np.vstack((s,t)) colorspec = [] colorspec = np.concatenate((s,np.flipud(s)),1) colorspec = np.concatenate((colorspec,np.zeros((len(s),1))),1) # plot function, axes lines ax.plot(w_plot,g_plot,color = 'k',zorder = 2) # plot function ax.axhline(y=0, color='k',zorder = 1,linewidth = 0.25) ax.axvline(x=0, color='k',zorder = 1,linewidth = 0.25) ax.set_xlabel(r'$w$',fontsize = 13) ax.set_ylabel(r'$g(w)$',fontsize = 13,rotation = 0,labelpad = 25) ### plot all local search points ### for k in range(len(eval_history)): # pick out current weight and function value from history, then plot w_val = pt_history[k] g_val = eval_history[k] ax.scatter(w_val,g_val,s = 90,c = colorspec[k],edgecolor = 'k',linewidth = 0.5*((1/(float(k) + 1)))**(0.4),zorder = 3,marker = 'X') # evaluation on function ax.scatter(w_val,0,s = 90,facecolor = colorspec[k],edgecolor = 'k',linewidth = 0.5*((1/(float(k) + 1)))**(0.4), zorder = 3)
def transpose_lower_banded_matrix(Lab): # This is painful Uab = np.flipud(Lab) u = Uab.shape[0] - 1 for i in range(1, u + 1): Uab[-(i + 1), i:] = Uab[-(i + 1), :-i] Uab[-(i + 1), :i] = 0 return Uab
def prox_sdss_symmetry(X, step): """SDSS/HSC symmetry operator This function uses the *minimum* of the two symmetric pixels in the update. """ Xs = np.fliplr(np.flipud(X)) X[:] = np.min([X, Xs], axis=0) return X
def fft_convolve2d(x, y): """ 2D convolution, using FFT""" fr = fft.fft2(x) fr2 = fft.fft2(np.flipud(np.fliplr(y))) m, n = fr.shape cc = np.real(fft.ifft2(fr * fr2)) cc = np.roll(cc, -int(m / 2) + 1, axis=0) cc = np.roll(cc, -int(n / 2) + 1, axis=1) return cc
def f_symmetry(dof, Mx, My, xsym, ysym, Nlayer=1): out = [] for i in range(Nlayer): df = np.reshape(dof[i * Mx * My:(i + 1) * Mx * My], (Mx, My)) if xsym == 1: df = np.hstack((df, np.fliplr(df))) if ysym == 1: df = np.vstack((df, np.flipud(df))) out.append(df.flatten()) return np.concatenate(np.array(out))
def prox_soft_symmetry(X, step, strength=1): """Soft version of symmetry Using a `sigma` that varies from 0 to 1, with 0 meaning no symmetry enforced at all and 1 being completely symmetric, the user can customize the level of symmetry required for a component """ Xs = np.fliplr(np.flipud(X)) X[:] = 0.5 * strength * (X + Xs) + (1 - strength) * X return X
def make_colorspec(self, w_hist): # make color range for path s = np.linspace(0, 1, len(w_hist[:round(len(w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(w_hist[round(len(w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) colorspec = [] colorspec = np.concatenate((s, np.flipud(s)), 1) colorspec = np.concatenate((colorspec, np.zeros((len(s), 1))), 1) return colorspec
def plotit(X, Y=None, clf=None, markers=('s', 'o'), hold=False, transform=None): """ Just a function for showing a data scatter plot and classification boundary of a classifier clf """ minx, maxx = np.min(X[:, 0]), np.max(X[:, 0]) miny, maxy = np.min(X[:, 1]), np.max(X[:, 1]) if clf is not None: npts = 100 x = np.linspace(minx, maxx, npts) y = np.linspace(miny, maxy, npts) t = np.array(list(itertools.product(x, y))) if transform is not None: t = transform(t) z = clf(t) z = np.reshape(z, (npts, npts)) extent = [minx, maxx, miny, maxy] plt.imshow(z, vmin=-2, vmax=+2) plt.contour(z, [-1, 0, 1], linewidths=[2], colors=('b', 'k', 'r'), extent=extent, label='f(x)=0') plt.imshow(np.flipud(z), extent=extent, cmap=plt.cm.Purples, vmin=-2, vmax=+2) plt.colorbar() plt.axis([minx, maxx, miny, maxy]) if Y is not None: plt.scatter(X[Y == 1, 0], X[Y == 1, 1], marker=markers[0], c='y', s=30) plt.scatter(X[Y == -1, 0], X[Y == -1, 1], marker=markers[1], c='c', s=30) plt.xlabel('$x_1$') plt.ylabel('$x_2$') else: plt.scatter(X[:, 0], X[:, 1], marker='.', c='k', s=5) if not hold: plt.grid() plt.show()
def add_control_surface(self, deflection=0., hinge_point=0.75): # Returns a version of the airfoil with a control surface added at a given point. # Inputs: # # deflection: the deflection angle, in degrees. Downwards-positive. # # hinge_point: the location of the hinge, as a fraction of chord. # Make the rotation matrix for the given angle. sintheta = np.sin(np.radians(-deflection)) costheta = np.cos(np.radians(-deflection)) rotation_matrix = np.array([[costheta, -sintheta], [sintheta, costheta]]) # Find the hinge point hinge_point = np.array( (hinge_point, self.get_camber_at_chord_fraction(hinge_point) )) # Make hinge_point a vector. # Split the airfoil into the sections before and after the hinge split_index = np.where( self.mcl_coordinates[:, 0] > hinge_point[0])[0][0] mcl_coordinates_before = self.mcl_coordinates[:split_index, :] mcl_coordinates_after = self.mcl_coordinates[split_index:, :] upper_minus_mcl_before = self.upper_minus_mcl[:split_index, :] upper_minus_mcl_after = self.upper_minus_mcl[split_index:, :] # Rotate the mean camber line (MCL) and "upper minus mcl" new_mcl_coordinates_after = np.transpose( rotation_matrix @ np.transpose(mcl_coordinates_after - hinge_point)) + hinge_point new_upper_minus_mcl_after = np.transpose( rotation_matrix @ np.transpose(upper_minus_mcl_after)) # Do blending # Assemble airfoil new_mcl_coordinates = np.vstack( (mcl_coordinates_before, new_mcl_coordinates_after)) new_upper_minus_mcl = np.vstack( (upper_minus_mcl_before, new_upper_minus_mcl_after)) upper_coordinates = np.flipud(new_mcl_coordinates + new_upper_minus_mcl) lower_coordinates = new_mcl_coordinates - new_upper_minus_mcl coordinates = np.vstack((upper_coordinates, lower_coordinates[1:, :])) new_airfoil = Airfoil(name=self.name + " flapped", coordinates=coordinates, repanel=False) return new_airfoil # TODO fix self-intersecting airfoils at high deflections
def animate(k): # clear the panels ax1.cla() ax2.cla() # print rendering update if np.mod(k + 1, 25) == 0: print('rendering animation frame ' + str(k + 1) + ' of ' + str(num_frames)) if k == num_frames - 1: print('animation rendering complete!') time.sleep(1.5) clear_output() if k > 0: # pull current tracer tracer = tracer_range[k - 1] tracer = np.array([float(tracer[0]), float(tracer[1])]) tracer.shape = (2, 1) g_tracer = func(tracer) ### draw 3d version ### for ax in [ax1, ax2]: # plot function plot_func(func, view, ax) if k > 0: # scatter anchor point ax.scatter(anchor[0], anchor[1], g_anchor, s=50, c='lime', edgecolor='k', linewidth=1) # plot hyperplane connecting the anchor to tracer secant(func, anchor, tracer, ax) # reset tracer tracer = np.flipud(tracer) return artist,
def fun(x): return to_scalar(np.flipud(x)) d_fun = lambda x : to_scalar(grad(fun)(x))
def animate_it(self, **kwargs): # get new initial point if desired if 'w_init' in kwargs: self.w_init = float(kwargs['w_init']) # take in user defined step length if 'alpha' in kwargs: self.alpha = float(kwargs['alpha']) # take in user defined maximum number of iterations if 'max_its' in kwargs: self.max_its = float(kwargs['max_its']) # viewing range wmax = 5 if 'wmax' in kwargs: wmax = kwargs['wmax'] # initialize figure fig = plt.figure(figsize=(10, 5)) artist = fig # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 3, width_ratios=[1, 5, 1]) ax1 = plt.subplot(gs[0]) ax1.axis('off') ax3 = plt.subplot(gs[2]) ax3.axis('off') # plot input function ax = plt.subplot(gs[1], aspect='equal') # generate function for plotting on each slide w_plot = np.linspace(-wmax, wmax, 1000) g_plot = self.g(w_plot) g_range = max(g_plot) - min(g_plot) ggap = g_range * 0.25 width = 30 # run gradient descent method self.w_hist = [] self.run_gradient_descent() # colors for points --> green as the algorithm begins, yellow as it converges, red at final point s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) self.colorspec = [] self.colorspec = np.concatenate((s, np.flipud(s)), 1) self.colorspec = np.concatenate((self.colorspec, np.zeros( (len(s), 1))), 1) # animation sub-function print('starting animation rendering...') num_frames = len(self.w_hist) def animate(k): ax.cla() # print rendering update if np.mod(k + 1, 25) == 0: print('rendering animation frame ' + str(k + 1) + ' of ' + str(num_frames)) if k == num_frames - 1: print('animation rendering complete!') time.sleep(1.5) clear_output() # plot function ax.plot(w_plot, g_plot, color='k', zorder=2) # plot function # plot initial point and evaluation if k == 0: w_val = self.w_init g_val = self.g(w_val) ax.scatter(w_val, g_val, s=100, c='r', edgecolor='k', linewidth=0.7, zorder=3) # plot point of tangency ax.scatter(w_val, 0, s=100, c='r', edgecolor='k', linewidth=0.7, zorder=3, marker='X') # draw dashed line connecting w axis to point on cost function s = np.linspace(0, g_val) o = np.ones((len(s))) ax.plot(o * w_val, s, 'k--', linewidth=1) # plot all input/output pairs generated by algorithm thus far if k > 0 and k < len(self.w_hist) + 1: # plot all points up to this point for j in range(min(k, len(self.w_hist))): alpha_val = 1 if j < k - 1: alpha_val = 0.1 # get next value of weight, function and gradient evaluation w_val = self.w_hist[j] g_val = self.g(w_val) grad_val = float(self.grad(w_val)) # plot current point ax.scatter(w_val, g_val, s=90, c='r', edgecolor='k', linewidth=0.7, zorder=3, alpha=alpha_val) # plot point of tangency ax.scatter(w_val, 0, s=90, facecolor='r', marker='X', edgecolor='k', linewidth=0.7, zorder=3, alpha=alpha_val) #### plot linear surrogate #### # determine width to plot the approximation -- so its length == width defined above div = float(1 + grad_val**2) w1 = w_val - math.sqrt(width / div) w2 = w_val + math.sqrt(width / div) # use point-slope form of line to plot wrange = np.linspace(w1, w2, 100) h = g_val + grad_val * (wrange - w_val) # plot tangent line ax.plot(wrange, h, color=self.colors[0], linewidth=2, zorder=1, alpha=alpha_val) # plot approx # plot tangent point ax.scatter(w_val, g_val, s=100, c='r', edgecolor='k', linewidth=0.7, zorder=3, alpha=alpha_val) # plot point of tangency # plot next point learned from surrogate # create next point information w_zero = w_val - self.alpha * grad_val g_zero = self.g(w_zero) h_zero = g_val + grad_val * (w_zero - w_val) # draw intersection at zero and associated point on cost function you hop back too ax.scatter(w_zero, h_zero, s=100, c=self.colors[0], edgecolor='k', linewidth=0.7, zorder=3, marker='X', alpha=alpha_val) ax.scatter(w_zero, 0, s=100, c='r', edgecolor='k', linewidth=0.7, zorder=3, marker='X', alpha=alpha_val) ax.scatter(w_zero, g_zero, s=100, c='r', edgecolor='k', linewidth=0.7, zorder=3, alpha=alpha_val) # plot point of tangency ### draw simple quadratic surrogate ### # decide on range for quadratic so it looks nice quad_term = 1 / float(2 * self.alpha) a = 0.5 * quad_term b = grad_val - 2 * 0.5 * quad_term * w_val c = 0.5 * quad_term * w_val**2 - grad_val * w_val - width # solve for zero points w1 = (-b + math.sqrt(b**2 - 4 * a * c)) / float(2 * a + 0.00001) w2 = (-b - math.sqrt(b**2 - 4 * a * c)) / float(2 * a + 0.00001) wrange = np.linspace(w1, w2, 100) # create simple quadratic surrogate h = g_val + grad_val * (wrange - w_val) + quad_term * ( wrange - w_val)**2 # plot simple quadratic surrogate ax.plot(wrange, h, color=self.colors[1], linewidth=2, zorder=1, alpha=alpha_val) # plot approx # plot point of intersection - next gradient descent step - on simple quadratic surrogate h_zero_2 = g_val + grad_val * (w_zero - w_val) + 1 / float( 2 * self.alpha) * (w_zero - w_val)**2 ax.scatter(w_zero, h_zero_2, s=100, c=self.colors[1], edgecolor='k', linewidth=0.7, zorder=3, marker='X', alpha=alpha_val) # draw dashed line connecting w axis to point on cost function s = np.linspace(0, g_val) o = np.ones((len(s))) ax.plot(o * w_val, s, 'k--', linewidth=1, alpha=alpha_val) vals = [0, h_zero, h_zero_2, g_zero] vals = np.sort(vals) s = np.linspace(vals[0], vals[3]) o = np.ones((len(s))) w_val = self.w_hist[j + 1] ax.plot(o * w_val, s, 'k--', linewidth=1, alpha=alpha_val) # fix viewing limits ax.set_xlim([-wmax, wmax]) ax.set_ylim([min(g_plot) - ggap, max(g_plot) + ggap]) ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) ax.set_xlabel(r'$w$', fontsize=12) ax.set_ylabel(r'$g(w)$', fontsize=12, rotation=0, labelpad=20) return artist, anim = animation.FuncAnimation(fig, animate, frames=num_frames, interval=num_frames, blit=True) return (anim)
def draw_panel(self, ax, title, **kwargs): # set viewing limits on contour plot xvals = [self.w_hist[s][0] for s in range(len(self.w_hist))] xvals.append(self.w_init[0]) yvals = [self.w_hist[s][1] for s in range(len(self.w_hist))] yvals.append(self.w_init[1]) xmax = max(xvals) xmin = min(xvals) xgap = (xmax - xmin) * 0.1 ymax = max(yvals) ymin = min(yvals) ygap = (ymax - ymin) * 0.1 xmin -= xgap xmax += xgap ymin -= ygap ymax += ygap if 'xmin' in kwargs: xmin = kwargs['xmin'] if 'xmax' in kwargs: xmax = kwargs['xmax'] if 'ymin' in kwargs: ymin = kwargs['ymin'] if 'ymax' in kwargs: ymax = kwargs['ymax'] axes = False if 'axes' in kwargs: axes = kwargs['ymax'] pts = False if 'pts' in kwargs: pts = kwargs['pts'] pts = False if 'pts' in kwargs: pts = kwargs['pts'] linewidth = 2.5 if 'linewidth' in kwargs: linewidth = kwargs['linewidth'] #### define input space for function and evaluate #### w1 = np.linspace(xmin, xmax, 400) w2 = np.linspace(ymin, ymax, 400) w1_vals, w2_vals = np.meshgrid(w1, w2) w1_vals.shape = (len(w1)**2, 1) w2_vals.shape = (len(w2)**2, 1) h = np.concatenate((w1_vals, w2_vals), axis=1) func_vals = np.asarray([self.g(s) for s in h]) w1_vals.shape = (len(w1), len(w1)) w2_vals.shape = (len(w2), len(w2)) func_vals.shape = (len(w1), len(w2)) ### make contour right plot - as well as horizontal and vertical axes ### # set level ridges num_contours = kwargs['num_contours'] levelmin = min(func_vals.flatten()) levelmax = max(func_vals.flatten()) cutoff = 0.5 cutoff = (levelmax - levelmin) * cutoff numper = 3 levels1 = np.linspace(cutoff, levelmax, numper) num_contours -= numper levels2 = np.linspace(levelmin, cutoff, min(num_contours, numper)) levels = np.unique(np.append(levels1, levels2)) num_contours -= numper while num_contours > 0: cutoff = levels[1] levels2 = np.linspace(levelmin, cutoff, min(num_contours, numper)) levels = np.unique(np.append(levels2, levels)) num_contours -= numper a = ax.contour(w1_vals, w2_vals, func_vals, levels=levels, colors='k') ax.contourf(w1_vals, w2_vals, func_vals, levels=levels, cmap='Blues') if axes == True: ax.axhline(linestyle='--', color='k', linewidth=1) ax.axvline(linestyle='--', color='k', linewidth=1) # colors for points s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) colorspec = [] colorspec = np.concatenate((s, np.flipud(s)), 1) colorspec = np.concatenate((colorspec, np.zeros((len(s), 1))), 1) ### plot function decrease plot in right panel for j in range(len(self.w_hist)): w_val = self.w_hist[j] g_val = self.g(w_val) # plot in left panel if pts == 'True': ax.scatter(w_val[0], w_val[1], s=30, c=colorspec[j], edgecolor='k', linewidth=1.5 * math.sqrt((1 / (float(j) + 1))), zorder=3) # plot connector between points for visualization purposes if j > 0: w_old = self.w_hist[j - 1] w_new = self.w_hist[j] ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]], color=colorspec[j], linewidth=linewidth, alpha=1, zorder=2) # plot approx ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]], color='k', linewidth=linewidth + 0.4, alpha=1, zorder=1) # plot approx # clean panel ax.set_title(title, fontsize=12) ax.set_xlabel('$w_1$', fontsize=12) ax.set_ylabel('$w_2$', fontsize=12, rotation=0) ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) ax.axvline(x=0, color='k', zorder=0, linewidth=0.5) ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax])
def draw_it_newtons(self,**args): # user-defined input point if 'w_init' in args: self.w_init = float(args['w_init']) # user-defined max_its if 'max_its' in args: self.max_its = float(args['max_its']) # initialize figure fig = plt.figure(figsize = (12,4)) artist = fig # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 2, width_ratios=[1,1]) ax1 = plt.subplot(gs[0]); ax2 = plt.subplot(gs[1]); artist = fig # generate function for plotting on each slide w_plot = np.linspace(-3.1,3.1,200) g_plot = self.g(w_plot) grad_plot = [self.grad(v) for v in w_plot] g_range = max(g_plot) - min(g_plot) ggap = g_range*0.1 w_vals = np.linspace(-2.5,2.5,50) # run newtons method self.w_hist = [] self.run_newtons_method() # colors for points s = np.linspace(0,1,len(self.w_hist[:round(len(self.w_hist)/2)])) s.shape = (len(s),1) t = np.ones(len(self.w_hist[round(len(self.w_hist)/2):])) t.shape = (len(t),1) s = np.vstack((s,t)) self.colorspec = [] self.colorspec = np.concatenate((s,np.flipud(s)),1) self.colorspec = np.concatenate((self.colorspec,np.zeros((len(s),1))),1) # animation sub-function print ('beginning animation rendering...') def animate(k): ax1.cla() ax2.cla() # print rendering update if k == len(self.w_hist): print ('animation rendering complete!') time.sleep(1.5) clear_output() # plot functions ax1.plot(w_plot,g_plot,color = 'k',zorder = 0) # plot function ax2.plot(w_plot,grad_plot,color = 'k',zorder = 2) # plot function # plot initial point and evaluation if k == 0: w_val = self.w_init g_val = self.g(w_val) ax1.scatter(w_val,g_val,s = 120,c = 'm',edgecolor = 'k',linewidth = 0.7,zorder = 2) # plot point of tangency ax1.scatter(w_val,0,s = 120,c = 'm',edgecolor = 'k',linewidth = 0.7, zorder = 2, marker = 'X') g_val = self.grad(w_val) ax2.scatter(w_val,g_val,s = 120,c = 'm',edgecolor = 'k',linewidth = 0.7,zorder = 2) # plot point of tangency ax2.scatter(w_val,0,s = 120,c = 'm',edgecolor = 'k',linewidth = 0.7, zorder = 2, marker = 'X') # draw functions first, then start animating process if k > 0: #### cost function (minimizing) view #### w_val = self.w_hist[k-1] # plug in value into func and derivative g_val = self.g(w_val) g_grad_val = self.grad(w_val) g_hess_val = self.hess(w_val) # determine width of plotting area for second order approximator width = 5 if g_hess_val < 0: width = - width # setup quadratic formula params a = 0.5*g_hess_val b = g_grad_val - 2*0.5*g_hess_val*w_val c = 0.5*g_hess_val*w_val**2 - g_grad_val*w_val - width # solve for zero points w1 = (-b + math.sqrt(b**2 - 4*a*c))/float(2*a + 0.00001) w2 = (-b - math.sqrt(b**2 - 4*a*c))/float(2*a + 0.00001) # compute second order approximation wrange = np.linspace(w1,w2, 100) h = g_val + g_grad_val*(wrange - w_val) + 0.5*g_hess_val*(wrange - w_val)**2 # create next point information w_zero = w_val - g_grad_val/(g_hess_val + 10**-5) g_zero = self.g(w_zero) h_zero = g_val + g_grad_val*(w_zero - w_val) + 0.5*g_hess_val*(w_zero - w_val)**2 # draw dashed linen connecting the three vals = [0,h_zero,g_zero] vals = np.sort(vals) s = np.linspace(vals[0],vals[2]) o = np.ones((len(s))) # plot all ax1.plot(wrange,h,color = 'b',linewidth = 2,zorder = 1) # plot approx # plot tangent point ax1.scatter(w_val, g_val, s = 120, c='m',edgecolor = 'k',linewidth = 0.7,zorder = 3) # created dashed linen connecting the three ax1.plot(o*w_zero,s,'k--',linewidth=1) # draw intersection at zero and associated point on cost function you hop back too ax1.scatter(w_zero,h_zero,s = 120,c = 'k', zorder = 2) ax1.scatter(w_zero,g_zero,s = 120,c = self.colorspec[k-1],edgecolor = 'k',linewidth = 0.7,zorder = 3) # plot point of tangency ax1.scatter(w_zero,0,s = 120,facecolor = self.colorspec[k-1],marker = 'X',edgecolor = 'k',linewidth = 0.7, zorder = 2) #### derivative (zero-crossing) view #### # grab historical weight, compute function and derivative evaluations g_val = float(self.grad(w_val)) grad_val = float(self.hess(w_val)) h = g_val + grad_val*(wrange - w_val) # draw points w_zero = -g_val/grad_val + w_val g_zero = self.grad(w_zero) s = np.linspace(0,g_zero) o = np.ones((len(s))) # plot tangent line ax2.plot(wrange,h,color = 'b',linewidth = 2,zorder = 1) # plot approx # plot tangent point ax2.scatter(w_val, g_val, s = 120, c='m',edgecolor = 'k',linewidth = 0.7,zorder = 3) # draw dashed lines to highlight zero crossing point ax2.plot(o*w_zero,s,'k--',linewidth=1) # draw intersection at zero and associated point on cost function you hop back too ax2.scatter(w_zero,g_zero,s = 120,c = self.colorspec[k-1],edgecolor = 'k',linewidth = 0.7,zorder = 3) # plot point of tangency ax2.scatter(w_zero,0,s = 120,facecolor = self.colorspec[k-1],marker = 'X',edgecolor = 'k',linewidth = 0.7, zorder = 2) # fix viewing limits ax1.set_xlim([-3,3]) ax1.set_ylim([min(g_plot) - ggap,max(g_plot) + ggap]) # fix viewing limits ax2.set_xlim([-3,3]) ax2.set_ylim([min(g_plot) - ggap,max(g_plot) + ggap]) # set titles ax1.set_title('cost function (minimizing) view',fontsize = 15) ax2.set_title('gradient (zero-crossing) view',fontsize = 15) # draw axes ax1.axhline(y=0, color='k',zorder = 0,linewidth = 0.5) ax2.axhline(y=0, color='k',zorder = 0,linewidth = 0.5) return artist, anim = animation.FuncAnimation(fig, animate,frames=len(self.w_hist)+1, interval=len(self.w_hist)+1, blit=True) return(anim)
def fun(x): return to_scalar(np.flipud(x))
def draw_it_secant(self, **args): if 'w_init' in args: self.w_init = float(args['w_init']) # initialize figure fig = plt.figure(figsize=(6, 6)) artist = fig ax = fig.add_subplot(111) # generate function for plotting on each slide w_plot = np.linspace(-3.1, 3.1, 200) g_plot = self.g(w_plot) g_range = max(g_plot) - min(g_plot) ggap = g_range * 0.1 width = 30 # run newtons method self.w_hist = [] self.run_secant() # colors for points s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) self.colorspec = [] self.colorspec = np.concatenate((s, np.flipud(s)), 1) self.colorspec = np.concatenate((self.colorspec, np.zeros( (len(s), 1))), 1) # animation sub-function print('beginning animation rendering...') def animate(t): ax.cla() k = math.floor((t + 1) / float(2)) # print rendering update if k == 2 * len(self.w_hist) - 1: print('animation rendering complete!') time.sleep(1.5) clear_output() # plot function ax.plot(w_plot, g_plot, color='k', zorder=2) # plot function # plot initial point and evaluation if k == 0: w_val = self.w_init g_val = self.g(w_val) ax.scatter(w_val, g_val, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=2) # plot point of tangency ax.scatter(w_val, 0, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=2, marker='X') # plot all input/output pairs generated by algorithm thus far if k > 0: # plot all points up to this point for j in range(min(k - 1, len(self.w_hist))): w_val = self.w_hist[j] g_val = self.g(w_val) ax.scatter(w_val, g_val, s=90, c=self.colorspec[j], edgecolor='k', linewidth=0.7, zorder=3) # plot point of tangency ax.scatter(w_val, 0, s=90, facecolor=self.colorspec[j], marker='X', edgecolor='k', linewidth=0.7, zorder=2) # plot surrogate function and travel-to point if k > 0 and k < len(self.w_hist): # grab historical weights, form associated secant line w2 = self.w_hist[k - 1] w1 = self.w_hist[k] g2 = self.g(w2) g1 = self.g(w1) m = (g1 - g2) / (w1 - w2) # determine width to plot the approximation -- so its length == width defined above div = float(1 + m**2) wa = w1 - math.sqrt(width / div) wb = w1 + math.sqrt(width / div) # use point-slope form of line to plot wrange = np.linspace(wa, wb, 100) h = g1 + m * (wrange - w1) # plot secant line ax.plot(wrange, h, color='b', linewidth=2, zorder=1) # plot approx # plot intersection points ax.scatter(w2, g2, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3) ax.scatter(w1, g1, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3) # plot next point learned from surrogate if np.mod(t, 2) == 0: # draw dashed lines to highlight zero crossing point w_zero = -g1 / m + w1 g_zero = self.g(w_zero) s = np.linspace(0, g_zero) o = np.ones((len(s))) ax.plot(o * w_zero, s, 'k--', linewidth=1, zorder=1) # draw zero intersection, and associated point on cost function you hop back too ax.scatter(w_zero, g_zero, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3) # plot point of tangency ax.scatter(w_zero, 0, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3, marker='X') # fix viewing limits ax.set_xlim([-3.1, 3.1]) ax.set_ylim([min(g_plot) - ggap, max(g_plot) + ggap]) # draw axes # ax.grid(True, which='both') ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) # ax.axvline(x=0, color='k',linewidth = 0.5) return artist, anim = animation.FuncAnimation(fig, animate, frames=2 * len(self.w_hist), interval=2 * len(self.w_hist), blit=True) return (anim)
def run(self, g, w_init, max_its, **kwargs): ### input arguments ### self.g = g self.max_its = max_its self.grad = compute_grad(self.g) # gradient of input function pts = 'off' if 'pts' in kwargs: pts = 'off' linewidth = 2.5 if 'linewidth' in kwargs: linewidth = kwargs['linewidth'] view = [20, -50] if 'view' in kwargs: view = kwargs['view'] axes = False if 'axes' in kwargs: axes = kwargs['axes'] plot_final = False if 'plot_final' in kwargs: plot_final = kwargs['plot_final'] num_contours = 15 if 'num_contours' in kwargs: num_contours = kwargs['num_contours'] # version of gradient descent to use (normalized or unnormalized) self.version = 'unnormalized' if 'version' in kwargs: self.version = kwargs['version'] # get initial point self.w_init = np.asarray([float(s) for s in w_init]) # take in user defined maximum number of iterations self.max_its = max_its # construct figure fig, axs = plt.subplots(1, 2, figsize=(9, 4)) # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 2, width_ratios=[2, 1]) ax = plt.subplot(gs[0], aspect='equal') ax2 = plt.subplot(gs[1]) # ,sharey = ax); #### run local random search algorithm #### self.w_hist = [] self.steplength = 'exact' self.run_coordinate_descent() # set viewing limits on contour plot xvals = [self.w_hist[s][0] for s in range(len(self.w_hist))] xvals.append(self.w_init[0]) yvals = [self.w_hist[s][1] for s in range(len(self.w_hist))] yvals.append(self.w_init[1]) xmax = max(xvals) xmin = min(xvals) xgap = (xmax - xmin) * 0.1 ymax = max(yvals) ymin = min(yvals) ygap = (ymax - ymin) * 0.1 xmin -= xgap xmax += xgap ymin -= ygap ymax += ygap if 'xmin' in kwargs: xmin = kwargs['xmin'] if 'xmax' in kwargs: xmax = kwargs['xmax'] if 'ymin' in kwargs: ymin = kwargs['ymin'] if 'ymax' in kwargs: ymax = kwargs['ymax'] #### define input space for function and evaluate #### w1 = np.linspace(xmin, xmax, 400) w2 = np.linspace(ymin, ymax, 400) w1_vals, w2_vals = np.meshgrid(w1, w2) w1_vals.shape = (len(w1)**2, 1) w2_vals.shape = (len(w2)**2, 1) h = np.concatenate((w1_vals, w2_vals), axis=1) func_vals = np.asarray([g(s) for s in h]) w1_vals.shape = (len(w1), len(w1)) w2_vals.shape = (len(w2), len(w2)) func_vals.shape = (len(w1), len(w2)) ### make contour right plot - as well as horizontal and vertical axes ### # set level ridges num_contours = kwargs['num_contours'] levelmin = min(func_vals.flatten()) levelmax = max(func_vals.flatten()) cutoff = 0.5 cutoff = (levelmax - levelmin) * cutoff numper = 3 levels1 = np.linspace(cutoff, levelmax, numper) num_contours -= numper levels2 = np.linspace(levelmin, cutoff, min(num_contours, numper)) levels = np.unique(np.append(levels1, levels2)) num_contours -= numper while num_contours > 0: cutoff = levels[1] levels2 = np.linspace(levelmin, cutoff, min(num_contours, numper)) levels = np.unique(np.append(levels2, levels)) num_contours -= numper a = ax.contour(w1_vals, w2_vals, func_vals, levels=levels, colors='k') ax.contourf(w1_vals, w2_vals, func_vals, levels=levels, cmap='Blues') # label contour lines? #ax.clabel(a, inline=1, fontsize=10) if axes == True: ax.axhline(linestyle='--', color='k', linewidth=1) ax.axvline(linestyle='--', color='k', linewidth=1) # colors for points s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) colorspec = [] colorspec = np.concatenate((s, np.flipud(s)), 1) colorspec = np.concatenate((colorspec, np.zeros((len(s), 1))), 1) ### plot function decrease plot in right panel for j in range(len(self.w_hist)): w_val = self.w_hist[j] g_val = self.g(w_val) # plot in left panel if pts == 'True': ax.scatter(w_val[0], w_val[1], s=30, c=colorspec[j], edgecolor='k', linewidth=1.5 * math.sqrt((1 / (float(j) + 1))), zorder=3) ax2.scatter(j, g_val, s=30, c=colorspec[j], edgecolor='k', linewidth=0.7, zorder=3) # plot point of tangency # plot connector between points for visualization purposes if j > 0: w_old = self.w_hist[j - 1] w_new = self.w_hist[j] g_old = self.g(w_old) g_new = self.g(w_new) ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]], color=colorspec[j], linewidth=linewidth, alpha=1, zorder=2) # plot approx ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]], color='k', linewidth=linewidth + 0.4, alpha=1, zorder=1) # plot approx ax2.plot([j - 1, j], [g_old, g_new], color=colorspec[j], linewidth=2, alpha=1, zorder=2) # plot approx ax2.plot([j - 1, j], [g_old, g_new], color='k', linewidth=2.5, alpha=1, zorder=1) # plot approx # clean panels title = self.steplength if type(self.steplength) == float: title = r'$\alpha = $' + str(self.steplength) #ax.set_title(title,fontsize = 12) ax.set_xlabel('$w_1$', fontsize=12) ax.set_ylabel('$w_2$', fontsize=12, rotation=0) ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) ax.axvline(x=0, color='k', zorder=0, linewidth=0.5) ax2.axhline(y=0, color='k', zorder=0, linewidth=0.5) ax2.set_xlabel('iteration', fontsize=12) ax2.set_ylabel(r'$g(w)$', fontsize=12, rotation=0, labelpad=25) ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) ax.set(aspect='equal') a = ax.get_position() yr = ax.get_position().y1 - ax.get_position().y0 xr = ax.get_position().x1 - ax.get_position().x0 aspectratio = 1.25 * xr / yr # + min(xr,yr) ratio_default = (ax2.get_xlim()[1] - ax2.get_xlim()[0]) / ( ax2.get_ylim()[1] - ax2.get_ylim()[0]) ax2.set_aspect(ratio_default * aspectratio) # plot plt.show()
def draw_it_newton(self, **args): if 'w_init' in args: self.w_init = float(args['w_init']) # initialize figure fig = plt.figure(figsize=(4, 4)) artist = fig ax = fig.add_subplot(111) # run newtons method and collect path history self.w_hist = [] self.run_newtons() # set viewing range wmax = max([v for v in self.w_hist]) wmin = min([v for v in self.w_hist]) wgap = (wmax - wmin) * 0.5 wmax += wgap wmin -= wgap w_plot = np.linspace(wmin, wmax, 200) g_plot = self.g(w_plot) width = 30 # set range for function plotting w_plot1 = np.linspace(-3, 3) g_plot1 = self.g(w_plot1) gmin = min(copy.deepcopy(g_plot1)) gmax = max(copy.deepcopy(g_plot1)) ggap = (gmax - gmin) * 0.2 gmin -= ggap gmax += ggap # colors for points s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) self.colorspec = [] self.colorspec = np.concatenate((s, np.flipud(s)), 1) self.colorspec = np.concatenate((self.colorspec, np.zeros( (len(s), 1))), 1) # animation sub-function print('beginning animation rendering...') def animate(k): ax.cla() # print rendering update if k == len(self.w_hist): print('animation rendering complete!') time.sleep(1.5) clear_output() # plot function ax.plot(w_plot1, g_plot1, color='k', zorder=1) # plot function # plot all input/output pairs generated by algorithm thus far if k > 0: # plot all points up to this point for j in range(0, min(k + 1, len(self.w_hist))): w_val = self.w_hist[j] g_val = self.g(w_val) if j == k - 1: # draw guide line to visua s = np.linspace(0, g_val) o = np.ones((len(s))) ax.plot(o * w_val, s, 'k--', linewidth=1, zorder=1) ax.scatter(w_val, g_val, s=90, c=self.colorspec[j], edgecolor='k', linewidth=1, zorder=3) # plot point of tangency ax.scatter(w_val, 0, s=90, facecolor=self.colorspec[j], marker='X', edgecolor='k', linewidth=1, zorder=2) if j == k: # draw guide line to visua s = np.linspace(0, g_val) o = np.ones((len(s))) ax.plot(o * w_val, s, 'k--', linewidth=1, zorder=1) ax.scatter(w_val, g_val, s=90, c='w', edgecolor='k', linewidth=1, zorder=3) # plot point of tangency ax.scatter(w_val, 0, s=90, facecolor='w', marker='X', edgecolor='k', linewidth=1, zorder=2) # plot surrogate function and travel-to point if k > 0 and k < len(self.w_hist) + 1: # grab historical weight, compute function and derivative evaluations w = self.w_hist[k - 1] g_eval = self.g(w) grad_eval = float(self.grad(w)) # determine width to plot the approximation -- so its length == width defined above div = float(1 + grad_eval**2) w1 = w - math.sqrt(width / div) w2 = w + math.sqrt(width / div) # use point-slope form of line to plot wrange = np.linspace(w1, w2, 100) h = g_eval + grad_eval * (wrange - w) # plot tangent line ax.plot(wrange, h, color=self.colorspec[k - 1], linewidth=2, zorder=1) # plot approx # plot tangent point #ax.scatter(w,g_eval,s = 100,c = 'm',edgecolor = 'k',linewidth = 0.7,zorder = 2) # plot point of tangency # plot go-too line on surrogate w_zero = -g_eval / grad_eval + w #ax.scatter(w_zero,0,s = 100,c = 'm',edgecolor = 'k',linewidth = 0.7, zorder = 2, marker = 'X') ''' # plot next point learned from surrogate if k > 0: # draw dashed lines to highlight zero crossing point g_zero = self.g(w_zero) s = np.linspace(0,g_zero) o = np.ones((len(s))) ax.plot(o*w_zero,s,'k--',linewidth=1,zorder = 1) # draw associated point on cost function you hop back too #ax.scatter(w_zero,g_zero,s = 100,c = 'm',edgecolor = 'k',linewidth = 0.7,zorder = 2) # plot point of tangency ''' # fix viewing limits ax.set_xlim([wmin, wmax]) ax.set_ylim([gmin, gmax]) # draw axes # ax.grid(True, which='both') ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) # ax.axvline(x=0, color='k') # place title ax.set_title("Newton's method (zero finding)", fontsize=12) return artist, anim = animation.FuncAnimation(fig, animate, frames=len(self.w_hist) + 1, interval=len(self.w_hist) + 1, blit=True) return (anim)
anp.roll.defjvp( lambda g, ans, gvs, vs, x, shift, axis=None: anp.roll(g, shift, axis=axis)) anp.array_split.defjvp(lambda g, ans, gvs, vs, ary, idxs, axis=0: anp. array_split(g, idxs, axis=axis)) anp.split.defjvp( lambda g, ans, gvs, vs, ary, idxs, axis=0: anp.split(g, idxs, axis=axis)) anp.vsplit.defjvp(lambda g, ans, gvs, vs, ary, idxs: anp.vsplit(g, idxs)) anp.hsplit.defjvp(lambda g, ans, gvs, vs, ary, idxs: anp.hsplit(g, idxs)) anp.dsplit.defjvp(lambda g, ans, gvs, vs, ary, idxs: anp.dsplit(g, idxs)) anp.ravel.defjvp( lambda g, ans, gvs, vs, x, order=None: anp.ravel(g, order=order)) anp.expand_dims.defjvp( lambda g, ans, gvs, vs, x, axis: anp.expand_dims(g, axis)) anp.squeeze.defjvp(lambda g, ans, gvs, vs, x, axis=None: anp.squeeze(g, axis)) anp.diag.defjvp(lambda g, ans, gvs, vs, x, k=0: anp.diag(g, k)) anp.flipud.defjvp(lambda g, ans, gvs, vs, x, : anp.flipud(g)) anp.fliplr.defjvp(lambda g, ans, gvs, vs, x, : anp.fliplr(g)) anp.rot90.defjvp(lambda g, ans, gvs, vs, x, k=1: anp.rot90(g, k)) anp.trace.defjvp(lambda g, ans, gvs, vs, x, offset=0: anp.trace(g, offset)) anp.full.defjvp(lambda g, ans, gvs, vs, shape, fill_value, dtype=None: anp. full(shape, g, dtype), argnum=1) anp.triu.defjvp(lambda g, ans, gvs, vs, x, k=0: anp.triu(g, k=k)) anp.tril.defjvp(lambda g, ans, gvs, vs, x, k=0: anp.tril(g, k=k)) anp.clip.defjvp(lambda g, ans, gvs, vs, x, a_min, a_max: g * anp.logical_and( ans != a_min, ans != a_max)) anp.swapaxes.defjvp( lambda g, ans, gvs, vs, x, axis1, axis2: anp.swapaxes(g, axis1, axis2)) anp.rollaxis.defjvp( lambda g, ans, gvs, vs, a, axis, start=0: anp.rollaxis(g, axis, start)) anp.real_if_close.defjvp(lambda g, ans, gvs, vs, x: npg.match_complex(vs, g))
def visualize3d(func, **kwargs): ### input arguments ### wmax = 1 if 'wmax' in kwargs: wmax = kwargs['wmax'] + 0.5 view = [20, -50] if 'view' in kwargs: view = kwargs['view'] axes = False if 'axes' in kwargs: axes = kwargs['axes'] plot_final = False if 'plot_final' in kwargs: plot_final = kwargs['plot_final'] num_contours = 10 if 'num_contours' in kwargs: num_contours = kwargs['num_contours'] pt = [0, 0] if 'pt' in kwargs: pt = kwargs['pt'] pt = np.asarray(pt) pt.shape = (2, 1) max_steps = 10 if 'max_steps' in kwargs: max_steps = kwargs['max_steps'] num_samples = 10 if 'num_samples' in kwargs: num_samples = kwargs['num_samples'] steplength = 1 if 'steplength' in kwargs: steplength = kwargs['steplength'] ##### construct figure with panels ##### # construct figure fig = plt.figure(figsize=(9, 3)) # remove whitespace from figure fig.subplots_adjust(left=0, right=1, bottom=0, top=1) # remove whitespace # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 2, width_ratios=[1, 2]) ax = plt.subplot(gs[0], projection='3d') ax2 = plt.subplot(gs[1], aspect='equal') #### define input space for function and evaluate #### w = np.linspace(-wmax, wmax, 200) w1_vals, w2_vals = np.meshgrid(w, w) w1_vals.shape = (len(w)**2, 1) w2_vals.shape = (len(w)**2, 1) h = np.concatenate((w1_vals, w2_vals), axis=1) func_vals = np.asarray([func(s) for s in h]) w1_vals.shape = (len(w), len(w)) w2_vals.shape = (len(w), len(w)) func_vals.shape = (len(w), len(w)) # plot function ax.plot_surface(w1_vals, w2_vals, func_vals, alpha=0.1, color='w', rstride=25, cstride=25, linewidth=1, edgecolor='k', zorder=2) # plot z=0 plane ax.plot_surface(w1_vals, w2_vals, func_vals * 0, alpha=0.1, color='w', zorder=1, rstride=25, cstride=25, linewidth=0.3, edgecolor='k') ### make contour right plot - as well as horizontal and vertical axes ### ax2.contour(w1_vals, w2_vals, func_vals, num_contours, colors='k') if axes == True: ax2.axhline(linestyle='--', color='k', linewidth=1) ax2.axvline(linestyle='--', color='k', linewidth=1) #### run local random search algorithm #### pt_history, eval_history = random_local_search(func, pt, max_steps, num_samples, steplength) ### plot circle on which point lies, as well as step length circle - used only for simple quadratic if plot_final == True: # plot contour of quadratic on which final point was plotted f = pt_history[-1] val = np.linalg.norm(f) theta = np.linspace(0, 1, 400) x = val * np.cos(2 * np.pi * theta) y = val * np.sin(2 * np.pi * theta) ax2.plot(x, y, color='r', linestyle='--', linewidth=1) # plot direction sampling circle centered at final point x = steplength * np.cos(2 * np.pi * theta) + f[0] y = steplength * np.sin(2 * np.pi * theta) + f[1] ax2.plot(x, y, color='b', linewidth=1) # colors for points s = np.linspace(0, 1, len(eval_history[:round(len(eval_history) / 2)])) s.shape = (len(s), 1) t = np.ones(len(eval_history[round(len(eval_history) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) colorspec = [] colorspec = np.concatenate((s, np.flipud(s)), 1) colorspec = np.concatenate((colorspec, np.zeros((len(s), 1))), 1) #### scatter path points #### for k in range(len(eval_history)): ax.scatter(pt_history[k, 0], pt_history[k, 1], 0, s=60, c=colorspec[k], edgecolor='k', linewidth=0.5 * math.sqrt((1 / (float(k) + 1))), zorder=3) ax2.scatter(pt_history[k, 0], pt_history[k, 1], s=60, c=colorspec[k], edgecolor='k', linewidth=1.5 * math.sqrt((1 / (float(k) + 1))), zorder=3) #### connect points with arrows #### if len(eval_history) < 10: for i in range(len(eval_history) - 1): pt1 = pt_history[i] pt2 = pt_history[i + 1] # draw arrow in left plot a = Arrow3D([pt1[0], pt2[0]], [pt1[1], pt2[1]], [0, 0], mutation_scale=10, lw=2, arrowstyle="-|>", color="k") ax.add_artist(a) # draw 2d arrow in right plot ax2.arrow(pt1[0], pt1[1], (pt2[0] - pt1[0]) * 0.78, (pt2[1] - pt1[1]) * 0.78, head_width=0.1, head_length=0.1, fc='k', ec='k', linewidth=3, zorder=2, length_includes_head=True) ### cleanup panels ### ax.set_xlabel('$w_1$', fontsize=12) ax.set_ylabel('$w_2$', fontsize=12, rotation=0) ax.set_title('$g(w_1,w_2)$', fontsize=12) ax.view_init(view[0], view[1]) ax2.set_xlabel('$w_1$', fontsize=12) ax2.set_ylabel('$w_2$', fontsize=12, rotation=0) # clean up axis ax.xaxis.pane.fill = False ax.yaxis.pane.fill = False ax.zaxis.pane.fill = False ax.xaxis.pane.set_edgecolor('white') ax.yaxis.pane.set_edgecolor('white') ax.zaxis.pane.set_edgecolor('white') ax.xaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) ax.yaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) ax.zaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) # plot plt.show()
def animate(k): ax1.cla() ax2.cla() # print rendering update if np.mod(k+1,25) == 0: print ('rendering animation frame ' + str(k+1) + ' of ' + str(num_frames)) if k == num_frames - 1: print ('animation rendering complete!') time.sleep(1.5) clear_output() # plot initial point and evaluation if k == 0: w_val = self.w_init g_val = self.g(w_val) ax1.scatter(w_val[0],w_val[1],g_val,s = 100,c = 'm',edgecolor = 'k',linewidth = 0.7,zorder = 2) # plot point of tangency # plot function r = np.linspace(-3,3,100) # create grid from plotting range w1_vals,w2_vals = np.meshgrid(r,r) w1_vals.shape = (len(r)**2,1) w2_vals.shape = (len(r)**2,1) g_vals = self.g([w1_vals,w2_vals]) # vals for cost surface w1_vals.shape = (len(r),len(r)) w2_vals.shape = (len(r),len(r)) g_vals.shape = (len(r),len(r)) ax1.plot_surface(w1_vals,w2_vals,g_vals,alpha = 0.1,color = 'k',rstride=15, cstride=15,linewidth=1,edgecolor = 'k') # plot function alone first along with initial point if k > 0: alpha = self.alpha_range[k-1] # setup axes ax1.set_title(r'$\alpha = $' + r'{:.2f}'.format(alpha),fontsize = 14) ax2.set_xlabel('iteration',fontsize = 13) ax2.set_ylabel('cost function value',fontsize = 13) # run gradient descent method self.w_hist = [] self.run_gradient_descent(alpha = alpha) # plot function self.plot_function(ax1) # colors for points s = np.linspace(0,1,len(self.w_hist[:round(len(self.w_hist)/2)])) s.shape = (len(s),1) t = np.ones(len(self.w_hist[round(len(self.w_hist)/2):])) t.shape = (len(t),1) s = np.vstack((s,t)) self.colorspec = [] self.colorspec = np.concatenate((s,np.flipud(s)),1) self.colorspec = np.concatenate((self.colorspec,np.zeros((len(s),1))),1) # plot everything for each iteration for j in range(len(self.w_hist)): w_val = self.w_hist[j] g_val = self.g(w_val) grad_val = self.grad(w_val) ax1.scatter(w_val[0],w_val[1],g_val,s = 90,c = self.colorspec[j],edgecolor = 'k',linewidth = 0.7,zorder = 3) # plot point of tangency ### plot all on cost function decrease plot ax2.scatter(j,g_val,s = 90,c = self.colorspec[j],edgecolor = 'k',linewidth = 0.7,zorder = 3) # plot point of tangency # clean up second axis ax2.set_xticks(np.arange(len(self.w_hist))) # plot connector between points for visualization purposes if j > 0: w_old = self.w_hist[j-1] w_new = self.w_hist[j] g_old = self.g(w_old) g_new = self.g(w_new) ax2.plot([j-1,j],[g_old,g_new],color = self.colorspec[j],linewidth = 2,alpha = 0.4,zorder = 1) # plot approx # clean up plot ax1.view_init(view[0],view[1]) ax1.set_axis_off() return artist,
def animate_run(self,w_hist,**kwargs): self.w_hist = w_hist ##### setup figure to plot ##### # initialize figure fig = plt.figure(figsize = (8,3)) artist = fig # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 2, width_ratios=[1,1]) ax1 = plt.subplot(gs[0]); ax2 = plt.subplot(gs[1]); # produce color scheme s = np.linspace(0,1,len(self.w_hist[:round(len(w_hist)/2)])) s.shape = (len(s),1) t = np.ones(len(self.w_hist[round(len(w_hist)/2):])) t.shape = (len(t),1) s = np.vstack((s,t)) self.colorspec = [] self.colorspec = np.concatenate((s,np.flipud(s)),1) self.colorspec = np.concatenate((self.colorspec,np.zeros((len(s),1))),1) # seed left panel plotting range xmin = copy.deepcopy(min(self.x)) xmax = copy.deepcopy(max(self.x)) xgap = (xmax - xmin)*0.1 xmin-=xgap xmax+=xgap x_fit = np.linspace(xmin,xmax,300) # seed right panel contour plot viewmax = 3 if 'viewmax' in kwargs: viewmax = kwargs['viewmax'] view = [20,100] if 'view' in kwargs: view = kwargs['view'] num_contours = 15 if 'num_contours' in kwargs: num_contours = kwargs['num_contours'] self.contour_plot(ax2,viewmax,num_contours) # start animation num_frames = len(self.w_hist) print ('starting animation rendering...') def animate(k): # clear panels ax1.cla() # current color color = self.colorspec[k] # print rendering update if np.mod(k+1,25) == 0: print ('rendering animation frame ' + str(k+1) + ' of ' + str(num_frames)) if k == num_frames - 1: print ('animation rendering complete!') time.sleep(1.5) clear_output() ###### make left panel - plot data and fit ###### # initialize fit w = self.w_hist[k] y_fit = self.sigmoid(w[0] + x_fit*w[1]) # scatter data self.scatter_pts(ax1) # plot fit to data ax1.plot(x_fit,y_fit,color = color,linewidth = 2) ###### make right panel - plot contour and steps ###### if k == 0: ax2.scatter(w[0],w[1],s = 90,facecolor = color,edgecolor = 'k',linewidth = 0.5, zorder = 3) if k > 0 and k < num_frames: self.plot_pts_on_contour(ax2,k,color) if k == num_frames -1: ax2.scatter(w[0],w[1],s = 90,facecolor = color,edgecolor = 'k',linewidth = 0.5, zorder = 3) return artist, anim = animation.FuncAnimation(fig, animate ,frames=num_frames, interval=num_frames, blit=True) return(anim)
def static_fig(self,w_hist,**kwargs): self.w_hist = w_hist ind = -1 show_path = True if np.size(w_hist) == 0: show_path = False w = 0 if show_path: w = w_hist[ind] ##### setup figure to plot ##### # initialize figure fig = plt.figure(figsize = (8,3)) artist = fig # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 2, width_ratios=[1,1]) ax1 = plt.subplot(gs[0]); ax2 = plt.subplot(gs[1]); # produce color scheme s = np.linspace(0,1,len(self.w_hist[:round(len(self.w_hist)/2)])) s.shape = (len(s),1) t = np.ones(len(self.w_hist[round(len(self.w_hist)/2):])) t.shape = (len(t),1) s = np.vstack((s,t)) self.colorspec = [] self.colorspec = np.concatenate((s,np.flipud(s)),1) self.colorspec = np.concatenate((self.colorspec,np.zeros((len(s),1))),1) # seed left panel plotting range xmin = copy.deepcopy(min(self.x)) xmax = copy.deepcopy(max(self.x)) xgap = (xmax - xmin)*0.1 xmin-=xgap xmax+=xgap x_fit = np.linspace(xmin,xmax,300) # seed right panel contour plot viewmax = 3 if 'viewmax' in kwargs: viewmax = kwargs['viewmax'] view = [20,100] if 'view' in kwargs: view = kwargs['view'] num_contours = 15 if 'num_contours' in kwargs: num_contours = kwargs['num_contours'] ### contour plot in right panel ### self.contour_plot(ax2,viewmax,num_contours) ### make left panel - plot data and fit ### # scatter data self.scatter_pts(ax1) if show_path: # initialize fit y_fit = self.sigmoid(w[0] + x_fit*w[1]) # plot fit to data color = self.colorspec[-1] ax1.plot(x_fit,y_fit,color = color,linewidth = 2) # add points to right panel contour plot num_frames = len(self.w_hist) for k in range(num_frames): # current color color = self.colorspec[k] # current weights w = self.w_hist[k] ###### make right panel - plot contour and steps ###### if k == 0: ax2.scatter(w[0],w[1],s = 90,facecolor = color,edgecolor = 'k',linewidth = 0.5, zorder = 3) if k > 0 and k < num_frames: self.plot_pts_on_contour(ax2,k,color) if k == num_frames -1: ax2.scatter(w[0],w[1],s = 90,facecolor = color,edgecolor = 'k',linewidth = 0.5, zorder = 3) plt.show()
sigma = 0.15 scl = 0. veclin = -1. + 2. * np.random.rand(2) veclin = veclin / np.linalg.norm(veclin) #veclin = np.array( [ 0., 0. ] ) Q = -1. + 2. * np.random.rand(2) Q = Q / np.linalg.norm(Q) lineslope = 2. ###################################################################################### x, y = np.meshgrid(np.linspace(-1., 1., 500), np.linspace(-1., 1., 500)) y = np.flipud(y) mask = (np.sqrt(x**2 + y**2) < gbrad).astype(float) # gradients calculated here dp_x = egrad(radfun, 0) #( x, y, mu=gbrad, sigma=sigma, veclin=veclin ) dp_y = egrad(radfun, 1) #( x, y, mu=gbrad, sigma=sigma, veclin=veclin ) linerange = np.linspace(-1., 1., 500) linecoords = Q.reshape(-1, 1) @ linerange.reshape(1, -1) linevalues = radfun(linecoords[0, :], linecoords[1, :], mu=gbrad, sigma=sigma, scl=scl, Q=Q, veclin=veclin)
def animate_2d(self, **kwargs): self.g = kwargs['g'] # input function self.grad = compute_grad(self.g) # gradient of input function self.w_init = float( -2 ) # user-defined initial point (adjustable when calling each algorithm) self.alpha = 10**-4 # user-defined step length for gradient descent (adjustable when calling gradient descent) self.max_its = 20 # max iterations to run for each algorithm self.w_hist = [] # container for algorithm path wmin = -3.1 wmax = 3.1 if 'wmin' in kwargs: wmin = kwargs['wmin'] if 'wmax' in kwargs: wmax = kwargs['wmax'] # version of gradient descent to use (normalized or unnormalized) self.version = 'unnormalized' if 'version' in kwargs: self.version = kwargs['version'] # get new initial point if desired if 'w_init' in kwargs: self.w_init = float(kwargs['w_init']) # take in user defined step length if 'steplength' in kwargs: self.steplength = kwargs['steplength'] # take in user defined maximum number of iterations if 'max_its' in kwargs: self.max_its = float(kwargs['max_its']) # initialize figure fig = plt.figure(figsize=(9, 4)) artist = fig # remove whitespace from figure #fig.subplots_adjust(left=0, right=1, bottom=0, top=1) # remove whitespace #fig.subplots_adjust(wspace=0.01,hspace=0.01) # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 3, width_ratios=[1, 4, 1]) ax1 = plt.subplot(gs[0]) ax1.axis('off') ax3 = plt.subplot(gs[2]) ax3.axis('off') ax = plt.subplot(gs[1]) # generate function for plotting on each slide w_plot = np.linspace(wmin, wmax, 200) g_plot = self.g(w_plot) g_range = max(g_plot) - min(g_plot) ggap = g_range * 0.1 width = 30 # run gradient descent method self.w_hist = [] self.run_gradient_descent() # colors for points --> green as the algorithm begins, yellow as it converges, red at final point s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) self.colorspec = [] self.colorspec = np.concatenate((s, np.flipud(s)), 1) self.colorspec = np.concatenate((self.colorspec, np.zeros( (len(s), 1))), 1) # animation sub-function num_frames = 2 * len(self.w_hist) + 2 print('starting animation rendering...') def animate(t): ax.cla() k = math.floor((t + 1) / float(2)) # print rendering update if np.mod(t + 1, 25) == 0: print('rendering animation frame ' + str(t + 1) + ' of ' + str(num_frames)) if t == num_frames - 1: print('animation rendering complete!') time.sleep(1.5) clear_output() # plot function ax.plot(w_plot, g_plot, color='k', zorder=2) # plot function # plot initial point and evaluation if k == 0: w_val = self.w_init g_val = self.g(w_val) ax.scatter(w_val, g_val, s=90, c=self.colorspec[k], edgecolor='k', linewidth=0.5 * ((1 / (float(k) + 1)))**(0.4), zorder=3, marker='X') # evaluation on function ax.scatter(w_val, 0, s=90, facecolor=self.colorspec[k], edgecolor='k', linewidth=0.5 * ((1 / (float(k) + 1)))**(0.4), zorder=3) # draw dashed line connecting w axis to point on cost function s = np.linspace(0, g_val) o = np.ones((len(s))) ax.plot(o * w_val, s, 'k--', linewidth=1) # plot all input/output pairs generated by algorithm thus far if k > 0: # plot all points up to this point for j in range(min(k - 1, len(self.w_hist))): w_val = self.w_hist[j] g_val = self.g(w_val) ax.scatter(w_val, g_val, s=90, c=self.colorspec[j], edgecolor='k', linewidth=0.5 * ((1 / (float(j) + 1)))**(0.4), zorder=3, marker='X') # plot point of tangency ax.scatter(w_val, 0, s=90, facecolor=self.colorspec[j], edgecolor='k', linewidth=0.5 * ((1 / (float(j) + 1)))**(0.4), zorder=2) # plot surrogate function and travel-to point if k > 0 and k < len(self.w_hist) + 1: # grab historical weight, compute function and derivative evaluations w = self.w_hist[k - 1] g_eval = self.g(w) grad_eval = float(self.grad(w)) # determine width to plot the approximation -- so its length == width defined above div = float(1 + grad_eval**2) w1 = w - math.sqrt(width / div) w2 = w + math.sqrt(width / div) # use point-slope form of line to plot wrange = np.linspace(w1, w2, 100) h = g_eval + grad_eval * (wrange - w) # plot tangent line ax.plot(wrange, h, color='lime', linewidth=2, zorder=1) # plot approx # plot tangent point ax.scatter(w, g_eval, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3, marker='X') # plot point of tangency # plot next point learned from surrogate if np.mod(t, 2) == 0: # create next point information w_zero = w - self.alpha * grad_eval g_zero = self.g(w_zero) h_zero = g_eval + grad_eval * (w_zero - w) # draw dashed line connecting the three vals = [0, h_zero, g_zero] vals = np.sort(vals) s = np.linspace(vals[0], vals[2]) o = np.ones((len(s))) ax.plot(o * w_zero, s, 'k--', linewidth=1) # draw intersection at zero and associated point on cost function you hop back too ax.scatter(w_zero, h_zero, s=100, c='k', zorder=3, marker='X') ax.scatter(w_zero, 0, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3) ax.scatter(w_zero, g_zero, s=100, c='m', edgecolor='k', linewidth=0.7, zorder=3, marker='X') # plot point of tangency # fix viewing limits ax.set_xlim([wmin - 0.1, wmax + 0.1]) ax.set_ylim([min(g_plot) - ggap, max(g_plot) + ggap]) ax.axhline(y=0, color='k', zorder=0, linewidth=0.5) # place title ax.set_xlabel(r'$w$', fontsize=14) ax.set_ylabel(r'$g(w)$', fontsize=14, rotation=0, labelpad=25) return artist, anim = animation.FuncAnimation(fig, animate, frames=num_frames, interval=num_frames, blit=True) return (anim)
def compare_versions_3d(self, g, w_init, steplength, max_its, **kwargs): ### input arguments ### self.g = g self.steplength = steplength self.max_its = max_its self.grad = compute_grad(self.g) # gradient of input function wmax = 1 if 'wmax' in kwargs: wmax = kwargs['wmax'] + 0.5 view = [20, -50] if 'view' in kwargs: view = kwargs['view'] axes = False if 'axes' in kwargs: axes = kwargs['axes'] plot_final = False if 'plot_final' in kwargs: plot_final = kwargs['plot_final'] num_contours = 10 if 'num_contours' in kwargs: num_contours = kwargs['num_contours'] # get initial point self.w_init = np.asarray([float(s) for s in w_init]) # take in user defined step length self.steplength = steplength # take in user defined maximum number of iterations self.max_its = max_its ##### construct figure with panels ##### # construct figure fig = plt.figure(figsize=(12, 6)) # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(2, 2, width_ratios=[1, 4]) ax3 = plt.subplot(gs[0], projection='3d') ax4 = plt.subplot(gs[1], aspect='equal') ax5 = plt.subplot(gs[2], projection='3d') ax6 = plt.subplot(gs[3], aspect='equal') # remove whitespace from figure fig.subplots_adjust(left=0, right=1, bottom=0, top=1) # remove whitespace #### define input space for function and evaluate #### w = np.linspace(-wmax, wmax, 200) w1_vals, w2_vals = np.meshgrid(w, w) w1_vals.shape = (len(w)**2, 1) w2_vals.shape = (len(w)**2, 1) h = np.concatenate((w1_vals, w2_vals), axis=1) func_vals = np.asarray([g(s) for s in h]) w1_vals.shape = (len(w), len(w)) w2_vals.shape = (len(w), len(w)) func_vals.shape = (len(w), len(w)) #### run local random search algorithms #### for algo in ['normalized', 'unnormalized']: # switch normalized / unnormalized self.version = algo title = '' if self.version == 'normalized': ax = ax3 ax2 = ax4 title = 'normalized gradient descent' else: ax = ax5 ax2 = ax6 title = 'unnormalized gradient descent' # plot function ax.plot_surface(w1_vals, w2_vals, func_vals, alpha=0.1, color='w', rstride=25, cstride=25, linewidth=1, edgecolor='k', zorder=2) # plot z=0 plane ax.plot_surface(w1_vals, w2_vals, func_vals * 0, alpha=0.1, color='w', zorder=1, rstride=25, cstride=25, linewidth=0.3, edgecolor='k') ### make contour right plot - as well as horizontal and vertical axes ### ax2.contour(w1_vals, w2_vals, func_vals, num_contours, colors='k') if axes == True: ax2.axhline(linestyle='--', color='k', linewidth=1) ax2.axvline(linestyle='--', color='k', linewidth=1) self.w_hist = [] self.run_gradient_descent() # colors for points s = np.linspace(0, 1, len(self.w_hist[:round(len(self.w_hist) / 2)])) s.shape = (len(s), 1) t = np.ones(len(self.w_hist[round(len(self.w_hist) / 2):])) t.shape = (len(t), 1) s = np.vstack((s, t)) colorspec = [] colorspec = np.concatenate((s, np.flipud(s)), 1) colorspec = np.concatenate((colorspec, np.zeros((len(s), 1))), 1) #### scatter path points #### for k in range(len(self.w_hist)): w_now = self.w_hist[k] ax.scatter(w_now[0], w_now[1], 0, s=60, c=colorspec[k], edgecolor='k', linewidth=0.5 * math.sqrt((1 / (float(k) + 1))), zorder=3) ax2.scatter(w_now[0], w_now[1], s=60, c=colorspec[k], edgecolor='k', linewidth=1.5 * math.sqrt((1 / (float(k) + 1))), zorder=3) #### connect points with arrows #### if len(self.w_hist) < 10: for i in range(len(self.w_hist) - 1): pt1 = self.w_hist[i] pt2 = self.w_hist[i + 1] # draw arrow in left plot a = Arrow3D([pt1[0], pt2[0]], [pt1[1], pt2[1]], [0, 0], mutation_scale=10, lw=2, arrowstyle="-|>", color="k") ax.add_artist(a) # draw 2d arrow in right plot ax2.arrow(pt1[0], pt1[1], (pt2[0] - pt1[0]) * 0.78, (pt2[1] - pt1[1]) * 0.78, head_width=0.1, head_length=0.1, fc='k', ec='k', linewidth=3, zorder=2, length_includes_head=True) ### cleanup panels ### ax.set_xlabel('$w_1$', fontsize=12) ax.set_ylabel('$w_2$', fontsize=12, rotation=0) ax.set_title(title, fontsize=12) ax.view_init(view[0], view[1]) ax2.set_xlabel('$w_1$', fontsize=12) ax2.set_ylabel('$w_2$', fontsize=12, rotation=0) ax2.axhline(y=0, color='k', zorder=0, linewidth=0.5) ax2.axvline(x=0, color='k', zorder=0, linewidth=0.5) # clean up axis ax.xaxis.pane.fill = False ax.yaxis.pane.fill = False ax.zaxis.pane.fill = False ax.xaxis.pane.set_edgecolor('white') ax.yaxis.pane.set_edgecolor('white') ax.zaxis.pane.set_edgecolor('white') ax.xaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) ax.yaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) ax.zaxis._axinfo["grid"]['color'] = (1, 1, 1, 0) # plot plt.show()
def draw_it(func, **kwargs): view = [33, 50] if 'view' in kwargs: view = kwargs['view'] # compute gradient, points anchor = [0, 0] anchor = np.array([float(anchor[0]), float(anchor[1])]) anchor.shape = (2, 1) g_anchor = func(anchor) # file tracer tracer = np.asarray([0, 10**-5]) tracer = np.array([float(tracer[0]), float(tracer[1])]) tracer.shape = (2, 1) g_tracer = func(tracer) # construct figure fig = plt.figure(figsize=(9, 3)) artist = fig # remove whitespace from figure fig.subplots_adjust(left=0, right=1, bottom=0, top=1) # remove whitespace fig.subplots_adjust(wspace=0.01, hspace=0.01) # create subplot with 3 panels, plot input function in center plot gs = gridspec.GridSpec(1, 3, width_ratios=[1, 1, 1]) ax1 = plt.subplot(gs[0], projection='3d') ax2 = plt.subplot(gs[1], projection='3d') ax3 = plt.subplot(gs[2], projection='3d') ### first panel - partial with respect to w_1 ### # scatter anchor point ax1.scatter(anchor[0], anchor[1], g_anchor, s=50, c='lime', edgecolor='k', linewidth=1) # plot hyperplane connecting the anchor to tracer secant(func, anchor, tracer, ax1) # plot function plot_func(func, view, ax1) ### second panel - partial with respect to w_2 ### tracer = np.flipud(tracer) ax2.scatter(anchor[0], anchor[1], g_anchor, s=50, c='lime', edgecolor='k', linewidth=1) # plot hyperplane connecting the anchor to tracer secant(func, anchor, tracer, ax2) # plot function plot_func(func, view, ax2) ### third panel - plot full tangent hyperplane at anchor ### ax3.scatter(anchor[0], anchor[1], g_anchor, s=50, c='lime', edgecolor='k', linewidth=1) # plot hyperplane connecting the anchor to tracer tangent(func, anchor, ax3) # plot function plot_func(func, view, ax3)