def transform_bezier_simplex(k, degree, M): print("------------------------------------------------------------") print("k={}, degree={}".format(k, degree)) print("M =") print_matrix(M) assert (M.rows == k and M.cols == k) rank = degree control_point_symbols = sym.symbols(" ".join( "P_" + "".join(str(i) for i in index) for index in stensor_indices(k, rank))) control_points = stensor(k, rank, control_point_symbols) masks = stensor(k, rank) for mask_index in masks.indices(): mask_tensor_index = masks.to_tensor_index(mask_index) masks.set( mask_index, sum( sum( prod(M[tensor_index[j], mask_tensor_index[j]] for j in range(rank)) for tensor_index in symmetric_tensor_indices(index)) * control_points[index] for index in control_points.indices())) print(masks[mask_index]) transformation = [] for mask_index in masks.indices(): transformation.append([ masks[mask_index].coeff(symbol) for symbol in control_point_symbols ]) transformation = sym.Matrix(transformation) print_matrix(transformation) return transformation
def general_discriminant(degree): assert (degree <= 25) variables = sym.symbols(" ".join(string.ascii_lowercase[:degree + 1])) p = variables[::-1] pp = [i * p[i] for i in range(1, len(p))] print_matrix(sylvester_matrix(p, pp)) return (-(1 / variables[0]) * resultant(p, pp)).expand()
def bezier_basis(degree): n = degree + 1 x = Sym('x') polys = [ p.as_poly() for p in [sym.binomial(n, k) * x**k * (1 - x)**(n - k) for k in range(n + 1)] ] print_matrix(coefficient_matrix(polys))
def finite_differences(samples, order): assert (len(set(samples)) == len(samples)) assert (order < len(samples)) print("finite_differences {}".format(", ".join(str(x) for x in samples))) x = sym.symbols("x") h = sym.symbols("h") n = len(samples) power_matrix = [] for i in range(n): power_matrix.append([(samples[i] * h)**j / factorial(j) for j in range(n)]) power_matrix = sym.Matrix(power_matrix).T A = power_matrix.inv() print_matrix(A) print(sym.latex(power_matrix.T.subs(h, 1))) print(sym.latex(A.T.subs(h, 1))) weights = A.col(order).T return [weights[0, i] for i in range(weights.cols)]
def bezier_curve_degree_elevation(m, n): # Multiply the Bezier curve polynomial of degree m by (u+v)^(n-m) and regroup terms # to get Bezier coefficients for the equivalent polynomial of degree n. assert (n > m) u, v = sym.symbols("u v") ps = sym.symbols(" ".join("p_{}".format(i) for i in range(m + 1))) f = 0 for i in range(m + 1): f += ps[i] * sym.binomial(m, i) * u**i * v**(m - i) f = f.as_poly() print(f) g = (u + v)**(n - m) * f print(g) M = [] for i in range(n + 1): coeffs = [] for j in range(m + 1): coeffs.append( g.coeff_monomial(ps[j] * u**i * v**(n - i)) / sym.binomial(n, i)) print(coeffs) M.append(coeffs) M = sym.Matrix(M) print_matrix(M)
def bezier_triangle_subpatch(degree, a0, b0, c0, a1, b1, c1, a2, b2, c2): x, y, z = Sym("x y z") X, Y, Z = Sym("X Y Z") monomials = [X**i * Y**j * Z**k for i, j, k in ordered_sums(3, degree)] M = [] for mono in monomials: p = mono.subs({ X: a0 * x + a1 * y + a2 * z, Y: b0 * x + b1 * y + b2 * z, Z: c0 * x + c1 * y + c2 * z, }).expand().subs({ x: X, y: Y, z: Z, }).as_poly() # print(mono, "|->", p.as_expr()) coeffs = [] for mono2 in monomials: try: coeffs.append(p.coeff_monomial(mono2)) except: coeffs.append(0) M.append(coeffs) M = Mat(M) A = sym.diag( *[trinomial(degree, i, j, k) for i, j, k in ordered_sums(3, degree)]) K = A * M * A.inv() print_matrix(K) for col, i, j, k in ordered_sums_indexed(3, degree): string = "Q_{}{}{} = ".format(i, j, k) string += " +\n ".join( "({})P_{}{}{}".format(K[row, col], ii, jj, kk) for row, ii, jj, kk in ordered_sums_indexed(3, degree) if K[row, col] != 0) print(string + "\n")
n = degp + degq M = [[0 for _ in range(n)] for __ in range(n)] for i in range(degq): for j in range(degp + 1): M[i + j][i] = p[j] for i in range(degp): for j in range(degq + 1): M[i + j][degq + i] = q[j] return sym.Matrix(M) def resultant(p, q): return sylvester_matrix(p, q).det() def general_discriminant(degree): assert (degree <= 25) variables = sym.symbols(" ".join(string.ascii_lowercase[:degree + 1])) p = variables[::-1] pp = [i * p[i] for i in range(1, len(p))] print_matrix(sylvester_matrix(p, pp)) return (-(1 / variables[0]) * resultant(p, pp)).expand() S = sylvester_matrix([1, -1, 3, -3], [3, -1, -2]) print_matrix(S) print(S.det()) print(general_discriminant(2)) print(general_discriminant(3))
def Rec(n): return Rat(1, n) from sympy.diffgeom.rn import R2_r from sympy.diffgeom import WedgeProduct ex, ey = R2_r.base_vectors() dx, dy = R2_r.base_oneforms() print(WedgeProduct(dx, dy)) print(WedgeProduct(dx, dy)(ex, ey)) J = Mat([[Sym("J_{}{}".format(i, j)) for j in range(1, 3)] for i in range(1, 4)]) print_matrix(J) print_matrix(J.T * J) class k_vector: def __init__(self, n): self.n = n def E(n, *vecs): assert (len(vecs) <= n) k = len(vecs) if len(set(vecs)) < k: return 0 v = k_vector(n)
def solve_linear_dirichlet_bvp(coefficients, boundary, boundary_values, intervals, order_of_accuracy): datatype = float assert (len(boundary) == 2 and len(boundary_values) == 2 and boundary[0] < boundary[1]) n = len(coefficients) # Central finite differences. # todo: Choose simplest central differences for the given accuracy. system = np.zeros((intervals + 1, intervals + 1), dtype=datatype) system[0, 0] = 1 system[intervals, intervals] = 1 dt = 1 / intervals b = np.zeros(intervals + 1, dtype=datatype) b[0] = boundary_values[0] b[intervals] = boundary_values[1] for i in range(1, intervals): b[i] = -coefficients[0](boundary[0] + (boundary[1] - boundary[0]) * i * dt) h = sym.symbols('h') for derivative_degree in range( 1, n): # skip 0'th order term as it will be in b. samples = list(range(-1, 1 + 1)) # only up to order 2 num_samples = len(samples) stencil = [ x.subs(h, dt) for x in finite_differences(samples, derivative_degree) ] stencil_radius = (len(stencil) - 1) // 2 M = np.zeros((intervals + 1, intervals + 1), dtype=datatype) # Left boundary stencils. for index, shift in enumerate(range(-stencil_radius + 1, 0)): shifted_samples = [s - shift for s in samples] shifted_weights = finite_differences(shifted_samples, derivative_degree) for i in range(num_samples): M[index + 1, i] = shifted_weights[i].subs(h, dt) # Right boundary stencils. for index, shift in enumerate(range(1, stencil_radius)): shifted_samples = [s - shift for s in samples] shifted_weights = finite_differences(shifted_samples, derivative_degree) for i in range(num_samples): M[intervals - index - 1, intervals + 1 - num_samples + i] = shifted_weights[i].subs( h, dt) # Middle stencils. for i in range(max(1, stencil_radius), min(intervals, intervals - stencil_radius + 1)): for j in range(num_samples): M[i, j + i - stencil_radius] = stencil[j] # Coefficients are functions of x, so discretize this function and use it to weight the rows. row_multipliers = np.array([ coefficients[derivative_degree] (boundary[0] + (boundary[1] - boundary[0]) * i * dt) for i in range(intervals + 1) ], dtype=datatype) M = np.multiply(M, row_multipliers[:, np.newaxis]) print_matrix(Mat(M)) # Add this matrix to the total system. system = np.add(system, M) print_matrix(Mat(system)) print_matrix(Mat(b)) x = linalg.solve(system, b) plt.plot(np.linspace(boundary[0], boundary[1], intervals + 1), x, "k")
def regular_triangular_bspline(continuity): # Lots of printouts for debugging. VERBOSE = False # Test with integral values to see if it matches the Sabin paper. TEST_INTEGRAL_VALUES = False if continuity % 2 == 0: patch_degree = 1 patches_width = 3 grid = stensor(3, 3, sym_rational=True) grid.set((1, 1, 1), 1) num_iterations = continuity // 2 else: print("Odd continuities not yet supported.") return print("regular_triangular_bspline, continuity={}".format(continuity)) print("============================================================") print("Initial grid") print_triangle_stensor(grid) print("------------------------------------------------------------") # Each repetition gives 2 more degrees of continuity. for iteration in range(num_iterations): print( "================================================================================" ) print("ITERATION", iteration + 1) print( "================================================================================" ) # Do the same shift-subtract-integrate convolution symmetrically in each direction. # Directions of convolution: i->j, j->k, k->i. # The below code is written w/r/t i->j, and the other directions are accounted for by permuting the multi-indices used. for perm_number, perm in enumerate(cyclic_permutations(3)): print( "--------------------------------------------------------------------------------" ) print("DIRECTION", ", ".join(str(i) for i in perm((1, 2, 3)))) if perm_number == 1: print(" --------") elif perm_number == 2: print(""" \\ \\ \\ \\ \\""") elif perm_number == 3: print(""" / / / / / """) print( "--------------------------------------------------------------------------------" ) # Shift the patch coefficients over one patch in the direction of integration, # and subtract this from the patch coefficients. shift_subtract_grid = stensor(3, patch_degree * (patches_width + 1), sym_rational=True) for index in grid.indices(): new_index = add_indices(index, perm((patch_degree, 0, 0))) shift_index = relative_index( new_index, perm((-patch_degree, patch_degree, 0))) shift_subtract_grid.set( new_index, shift_subtract_grid[new_index] + grid[index]) shift_subtract_grid.set( shift_index, shift_subtract_grid[shift_index] - grid[index]) print("Shift and subtract") print_triangle_stensor(grid) print("------->") print_triangle_stensor(shift_subtract_grid) # Integrate, raising the degree of each patch by one. integrand_grid = shift_subtract_grid integral_grid = stensor(3, (patch_degree + 1) * (patches_width + 1)) # Go over each strip of patches. In each strip, there are two stages of integration, for each orientation of triangle. # /\ # /__\ <-- Each quadrilateral: ,--------- # /__/ \ /\ / # /__/ \ / \ / # /__/ \ / \ / # /__/ \ / \ / # /__/ \ /________\/ # /__/ \ # /__/_____________\ new_patch_degree = patch_degree + 1 patches_width += 1 # Now that shift-subtract is done, the grid is wider. for depth in range(patches_width): if VERBOSE: print("~~~~~~ DEPTH {} ~~~~~~".format(depth)) # Depth increases from the top-left strip to the bottom-right corner. for height in range(patches_width - depth): if VERBOSE: print("~~~~~~ DEPTH {}: HEIGHT {} ~~~~~~".format( depth, height)) # Height ranges from the bottom-most part of the strip to the top-most. # # Each quadrilateral is formed by two patches with shared coefficients. # For example, below is the structure of coefficients for a quadrilateral of degree 1 and 2. # # o---------o # /\ / # / \ / # / \ / # / \ / # o________o/ # Degree 1 patches integrate to # *---o-----o # /\ / \ / # / \/ \ / # *---o-----o # / \ / \ / # *___o____o/ The *s are constants of integration, assumed already computed when integrating previous strips. # Compute important corresponding indices for the patch/pair in both the integrand grid and the integral grid. integrand_lower_left_index = perm( ((patches_width - height - depth) * patch_degree, depth * patch_degree, height * patch_degree)) integrand_lower_right_index = relative_index( integrand_lower_left_index, perm((-patch_degree, patch_degree, 0))) integral_lower_left_index = perm( ((patches_width - height - depth) * new_patch_degree - 1, depth * new_patch_degree + 1, height * new_patch_degree)) integral_lower_right_index = relative_index( integral_lower_left_index, perm((-patch_degree - 1, patch_degree, 1))) if VERBOSE: print("integrand_lower_left_index:", integrand_lower_left_index) print("integrand_lower_right_index:", integrand_lower_right_index) print("integral_lower_left_index:", integral_lower_left_index) print("integral_lower_right_index:", integral_lower_right_index) # The integrand patch corresponds to the bottom-right sub-triangle in this integrated patch: # * # /\ # / \ # *---o\ e.g. The integrand here is of degree 1. # / \ / \ # *___o____o # ^ # lower_left_index into the integral grid. # *----o---o # \ / \ / # *----o <- lower_right_index into the integral grid. # \ / # \* if VERBOSE: print( "------------------------------------------------------------" ) print("Lower-left triangle") print( "------------------------------------------------------------" ) print("Integrand:") print_triangle_stensor(integrand_grid) for patch_depth in range(patch_degree + 1): for patch_height in range(patch_degree + 1 - patch_depth): integrand_index = relative_index( integrand_lower_left_index, perm((-patch_depth - patch_height, patch_depth, patch_height))) integral_index = relative_index( integral_lower_left_index, perm((-patch_depth - patch_height, patch_depth, patch_height))) left_integral_index = relative_index( integral_index, perm((1, -1, 0))) if VERBOSE: print("integrand_index:", integrand_index) print("integral_index:", integral_index) print("left_integral_index:", left_integral_index) if TEST_INTEGRAL_VALUES: integral_grid.set( integral_index, integrand_grid[integrand_index] + integral_grid[left_integral_index]) else: integral_grid.set( integral_index, integrand_grid[integrand_index] / (patch_degree + 1) + integral_grid[left_integral_index]) # When height is maximal, there is no adjacent triangle to the top-right, so # those coefficients aren't computed. if height == patches_width - depth - 1: continue # Otherwise, do effectively the same thing for the second triangle. The previous triangle has been integrated, # so the initial conditions are already provided. # *----o---o # \ / \ / Now, patch_depth increases from the bottom-left strip to the top-right corner, # *----o and patch_height increases from the bottom-right to the top-left part of the strip. # \ / # \* if VERBOSE: print( "------------------------------------------------------------" ) print("Top-right triangle") print( "------------------------------------------------------------" ) for patch_depth in range(patch_degree + 1): for patch_height in range(patch_degree + 1 - patch_depth): integrand_index = relative_index( integrand_lower_right_index, perm((-patch_depth, -patch_height, patch_depth + patch_height))) integral_index = relative_index( integral_lower_right_index, perm((-patch_depth, -patch_height, patch_depth + patch_height))) left_integral_index = relative_index( integral_index, perm((1, -1, 0))) if VERBOSE: print("integrand_index:", integrand_index) print("integral_index:", integral_index) print("left_integral_index:", left_integral_index) if TEST_INTEGRAL_VALUES: integral_grid.set( integral_index, integrand_grid[integrand_index] + integral_grid[left_integral_index]) else: integral_grid.set( integral_index, integrand_grid[integrand_index] / (patch_degree + 1) + integral_grid[left_integral_index]) # Continue for permutation ... # The grid has been integrated. grid = integral_grid patch_degree += 1 print("Integrated") print_triangle_stensor(grid) print("patch_degree:", patch_degree) print("patches_width:", patches_width) print("COMPLETE") print("patch_degree:", patch_degree) print("patches_width:", patches_width) print("grid_width:", patch_degree * patches_width) # Convert this raw triangle of Bezier coefficients into a triangle of triangles, each triangle being # the Bezier coefficients of a patch (polynomial piece of the basis function). # These patches are of /\-oriented triangles. patches = stensor(3, patches_width - 1) for patch_index in patches.indices(): lower_left_index = (patch_index[0] * patch_degree + patch_degree, patch_index[1] * patch_degree, patch_index[2] * patch_degree) print(patch_index, "-->", lower_left_index) bezier_coefficients = stensor(3, patch_degree, sym_rational=True) for bezier_coefficient_index in bezier_coefficients.indices(): grid_index = (lower_left_index[0] - bezier_coefficient_index[1] - bezier_coefficient_index[2], lower_left_index[1] + bezier_coefficient_index[1], lower_left_index[2] + bezier_coefficient_index[2]) bezier_coefficients.set(bezier_coefficient_index, grid[grid_index]) print_triangle_stensor(bezier_coefficients) # if all(bezier_coefficients[i] == 0 for i in bezier_coefficients.indices()): # # This patch is zero everywhere. Signify this by giving it the value None. # patches.set(patch_index, None) # else: # patches.set(patch_index, bezier_coefficients) #------------------------------------------------------------ patches.set(patch_index, bezier_coefficients) # Now the basis function is represented by a bounding triangle of polynomial patches. # Each patch in this triangle stores a triangle of Bezier coefficients, or is None if this patch is outside the support of the basis function. # Consider a regular isometric grid in the domain. # For each point, there is a basis function that corresponds to a control point. # Consider a /\-oriented triangle in the domain tessellation. # This triangle is in the support of a certain number of basis functions, each corresponding to a control point. # The image of this triangle is a polynomial piece of the surface. This polynomial piece has Bezier points dependent on # the control points of those basis functions. # # Initialize a triangle of points symmetrically bounding a central triangle in the domain. # Go over each point, and check whether the support of that point's basis function reaches the central triangle. # # The triangle patch has Bezier points. Each Bezier point is a combination of the relevant control points weighted by # the corresponding Bezier coefficient in the relevant basis function patch of that control point. patches_triangle_corners = [ (patches_width // 3 - 1, patches_width // 3, patches_width // 3), (patches_width // 3, patches_width // 3 - 1, patches_width // 3), (patches_width // 3, patches_width // 3, patches_width // 3 - 1) ] patches_triangle_corners_matrix = sym.Matrix( [[i / (patches_width - 1) for i in corner] for corner in patches_triangle_corners]) bezier_masks = stensor(3, patch_degree) for index in bezier_masks.indices(): # Each Bezier point has a mask of weight contributions from the bounding triangle of relevant control points. bezier_masks.set( index, stensor(3, 1 + 3 * (continuity // 2), sym_rational=True)) print("Organizing coefficients...") print("patch_degree:", patch_degree) print("patches_width:", patches_width) print("grid_width:", patch_degree * patches_width) control_points_width = 1 + 3 * (continuity // 2) for control_point_index in stensor_indices(3, control_points_width): # Convert to central-triangle coordinates. central_triangle_index = [ i - continuity // 2 for i in control_point_index ] #---I think this is correct. patches_barycentric = patches_triangle_corners_matrix * sym.Matrix( central_triangle_index) patches_barycentric = [ patches_barycentric[i, 0] for i in range(patches_barycentric.rows) ] patches_index = [ round((patches_width - 1) * x) for x in patches_barycentric ] if any(i < 0 for i in patches_index): # This patch does not exist in the bounding triangle of the patches. continue patch = patches[patches_index] for bezier_index in bezier_masks.indices(): bezier_masks[bezier_index].set( control_point_index, bezier_masks[bezier_index][control_point_index] + patch[bezier_index]) for index in bezier_masks.indices(): print_triangle_stensor(bezier_masks[index]) print( "sum =", sum(bezier_masks[index][i] for i in bezier_masks[index].indices())) de_boor_to_bezier_matrix = [] # Print out the de-Boor-to-Bezier matrix in C/C++ syntax. string = "float ____[({0}*({0}+1))/2 * ({1}*({1}+1))/2] = ".format( patch_degree + 1, control_points_width + 1) + "{\n" for bezier_index in bezier_masks.indices(): mask = bezier_masks[bezier_index] string += " " weights = [] for control_point_index in mask.indices(): weight = mask[control_point_index] weights.append(weight) if weight == 0: string += "0, " else: string += "{}.f/{}.f, ".format(weight.p, weight.q) string += "\n" de_boor_to_bezier_matrix.append(weights) string += "};" print(string) f = open( "data/triangular_bspline_coefficients_C_{}.txt".format(continuity), "w+") f.write(string) f.close() #================================================================================ # Subdivision #================================================================================ # A full rank (possibly overdetermined) system is wanted, so that the de Boor window can # be transformed to Bezier points, those Bezier points subdivided, then an inversion attempt made # with the Moore-Penrose pseudoinverse, to find de Boor points which transform to the subdivided Bezier points. # # It is necessary to remove columns of zeroes. These correspond to points in the bounding triangle which are not actually in the # support of the basis function. M = [] M_extracted_columns = [ ] # The relevant columns correspond to named points in the bounding triangle, so tracking which points are considered will be useful. for col in range(len(de_boor_to_bezier_matrix[0])): c = [ de_boor_to_bezier_matrix[row][col] for row in range(len(de_boor_to_bezier_matrix)) ] if not all(x == 0 for x in c): M_extracted_columns.append(col) M.append(c) M = sym.Matrix(M).T print_matrix(M) print("Computing pseudo-inverse...") try: M_pseudoinverse = (M.T * M).inv() * M.T except: print("Failed to compute pseudo-inverse. M is not full rank.") # The de Boor subdivision matrix is computed: # - The window of de Boor points is transformed by M. # - The resulting Bezier points are transformed by T to new Bezier points based on a certain affine parameter transformation. # - The pseudoinverse of M, M+, is used in an attempt to find de Boor points which would generate these new Bezier points. # So, de_boor_subdiv = M+ T M. bottom_left_affine_parameter_transform = Mat([[1, Rat(1, 2), Rat(1, 2)], [0, Rat(1, 2), 0], [0, 0, Rat(1, 2)]]) middle_affine_parameter_transform = Mat([[Rat(1, 2), Rat(1, 2), 0], [0, Rat(1, 2), Rat(1, 2)], [Rat(1, 2), 0, Rat(1, 2)]]) T = transform_bezier_simplex(3, patch_degree, bottom_left_affine_parameter_transform) deboor_subdiv = M_pseudoinverse * T * M # Check that all rows sum to 1. assert (all( sum(deboor_subdiv[row, col] for col in range(deboor_subdiv.cols)) == 1 for row in range(deboor_subdiv.rows))) for i, index in enumerate(stensor_indices(3, control_points_width)): if i in M_extracted_columns: # do not consider points not in the support. print(index) print_matrix(deboor_subdiv)
def deboor_to_bezier(domain_simplex_dim, continuity, knots=None): #----- This only works for domain_simplex_dim == 2. The attempt of generalization to higher simplex dimension did not work or really make sense. print("============================================================") print("deboor_to_bezier, domain_simplex_dim={}, continuity={}".format( domain_simplex_dim, continuity)) print("------------------------------------------------------------") # Compute the de Boor net width as a figurate number, then check # that the knot tensor has the right shape. # ------------------------------------------------------------ deboor_net_width = figurate_number(domain_simplex_dim - 1, continuity + 1) + 1 #--- num_deboor_points = figurate_number(domain_simplex_dim - 1, deboor_net_width) degree = deboor_net_width - 1 knots_width = deboor_net_width + continuity num_knots = figurate_number(domain_simplex_dim - 1, knots_width) print("deboor_net_width:", deboor_net_width) print("num_deboor_points:", num_deboor_points) print("degree:", degree) print("knots_width:", knots_width) print("num_knots:", num_knots) if knots == None: knots = stensor(domain_simplex_dim, knots_width - 1) for index in knots.indices(): knots.set(index, index) # just some distinct value for now elif type(knots) == list: knots = stensor(domain_simplex_dim, knots_width - 1, knots) assert (knots.k == domain_simplex_dim) assert (knots.rank == knots_width - 1) deboor_weights_matrix = [] for deboor_index in stensor_indices(domain_simplex_dim, degree): # For each de Boor net index, get a list of corresponding knot # indices into the knot tensor. # ------------------------------------------------------------ print("------------------------------------------------------------") print("deboor_index:", deboor_index) print("---") top_knot_mask_index = list(deboor_index) top_knot_mask_index[0] += continuity knot_mask_indices = deboor_to_bezier_knot_mask(top_knot_mask_index, continuity) print("knot_mask_indices:", knot_mask_indices) knot_mask = [knots[knot_index] for knot_index in knot_mask_indices] print("knot_mask:", knot_mask) # The values in the knot tensor are points in the affine domain. The de Boor net point p (of index deboor_index) is # p = f(...) where f is multi-affine and symmetric and the inputs are the knots in the knot mask of p, knot_mask. # Expanding p = f(...) gives p as an affine combination of Bezier points f(e_i,...), which are multiset inputs # of the affine domain basis simplex that the knots are expressed in. affine_weights = [0 for _ in range(num_deboor_points) ] # one for each Bezier point. for multiindex in itertools.product(range(domain_simplex_dim), repeat=degree): flat_index = tensor_to_flat_index(domain_simplex_dim, degree, multiindex) affine_weights[flat_index] += prod( knot_mask[position][i] for position, i in enumerate(multiindex)) print("weights:", affine_weights) deboor_weights_matrix.append(affine_weights) print(knot_mask) # Check that the rows sum to 1. If not, something definitely went wrong. for row in deboor_weights_matrix: assert (sum(row) == 1) deboor_weights_matrix = sym.Matrix(deboor_weights_matrix) print_matrix(deboor_weights_matrix) print_matrix(deboor_weights_matrix.inv()) deboor_to_bezier_matrix = deboor_weights_matrix.inv() for i, index in enumerate(stensor_indices(domain_simplex_dim, degree)): print("{}: {}".format( index, ", ".join(str(c) for c in list(deboor_to_bezier_matrix.row(i)))))
quadratic_triangular_bspline_subdivision_scheme() A = Mat([[0, 0, 0, Half, 0, 0, 0, 0, 0], [0, 0, 0, 0, Half, 0, 0, 0, 0], [0, 0, 0, 0, 0, Half, 0, 0, 0], [Half, Half, Half, 0, 0, 0, 1, 1, 1]]) AM = Mat([[0, 0, 0, 0, Rat(1, 8), Rat(1, 8), 0, 0, Quarter], [0, 0, 0, Rat(1, 8), 0, Rat(1, 8), 0, Quarter, 0], [0, 0, 0, Rat(1, 8), Rat(1, 8), 0, Quarter, 0, 0], [ Half, Half, Half, Quarter, Quarter, Quarter, Rat(3, 4), Rat(3, 4), Rat(3, 4) ]]) print_matrix(AM * A.T * (A * A.T).inv()) A = Mat([[0, 0, Half, 0, 0], [0, 0, 0, Half, 0], [Half, Half, 0, 0, 1]]) AM = Mat([[0, 0, Half, 0, 0], [0, 0, Rat(1, 8), Rat(1, 8), Quarter], [Rat(3, 4), Rat(1, 4), Rat(1, 2), 0, Rat(1, 2)]]) print_matrix(A) print_matrix(AM) print_matrix(AM * A.T * (A * A.T).inv()) x, y, z = Sym("x y z") X, Y, Z = Sym("X Y Z") print(((1 - x)**2 / 2).expand()) print((x / 2 + y / 2 + x * y).subs(y, 1 - x).expand())
def create_stochastic_blockmodel_graph(self, blocks=10, size=100, self_block_connectivity=0.9, other_block_connectivity=0.1, connectivity_matrix=None, directed=False, self_edges=False, power_exp=None, scale=None, plot_stat=False): size = size if isinstance(size, list) else [size] self_block_connectivity = self_block_connectivity if isinstance(self_block_connectivity, list) else [self_block_connectivity] other_block_connectivity = other_block_connectivity if isinstance(other_block_connectivity, list) else [other_block_connectivity] num_nodes = sum([size[i % len(size)] for i in xrange(blocks)]) if power_exp is None: self.print_f("Starting to create Stochastic Blockmodel Graph with {} nodes and {} blocks".format(num_nodes, blocks)) else: self.print_f("Starting to create degree-corrected (alpha=" + str(power_exp) + ") Stochastic Blockmodel Graph with {} nodes and {} blocks".format(num_nodes, blocks)) self.print_f('convert/transform probabilities') blocks_range = range(blocks) block_sizes = np.array([size[i % len(size)] for i in blocks_range]) # create connectivity matrix of self- and other-block-connectivity if connectivity_matrix is None: connectivity_matrix = [] self.print_f('inner conn: ' + str(self_block_connectivity) + '\tother conn: ' + str(other_block_connectivity)) for idx in blocks_range: row = [] for jdx in blocks_range: if idx == jdx: row.append(self_block_connectivity[idx % len(self_block_connectivity)]) else: if scale is not None: prob = other_block_connectivity[idx % len(other_block_connectivity)] / (num_nodes - block_sizes[idx]) * block_sizes[jdx] if directed: row.append(prob) else: row.append(prob / 2) else: row.append(other_block_connectivity[idx % len(other_block_connectivity)]) connectivity_matrix.append(row) # convert con-matrix to np.array if connectivity_matrix is not None and isinstance(connectivity_matrix, np.matrix): connectivity_matrix = np.asarray(connectivity_matrix) # convert con-matrix to np.array if connectivity_matrix is not None and not isinstance(connectivity_matrix, np.ndarray): connectivity_matrix = np.array(connectivity_matrix) self.print_f('conn mat') printing.print_matrix(connectivity_matrix) if scale == 'relative' or scale == 'absolute': new_connectivity_matrix = [] for i in blocks_range: connectivity_row = connectivity_matrix[i, :] if connectivity_matrix is not None else None nodes_in_src_block = block_sizes[i] multp = 1 if scale == 'absolute' else (nodes_in_src_block * (nodes_in_src_block - 1)) row_prob = [(connectivity_row[idx] * multp) / (nodes_in_src_block * (nodes_in_block - 1)) for idx, nodes_in_block in enumerate(block_sizes)] new_connectivity_matrix.append(np.array(row_prob)) connectivity_matrix = np.array(new_connectivity_matrix) self.print_f(scale + ' scaled conn mat:') printing.print_matrix(connectivity_matrix) # create nodes and store corresponding block-id self.print_f('insert nodes') vertex_to_block = [] appender = vertex_to_block.append colors = self.graph.new_vertex_property("float") for i in xrange(blocks): block_size = size[i % len(size)] for j in xrange(block_size): appender((self.graph.add_vertex(), i)) node = vertex_to_block[-1][0] colors[node] = i # create edges get_rand = np.random.random add_edge = self.graph.add_edge self.print_f('create edge probs') degree_probs = defaultdict(lambda: dict()) for vertex, block_id in vertex_to_block: if power_exp is None: degree_probs[block_id][vertex] = 1 else: degree_probs[block_id][vertex] = math.exp(power_exp * np.random.random()) tmp = dict() self.print_f('normalize edge probs') all_prop = [] for block_id, node_to_prop in degree_probs.iteritems(): sum_of_block_norm = 1 / sum(node_to_prop.values()) tmp[block_id] = {key: val * sum_of_block_norm for key, val in node_to_prop.iteritems()} all_prop.append(tmp[block_id].values()) degree_probs = tmp if plot_stat: plt.clf() plt.hist(all_prop, bins=15) plt.savefig("prop_dist.png") plt.close('all') self.print_f('count edges between blocks') edges_between_blocks = defaultdict(lambda: defaultdict(int)) for idx, (src_node, src_block) in enumerate(vertex_to_block): conn_mat_row = connectivity_matrix[src_block, :] for dest_node, dest_block in vertex_to_block: if get_rand() < conn_mat_row[dest_block]: edges_between_blocks[src_block][dest_block] += 1 self.print_f('create edges') for src_block, dest_dict in edges_between_blocks.iteritems(): self.print_f(' -- Processing Block {}. Creating links to: {}'.format(src_block, dest_dict)) for dest_block, num_edges in dest_dict.iteritems(): self.print_f(' ++ adding {} edges to {}'.format(num_edges, dest_block)) for i in xrange(num_edges): # find src node prob = np.random.random() prob_sum = 0 src_node = None for vertex, v_prob in degree_probs[src_block].iteritems(): prob_sum += v_prob if prob_sum >= prob: src_node = vertex break # find dest node prob = np.random.random() prob_sum = 0 dest_node = None for vertex, v_prob in degree_probs[dest_block].iteritems(): prob_sum += v_prob if prob_sum >= prob: dest_node = vertex break if src_node is None or dest_node is None: print 'Error selecting node:', src_node, dest_node if self.graph.edge(src_node, dest_node) is None: if self_edges or not src_node == dest_node: add_edge(src_node, dest_node) self.graph.vertex_properties["colorsComm"] = colors return self.return_and_reset()
import sympy as sym from printing import print_matrix Rat = sym.Rational Mat = sym.Matrix Sym = sym.symbols m = Mat([[Rat(1,2), Rat(1,2), 0], [Rat(1,6), Rat(2,3), Rat(1,6)], [0, Rat(1,2), Rat(1,2)]]) [P,D] = m.diagonalize() print_matrix(P) print_matrix(D) K = P * Mat([[0,0,0],[0,0,0],[0,0,1]]) * P.inv() print_matrix(K) C = [1, 5, 9] c = [1, 5, 9] for i in range(100): c = [(c[0]+c[1])/2, c[0]/6 + 2*c[1]/3 + c[2]/6, (c[1]+c[2])/2] print(c[1]) print(C[0]/5 + 3*C[1]/5 + C[2]/5)
scale_dir *= 1 / sqrt(sum(x**2 for x in scale_dir)) scale = random.uniform(0, 0.5) points = np.array([[scales[i] * np.random.normal(0, 1) for i in range(3)] for __ in range(n)]) for row in range(points.shape[0]): points[row, :] = points[ row, :] + (scale - 1) * scale_dir * points[row, :].dot(scale_dir) # print_matrix(sym.Matrix(points)) mean = 1 / n * sum(points[row, :] for row in range(points.shape[0])) # C = 1/n * sum(np.outer(points[row,:] - mean, points[row,:] - mean) for row in range(points.shape[0])) centralized_points = np.array( [points[row, :] - mean for row in range(points.shape[0])]) C = (1 / n) * centralized_points.T.dot( centralized_points) # Easier way to write the above. print_matrix(Mat(C)) print("det(C) =", linalg.det(C)) U, s, Vh = linalg.svd(C) # Compute principal plane. C2 = sum(s[i] * np.outer(U[:, i], Vh[i, :].T) for i in range(2)) print_matrix(Mat(C2)) print("det(C2) =", linalg.det(C2)) # Should be 0. fig = plt.figure() ax = plt.gca(projection="3d") X = U[:, 0] Y = U[:, 1] plane_points = np.array([ x * X + y * Y + mean for x, y in np.mgrid[-3:3:25j, -3:3:25j].reshape(2, -1).T