Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
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))
Ejemplo n.º 4
0
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)]
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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")
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
0

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)
Ejemplo n.º 9
0
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")
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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)))))
Ejemplo n.º 12
0
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())
Ejemplo n.º 13
0
    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()
Ejemplo n.º 14
0
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)





Ejemplo n.º 15
0
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