def generate_figure(z, num_samples, empty=False, disable={}, verbose=True): degree, num_control_points, dim, is_closed = (z['degree'], z['num_control_points'], z['dim'], z['is_closed']) if verbose: print(' degree:', degree) print(' num_control_points:', num_control_points) print(' dim:', dim) print(' is_closed:', is_closed) c = UniformBSpline(degree, num_control_points, dim, is_closed=is_closed) Y, w, u, X = [np.array(z[k]) for k in 'YwuX'] if verbose: print(' num_data_points:', Y.shape[0]) kw = {} if Y.shape[1] == 3: kw['projection'] = '3d' f = plt.figure() if empty: ax = f.add_axes((0, 0, 1, 1), **kw) ax.set_xticks([]) ax.set_yticks([]) if Y.shape[1] == 3: ax.set_zticks([]) ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) for spine in ax.spines.values(): spine.set_visible(False) else: ax = f.add_subplot(111, **kw) ax.set_aspect('equal') def plot(X, *args, **kwargs): ax.plot(*(tuple(X.T) + args), **kwargs) if 'Y' not in disable: plot(Y, '.', c=C['r']) if 'u' not in disable: for m, y in zip(c.M(u, X), Y): plot(np.r_['0,2', m, y], '-', c=C['o']) if 'X' not in disable: plot(X, 'o--', ms=6.0, c='k', mec='k') if 'M' not in disable: plot(c.M(c.uniform_parameterisation(num_samples), X), '-', c=C['b'], lw=3.0) if not empty: e = z.get('e') if e is not None: ax.set_title('Energy: {:.7e}'.format(e)) return f
def generate_figure(z, num_samples, empty=False, disable={}, verbose=True): degree, num_control_points, dim, is_closed = ( z['degree'], z['num_control_points'], z['dim'], z['is_closed']) if verbose: print(' degree:', degree) print(' num_control_points:', num_control_points) print(' dim:', dim) print(' is_closed:', is_closed) c = UniformBSpline(degree, num_control_points, dim, is_closed=is_closed) Y, w, u, X = [np.array(z[k]) for k in 'YwuX'] if verbose: print(' num_data_points:', Y.shape[0]) kw = {} if Y.shape[1] == 3: kw['projection'] = '3d' f = plt.figure() if empty: ax = f.add_axes((0, 0, 1, 1), **kw) ax.set_xticks([]) ax.set_yticks([]) if Y.shape[1] == 3: ax.set_zticks([]) ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) for spine in ax.spines.values(): spine.set_visible(False) else: ax = f.add_subplot(111, **kw) ax.set_aspect('equal') def plot(X, *args, **kwargs): ax.plot(*(tuple(X.T) + args), **kwargs) if 'Y' not in disable: plot(Y, '.', c=C['r']) if 'u' not in disable: for m, y in zip(c.M(u, X), Y): plot(np.r_['0,2', m, y], '-', c=C['o']) if 'X' not in disable: plot(X, 'o--', ms=6.0, c='k', mec='k') if 'M' not in disable: plot(c.M(c.uniform_parameterisation(num_samples), X), '-', c=C['b'], lw=3.0) if not empty: e = z.get('e') if e is not None: ax.set_title('Energy: {:.7e}'.format(e)) return f
def main(): parser = argparse.ArgumentParser() parser.add_argument('input_path') parser.add_argument('output_path') parser.add_argument( 'solver_type', nargs='?', default='dn', choices=UniformBSplineLeastSquaresOptimiser.SOLVER_TYPES) parser.add_argument('--output-all', default=False, action='store_true') parser.add_argument('--max-num-iterations', type=int, default=100) parser.add_argument('--min-radius', type=float, default=1e-9) parser.add_argument('--max-radius', type=float, default=1e12) parser.add_argument('--initial-radius', type=float, default=1e4) args = parser.parse_args() print('Input:', args.input_path) with open(args.input_path, 'r') as fp: z = json.load(fp) degree, num_control_points, dim, is_closed = (z['degree'], z['num_control_points'], z['dim'], z['is_closed']) print(' degree:', degree) print(' num_control_points:', num_control_points) print(' dim:', dim) print(' is_closed:', is_closed) c = UniformBSpline(degree, num_control_points, dim, is_closed=is_closed) Y, w, u, X = [np.array(z[k]) for k in 'YwuX'] lambda_ = z['lambda_'] print(' num_data_points:', Y.shape[0]) print(' lambda_:', lambda_) print('UniformBSplineLeastSquaresOptimiser:') print(' solver_type:', args.solver_type) print(' max_num_iterations:', args.max_num_iterations) print(' min_radius: {:g}'.format(args.min_radius)) print(' max_radius: {:g}'.format(args.max_radius)) print(' initial_radius: {:g}'.format(args.initial_radius)) print('UniformBSplineLeastSquaresOptimiser Output:') (u1, X1, has_converged, states, num_iterations, time_taken) = UniformBSplineLeastSquaresOptimiser( c, args.solver_type).minimise(Y, w, lambda_, u, X, max_num_iterations=args.max_num_iterations, min_radius=args.min_radius, max_radius=args.max_radius, initial_radius=args.initial_radius, return_all=True) print(' has_converged:', has_converged) print(' num_iterations:', num_iterations) print(' num_successful_iterations:', len(states) - 1) print(' initial_energy: {:.3e}'.format(states[0][2])) print(' final_energy: {:.3e}'.format(states[-1][2])) print(' time_taken: {:.3e}s'.format(time_taken)) print(' per_iteration: {:.3e}s'.format(time_taken / num_iterations)) print('Output:', args.output_path) if args.output_all: if not os.path.exists(args.output_path): os.makedirs(args.output_path) for i, (u, X, e, radius) in enumerate(states): z['u'], z['X'] = u.tolist(), X.tolist() z['e'], z['radius'] = e, radius output_path = os.path.join(args.output_path, '{}.json'.format(i)) print(' ', output_path) with open(output_path, 'w') as fp: fp.write(json.dumps(z, indent=4)) else: z['u'], z['X'] = u1.tolist(), X1.tolist() z['e'], z['radius'] = states[-1][2:] with open(args.output_path, 'w') as fp: fp.write(json.dumps(z, indent=4))
def main(): parser = argparse.ArgumentParser() parser.add_argument('num_data_points', type=int) parser.add_argument('w', type=float_tuple) parser.add_argument('lambda_', type=float) parser.add_argument('degree', type=int) parser.add_argument('num_control_points', type=int) parser.add_argument('output_path') parser.add_argument('--alpha', type=float, default=1.0 / (2.0 * np.pi)) parser.add_argument('--dim', type=int, choices={2, 3}, default=2) parser.add_argument('--frequency', type=float, default=1.0) parser.add_argument('--num-init-points', type=int, default=16) parser.add_argument('--sigma', type=float, default=0.05) parser.add_argument('--seed', type=int) args = parser.parse_args() print('Parameters:') print(' alpha:', args.alpha) print(' frequency:', args.frequency) x = np.linspace(0.0, 2.0 * np.pi, args.num_data_points) y = np.exp(-args.alpha * x) * np.sin(args.frequency * x) if args.dim == 2: Y = np.c_[x, y] else: Y = np.c_[x, y, np.linspace(0.0, 1.0, args.num_data_points)] # Initialise `X` so that the uniform B-spline linearly interpolates between # the first and last noise-free data points. t = np.linspace(0.0, 1.0, args.num_control_points)[:, np.newaxis] X = Y[0] * (1 - t) + Y[-1] * t c = UniformBSpline(args.degree, args.num_control_points, args.dim) m0, m1 = c.M(c.uniform_parameterisation(2), X) x01 = 0.5 * (X[0] + X[-1]) X = (np.linalg.norm(Y[0] - Y[-1]) / np.linalg.norm(m1 - m0)) * (X - x01) + x01 # Add isotropic zero-mean Gaussian noise to the data. if args.seed is not None: print(' seed:', args.seed) np.random.seed(args.seed) print(' sigma:', args.sigma) Y += args.sigma * np.random.randn(Y.size).reshape(Y.shape) # Set `w`. if np.any(np.asarray(args.w) < 0): raise ValueError('w <= 0.0 (= {})'.format(args.w)) if len(args.w) == 1: w = np.empty((args.num_data_points, args.dim), dtype=float) w.fill(args.w[0]) elif len(args.w) == args.dim: w = np.tile(args.w, (args.num_data_points, 1)) else: raise ValueError('len(w) is invalid (= {})'.format(len(args.w))) # Check `lambda_`. if args.lambda_ <= 0.0: raise ValueError('lambda_ <= 0.0 (= {})'.format(args.lambda_)) # Initialise `u`. u0 = c.uniform_parameterisation(args.num_init_points) D = scipy.spatial.distance.cdist(Y, c.M(u0, X)) u = u0[D.argmin(axis=1)] # Save. to_list = lambda _: _.tolist() z = dict(degree=args.degree, num_control_points=args.num_control_points, dim=args.dim, is_closed=False, Y=to_list(Y), w=to_list(w), lambda_=args.lambda_, u=to_list(u), X=to_list(X)) print('Output:', args.output_path) with open(args.output_path, 'w') as fp: fp.write(json.dumps(z, indent=4))
def fit_bspline(x, y, dim = 2, degree=2, num_control_points = 20, is_closed = False, num_init_points=1000): ''' Fits and returns a bspline curve to the given x and y points Parameters ---------- x : list data x-coordinates y : list data y-coordinates dim : int the dimensionality of the dataset (default: 2) degree : int the degree of the b-spline polynomial (default: 2) num_control_points : int the number of b-spline control points (default: 20) is_closed : boolean should the b-spline be closed? (default: false) num_init_points : int number of initial points to use in the b-spline parameterization when starting the regression. (default: 1000) Returns ------- c: a UniformBSpline object containing the optimized b-spline ''' # TODO: extract dimensionality from the x,y dataset itself num_data_points = len(x) c = UniformBSpline(degree, num_control_points, dim, is_closed=is_closed) Y = np.c_[x, y] # Data num_points by dimension # Now we need weights for all of the data points w = np.empty((num_data_points, dim), dtype=float) # Currently, every point is equally important w.fill(1) # Uniform weight to the different points # Initialize `X` so that the uniform B-spline linearly interpolates between # the first and last noise-free data points. t = np.linspace(0.0, 1.0, num_control_points)[:, np.newaxis] X = Y[0] * (1 - t) + Y[-1] * t # NOTE: Not entirely sure if the next three lines are necessary or not m0, m1 = c.M(c.uniform_parameterisation(2), X) x01 = 0.5 * (X[0] + X[-1]) X = (np.linalg.norm(Y[0] - Y[-1]) / np.linalg.norm(m1 - m0)) * (X - x01) + x01 # Regularization weight on the control point distance # This specifies a penalty on having the b-spline control points close # together, and in some sense prevents over-fitting. Change this is the # curve doesn't capture the curve variation well or smoothly enough lambda_ = 0.5 # These parameters affect the regression solver. # Presently, they are disabled below, but you can think about enabling them # if that would be useful for your use case. max_num_iterations = 1000 min_radius = 0 max_radius = 400 initial_radius = 100 # Initialize U u0 = c.uniform_parameterisation(num_init_points) D = cdist(Y, c.M(u0, X)) u = u0[D.argmin(axis=1)] # Run the solver (u, X, has_converged, states, num_iterations, time_taken) = UniformBSplineLeastSquaresOptimiser(c,'lm').minimise( Y, w, lambda_, u, X, #max_num_iterations = max_num_iterations, #min_radius = min_radius, #max_radius = max_radius, #initial_radius = initial_radius, return_all=True) return c,u0,X
def fit_bspline(x, y, dim=2, degree=2, num_control_points=20, is_closed=False, num_init_points=1000): ''' Fits and returns a bspline curve to the given x and y points Parameters ---------- x : list data x-coordinates y : list data y-coordinates dim : int the dimensionality of the dataset (default: 2) degree : int the degree of the b-spline polynomial (default: 2) num_control_points : int the number of b-spline control points (default: 20) is_closed : boolean should the b-spline be closed? (default: false) num_init_points : int number of initial points to use in the b-spline parameterization when starting the regression. (default: 1000) Returns ------- c: a UniformBSpline object containing the optimized b-spline ''' # TODO: extract dimensionality from the x,y dataset itself num_data_points = len(x) c = UniformBSpline(degree, num_control_points, dim, is_closed=is_closed) Y = np.c_[x, y] # Data num_points by dimension # Now we need weights for all of the data points w = np.empty((num_data_points, dim), dtype=float) # Currently, every point is equally important w.fill(1) # Uniform weight to the different points # Initialize `X` so that the uniform B-spline linearly interpolates between # the first and last noise-free data points. t = np.linspace(0.0, 1.0, num_control_points)[:, np.newaxis] X = Y[0] * (1 - t) + Y[-1] * t # NOTE: Not entirely sure if the next three lines are necessary or not m0, m1 = c.M(c.uniform_parameterisation(2), X) x01 = 0.5 * (X[0] + X[-1]) X = (np.linalg.norm(Y[0] - Y[-1]) / np.linalg.norm(m1 - m0)) * (X - x01) + x01 # Regularization weight on the control point distance # This specifies a penalty on having the b-spline control points close # together, and in some sense prevents over-fitting. Change this if the # curve doesn't capture the curve variation well or smoothly enough lambda_ = 0.5 # These parameters affect the regression solver. # Presently, they are disabled below, but you can think about enabling them # if that would be useful for your use case. # max_num_iterations = 1000 # min_radius = 0 # max_radius = 400 # initial_radius = 100 # Initialize U u0 = c.uniform_parameterisation(num_init_points) D = cdist(Y, c.M(u0, X)) u = u0[D.argmin(axis=1)] # Run the solver ( u, X, has_converged, states, num_iterations, time_taken ) = UniformBSplineLeastSquaresOptimiser(c, 'lm').minimise( Y, w, lambda_, u, X, #max_num_iterations = max_num_iterations, #min_radius = min_radius, #max_radius = max_radius, #initial_radius = initial_radius, return_all=True) return c, u0, X