Buckets:
MisterAI/LocalAI_Demo_backends / cpu-diffusers.upgrade-tmp /venv /lib /python3.10 /site-packages /sympy /integrals /intpoly.py
| """ | |
| Module to implement integration of uni/bivariate polynomials over | |
| 2D Polytopes and uni/bi/trivariate polynomials over 3D Polytopes. | |
| Uses evaluation techniques as described in Chin et al. (2015) [1]. | |
| References | |
| =========== | |
| .. [1] Chin, Eric B., Jean B. Lasserre, and N. Sukumar. "Numerical integration | |
| of homogeneous functions on convex and nonconvex polygons and polyhedra." | |
| Computational Mechanics 56.6 (2015): 967-981 | |
| PDF link : http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf | |
| """ | |
| from functools import cmp_to_key | |
| from sympy.abc import x, y, z | |
| from sympy.core import S, diff, Expr, Symbol | |
| from sympy.core.sympify import _sympify | |
| from sympy.geometry import Segment2D, Polygon, Point, Point2D | |
| from sympy.polys.polytools import LC, gcd_list, degree_list, Poly | |
| from sympy.simplify.simplify import nsimplify | |
| def polytope_integrate(poly, expr=None, *, clockwise=False, max_degree=None): | |
| """Integrates polynomials over 2/3-Polytopes. | |
| Explanation | |
| =========== | |
| This function accepts the polytope in ``poly`` and the function in ``expr`` | |
| (uni/bi/trivariate polynomials are implemented) and returns | |
| the exact integral of ``expr`` over ``poly``. | |
| Parameters | |
| ========== | |
| poly : The input Polygon. | |
| expr : The input polynomial. | |
| clockwise : Binary value to sort input points of 2-Polytope clockwise.(Optional) | |
| max_degree : The maximum degree of any monomial of the input polynomial.(Optional) | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import Point, Polygon | |
| >>> from sympy.integrals.intpoly import polytope_integrate | |
| >>> polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) | |
| >>> polys = [1, x, y, x*y, x**2*y, x*y**2] | |
| >>> expr = x*y | |
| >>> polytope_integrate(polygon, expr) | |
| 1/4 | |
| >>> polytope_integrate(polygon, polys, max_degree=3) | |
| {1: 1, x: 1/2, y: 1/2, x*y: 1/4, x*y**2: 1/6, x**2*y: 1/6} | |
| """ | |
| if clockwise: | |
| if isinstance(poly, Polygon): | |
| poly = Polygon(*point_sort(poly.vertices), evaluate=False) | |
| else: | |
| raise TypeError("clockwise=True works for only 2-Polytope" | |
| "V-representation input") | |
| if isinstance(poly, Polygon): | |
| # For Vertex Representation(2D case) | |
| hp_params = hyperplane_parameters(poly) | |
| facets = poly.sides | |
| elif len(poly[0]) == 2: | |
| # For Hyperplane Representation(2D case) | |
| plen = len(poly) | |
| if len(poly[0][0]) == 2: | |
| intersections = [intersection(poly[(i - 1) % plen], poly[i], | |
| "plane2D") | |
| for i in range(0, plen)] | |
| hp_params = poly | |
| lints = len(intersections) | |
| facets = [Segment2D(intersections[i], | |
| intersections[(i + 1) % lints]) | |
| for i in range(lints)] | |
| else: | |
| raise NotImplementedError("Integration for H-representation 3D" | |
| "case not implemented yet.") | |
| else: | |
| # For Vertex Representation(3D case) | |
| vertices = poly[0] | |
| facets = poly[1:] | |
| hp_params = hyperplane_parameters(facets, vertices) | |
| if max_degree is None: | |
| if expr is None: | |
| raise TypeError('Input expression must be a valid SymPy expression') | |
| return main_integrate3d(expr, facets, vertices, hp_params) | |
| if max_degree is not None: | |
| result = {} | |
| if expr is not None: | |
| f_expr = [] | |
| for e in expr: | |
| _ = decompose(e) | |
| if len(_) == 1 and not _.popitem()[0]: | |
| f_expr.append(e) | |
| elif Poly(e).total_degree() <= max_degree: | |
| f_expr.append(e) | |
| expr = f_expr | |
| if not isinstance(expr, list) and expr is not None: | |
| raise TypeError('Input polynomials must be list of expressions') | |
| if len(hp_params[0][0]) == 3: | |
| result_dict = main_integrate3d(0, facets, vertices, hp_params, | |
| max_degree) | |
| else: | |
| result_dict = main_integrate(0, facets, hp_params, max_degree) | |
| if expr is None: | |
| return result_dict | |
| for poly in expr: | |
| poly = _sympify(poly) | |
| if poly not in result: | |
| if poly.is_zero: | |
| result[S.Zero] = S.Zero | |
| continue | |
| integral_value = S.Zero | |
| monoms = decompose(poly, separate=True) | |
| for monom in monoms: | |
| monom = nsimplify(monom) | |
| coeff, m = strip(monom) | |
| integral_value += result_dict[m] * coeff | |
| result[poly] = integral_value | |
| return result | |
| if expr is None: | |
| raise TypeError('Input expression must be a valid SymPy expression') | |
| return main_integrate(expr, facets, hp_params) | |
| def strip(monom): | |
| if monom.is_zero: | |
| return S.Zero, S.Zero | |
| elif monom.is_number: | |
| return monom, S.One | |
| else: | |
| coeff = LC(monom) | |
| return coeff, monom / coeff | |
| def _polynomial_integrate(polynomials, facets, hp_params): | |
| dims = (x, y) | |
| dim_length = len(dims) | |
| integral_value = S.Zero | |
| for deg in polynomials: | |
| poly_contribute = S.Zero | |
| facet_count = 0 | |
| for hp in hp_params: | |
| value_over_boundary = integration_reduction(facets, | |
| facet_count, | |
| hp[0], hp[1], | |
| polynomials[deg], | |
| dims, deg) | |
| poly_contribute += value_over_boundary * (hp[1] / norm(hp[0])) | |
| facet_count += 1 | |
| poly_contribute /= (dim_length + deg) | |
| integral_value += poly_contribute | |
| return integral_value | |
| def main_integrate3d(expr, facets, vertices, hp_params, max_degree=None): | |
| """Function to translate the problem of integrating uni/bi/tri-variate | |
| polynomials over a 3-Polytope to integrating over its faces. | |
| This is done using Generalized Stokes' Theorem and Euler's Theorem. | |
| Parameters | |
| ========== | |
| expr : | |
| The input polynomial. | |
| facets : | |
| Faces of the 3-Polytope(expressed as indices of `vertices`). | |
| vertices : | |
| Vertices that constitute the Polytope. | |
| hp_params : | |
| Hyperplane Parameters of the facets. | |
| max_degree : optional | |
| Max degree of constituent monomial in given list of polynomial. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import main_integrate3d, \ | |
| hyperplane_parameters | |
| >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ | |
| (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ | |
| [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ | |
| [3, 1, 0, 2], [0, 4, 6, 2]] | |
| >>> vertices = cube[0] | |
| >>> faces = cube[1:] | |
| >>> hp_params = hyperplane_parameters(faces, vertices) | |
| >>> main_integrate3d(1, faces, vertices, hp_params) | |
| -125 | |
| """ | |
| result = {} | |
| dims = (x, y, z) | |
| dim_length = len(dims) | |
| if max_degree: | |
| grad_terms = gradient_terms(max_degree, 3) | |
| flat_list = [term for z_terms in grad_terms | |
| for x_term in z_terms | |
| for term in x_term] | |
| for term in flat_list: | |
| result[term[0]] = 0 | |
| for facet_count, hp in enumerate(hp_params): | |
| a, b = hp[0], hp[1] | |
| x0 = vertices[facets[facet_count][0]] | |
| for i, monom in enumerate(flat_list): | |
| # Every monomial is a tuple : | |
| # (term, x_degree, y_degree, z_degree, value over boundary) | |
| expr, x_d, y_d, z_d, z_index, y_index, x_index, _ = monom | |
| degree = x_d + y_d + z_d | |
| if b.is_zero: | |
| value_over_face = S.Zero | |
| else: | |
| value_over_face = \ | |
| integration_reduction_dynamic(facets, facet_count, a, | |
| b, expr, degree, dims, | |
| x_index, y_index, | |
| z_index, x0, grad_terms, | |
| i, vertices, hp) | |
| monom[7] = value_over_face | |
| result[expr] += value_over_face * \ | |
| (b / norm(a)) / (dim_length + x_d + y_d + z_d) | |
| return result | |
| else: | |
| integral_value = S.Zero | |
| polynomials = decompose(expr) | |
| for deg in polynomials: | |
| poly_contribute = S.Zero | |
| facet_count = 0 | |
| for i, facet in enumerate(facets): | |
| hp = hp_params[i] | |
| if hp[1].is_zero: | |
| continue | |
| pi = polygon_integrate(facet, hp, i, facets, vertices, expr, deg) | |
| poly_contribute += pi *\ | |
| (hp[1] / norm(tuple(hp[0]))) | |
| facet_count += 1 | |
| poly_contribute /= (dim_length + deg) | |
| integral_value += poly_contribute | |
| return integral_value | |
| def main_integrate(expr, facets, hp_params, max_degree=None): | |
| """Function to translate the problem of integrating univariate/bivariate | |
| polynomials over a 2-Polytope to integrating over its boundary facets. | |
| This is done using Generalized Stokes's Theorem and Euler's Theorem. | |
| Parameters | |
| ========== | |
| expr : | |
| The input polynomial. | |
| facets : | |
| Facets(Line Segments) of the 2-Polytope. | |
| hp_params : | |
| Hyperplane Parameters of the facets. | |
| max_degree : optional | |
| The maximum degree of any monomial of the input polynomial. | |
| >>> from sympy.abc import x, y | |
| >>> from sympy.integrals.intpoly import main_integrate,\ | |
| hyperplane_parameters | |
| >>> from sympy import Point, Polygon | |
| >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) | |
| >>> facets = triangle.sides | |
| >>> hp_params = hyperplane_parameters(triangle) | |
| >>> main_integrate(x**2 + y**2, facets, hp_params) | |
| 325/6 | |
| """ | |
| dims = (x, y) | |
| dim_length = len(dims) | |
| result = {} | |
| if max_degree: | |
| grad_terms = [[0, 0, 0, 0]] + gradient_terms(max_degree) | |
| for facet_count, hp in enumerate(hp_params): | |
| a, b = hp[0], hp[1] | |
| x0 = facets[facet_count].points[0] | |
| for i, monom in enumerate(grad_terms): | |
| # Every monomial is a tuple : | |
| # (term, x_degree, y_degree, value over boundary) | |
| m, x_d, y_d, _ = monom | |
| value = result.get(m, None) | |
| degree = S.Zero | |
| if b.is_zero: | |
| value_over_boundary = S.Zero | |
| else: | |
| degree = x_d + y_d | |
| value_over_boundary = \ | |
| integration_reduction_dynamic(facets, facet_count, a, | |
| b, m, degree, dims, x_d, | |
| y_d, max_degree, x0, | |
| grad_terms, i) | |
| monom[3] = value_over_boundary | |
| if value is not None: | |
| result[m] += value_over_boundary * \ | |
| (b / norm(a)) / (dim_length + degree) | |
| else: | |
| result[m] = value_over_boundary * \ | |
| (b / norm(a)) / (dim_length + degree) | |
| return result | |
| else: | |
| if not isinstance(expr, list): | |
| polynomials = decompose(expr) | |
| return _polynomial_integrate(polynomials, facets, hp_params) | |
| else: | |
| return {e: _polynomial_integrate(decompose(e), facets, hp_params) for e in expr} | |
| def polygon_integrate(facet, hp_param, index, facets, vertices, expr, degree): | |
| """Helper function to integrate the input uni/bi/trivariate polynomial | |
| over a certain face of the 3-Polytope. | |
| Parameters | |
| ========== | |
| facet : | |
| Particular face of the 3-Polytope over which ``expr`` is integrated. | |
| index : | |
| The index of ``facet`` in ``facets``. | |
| facets : | |
| Faces of the 3-Polytope(expressed as indices of `vertices`). | |
| vertices : | |
| Vertices that constitute the facet. | |
| expr : | |
| The input polynomial. | |
| degree : | |
| Degree of ``expr``. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import polygon_integrate | |
| >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ | |
| (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ | |
| [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ | |
| [3, 1, 0, 2], [0, 4, 6, 2]] | |
| >>> facet = cube[1] | |
| >>> facets = cube[1:] | |
| >>> vertices = cube[0] | |
| >>> polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) | |
| -25 | |
| """ | |
| expr = S(expr) | |
| if expr.is_zero: | |
| return S.Zero | |
| result = S.Zero | |
| x0 = vertices[facet[0]] | |
| facet_len = len(facet) | |
| for i, fac in enumerate(facet): | |
| side = (vertices[fac], vertices[facet[(i + 1) % facet_len]]) | |
| result += distance_to_side(x0, side, hp_param[0]) *\ | |
| lineseg_integrate(facet, i, side, expr, degree) | |
| if not expr.is_number: | |
| expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ | |
| diff(expr, z) * x0[2] | |
| result += polygon_integrate(facet, hp_param, index, facets, vertices, | |
| expr, degree - 1) | |
| result /= (degree + 2) | |
| return result | |
| def distance_to_side(point, line_seg, A): | |
| """Helper function to compute the signed distance between given 3D point | |
| and a line segment. | |
| Parameters | |
| ========== | |
| point : 3D Point | |
| line_seg : Line Segment | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import distance_to_side | |
| >>> point = (0, 0, 0) | |
| >>> distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) | |
| -sqrt(2)/2 | |
| """ | |
| x1, x2 = line_seg | |
| rev_normal = [-1 * S(i)/norm(A) for i in A] | |
| vector = [x2[i] - x1[i] for i in range(0, 3)] | |
| vector = [vector[i]/norm(vector) for i in range(0, 3)] | |
| n_side = cross_product((0, 0, 0), rev_normal, vector) | |
| vectorx0 = [line_seg[0][i] - point[i] for i in range(0, 3)] | |
| dot_product = sum(vectorx0[i] * n_side[i] for i in range(0, 3)) | |
| return dot_product | |
| def lineseg_integrate(polygon, index, line_seg, expr, degree): | |
| """Helper function to compute the line integral of ``expr`` over ``line_seg``. | |
| Parameters | |
| =========== | |
| polygon : | |
| Face of a 3-Polytope. | |
| index : | |
| Index of line_seg in polygon. | |
| line_seg : | |
| Line Segment. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import lineseg_integrate | |
| >>> polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)] | |
| >>> line_seg = [(0, 5, 0), (5, 5, 0)] | |
| >>> lineseg_integrate(polygon, 0, line_seg, 1, 0) | |
| 5 | |
| """ | |
| expr = _sympify(expr) | |
| if expr.is_zero: | |
| return S.Zero | |
| result = S.Zero | |
| x0 = line_seg[0] | |
| distance = norm(tuple([line_seg[1][i] - line_seg[0][i] for i in | |
| range(3)])) | |
| if isinstance(expr, Expr): | |
| expr_dict = {x: line_seg[1][0], | |
| y: line_seg[1][1], | |
| z: line_seg[1][2]} | |
| result += distance * expr.subs(expr_dict) | |
| else: | |
| result += distance * expr | |
| expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ | |
| diff(expr, z) * x0[2] | |
| result += lineseg_integrate(polygon, index, line_seg, expr, degree - 1) | |
| result /= (degree + 1) | |
| return result | |
| def integration_reduction(facets, index, a, b, expr, dims, degree): | |
| """Helper method for main_integrate. Returns the value of the input | |
| expression evaluated over the polytope facet referenced by a given index. | |
| Parameters | |
| =========== | |
| facets : | |
| List of facets of the polytope. | |
| index : | |
| Index referencing the facet to integrate the expression over. | |
| a : | |
| Hyperplane parameter denoting direction. | |
| b : | |
| Hyperplane parameter denoting distance. | |
| expr : | |
| The expression to integrate over the facet. | |
| dims : | |
| List of symbols denoting axes. | |
| degree : | |
| Degree of the homogeneous polynomial. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy.integrals.intpoly import integration_reduction,\ | |
| hyperplane_parameters | |
| >>> from sympy import Point, Polygon | |
| >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) | |
| >>> facets = triangle.sides | |
| >>> a, b = hyperplane_parameters(triangle)[0] | |
| >>> integration_reduction(facets, 0, a, b, 1, (x, y), 0) | |
| 5 | |
| """ | |
| expr = _sympify(expr) | |
| if expr.is_zero: | |
| return expr | |
| value = S.Zero | |
| x0 = facets[index].points[0] | |
| m = len(facets) | |
| gens = (x, y) | |
| inner_product = diff(expr, gens[0]) * x0[0] + diff(expr, gens[1]) * x0[1] | |
| if inner_product != 0: | |
| value += integration_reduction(facets, index, a, b, | |
| inner_product, dims, degree - 1) | |
| value += left_integral2D(m, index, facets, x0, expr, gens) | |
| return value/(len(dims) + degree - 1) | |
| def left_integral2D(m, index, facets, x0, expr, gens): | |
| """Computes the left integral of Eq 10 in Chin et al. | |
| For the 2D case, the integral is just an evaluation of the polynomial | |
| at the intersection of two facets which is multiplied by the distance | |
| between the first point of facet and that intersection. | |
| Parameters | |
| ========== | |
| m : | |
| No. of hyperplanes. | |
| index : | |
| Index of facet to find intersections with. | |
| facets : | |
| List of facets(Line Segments in 2D case). | |
| x0 : | |
| First point on facet referenced by index. | |
| expr : | |
| Input polynomial | |
| gens : | |
| Generators which generate the polynomial | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy.integrals.intpoly import left_integral2D | |
| >>> from sympy import Point, Polygon | |
| >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) | |
| >>> facets = triangle.sides | |
| >>> left_integral2D(3, 0, facets, facets[0].points[0], 1, (x, y)) | |
| 5 | |
| """ | |
| value = S.Zero | |
| for j in range(m): | |
| intersect = () | |
| if j in ((index - 1) % m, (index + 1) % m): | |
| intersect = intersection(facets[index], facets[j], "segment2D") | |
| if intersect: | |
| distance_origin = norm(tuple(map(lambda x, y: x - y, | |
| intersect, x0))) | |
| if is_vertex(intersect): | |
| if isinstance(expr, Expr): | |
| if len(gens) == 3: | |
| expr_dict = {gens[0]: intersect[0], | |
| gens[1]: intersect[1], | |
| gens[2]: intersect[2]} | |
| else: | |
| expr_dict = {gens[0]: intersect[0], | |
| gens[1]: intersect[1]} | |
| value += distance_origin * expr.subs(expr_dict) | |
| else: | |
| value += distance_origin * expr | |
| return value | |
| def integration_reduction_dynamic(facets, index, a, b, expr, degree, dims, | |
| x_index, y_index, max_index, x0, | |
| monomial_values, monom_index, vertices=None, | |
| hp_param=None): | |
| """The same integration_reduction function which uses a dynamic | |
| programming approach to compute terms by using the values of the integral | |
| of previously computed terms. | |
| Parameters | |
| ========== | |
| facets : | |
| Facets of the Polytope. | |
| index : | |
| Index of facet to find intersections with.(Used in left_integral()). | |
| a, b : | |
| Hyperplane parameters. | |
| expr : | |
| Input monomial. | |
| degree : | |
| Total degree of ``expr``. | |
| dims : | |
| Tuple denoting axes variables. | |
| x_index : | |
| Exponent of 'x' in ``expr``. | |
| y_index : | |
| Exponent of 'y' in ``expr``. | |
| max_index : | |
| Maximum exponent of any monomial in ``monomial_values``. | |
| x0 : | |
| First point on ``facets[index]``. | |
| monomial_values : | |
| List of monomial values constituting the polynomial. | |
| monom_index : | |
| Index of monomial whose integration is being found. | |
| vertices : optional | |
| Coordinates of vertices constituting the 3-Polytope. | |
| hp_param : optional | |
| Hyperplane Parameter of the face of the facets[index]. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy.integrals.intpoly import (integration_reduction_dynamic, \ | |
| hyperplane_parameters) | |
| >>> from sympy import Point, Polygon | |
| >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) | |
| >>> facets = triangle.sides | |
| >>> a, b = hyperplane_parameters(triangle)[0] | |
| >>> x0 = facets[0].points[0] | |
| >>> monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\ | |
| [y, 0, 1, 15], [x, 1, 0, None]] | |
| >>> integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1, 0, 1,\ | |
| x0, monomial_values, 3) | |
| 25/2 | |
| """ | |
| value = S.Zero | |
| m = len(facets) | |
| if expr == S.Zero: | |
| return expr | |
| if len(dims) == 2: | |
| if not expr.is_number: | |
| _, x_degree, y_degree, _ = monomial_values[monom_index] | |
| x_index = monom_index - max_index + \ | |
| x_index - 2 if x_degree > 0 else 0 | |
| y_index = monom_index - 1 if y_degree > 0 else 0 | |
| x_value, y_value =\ | |
| monomial_values[x_index][3], monomial_values[y_index][3] | |
| value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] | |
| value += left_integral2D(m, index, facets, x0, expr, dims) | |
| else: | |
| # For 3D use case the max_index contains the z_degree of the term | |
| z_index = max_index | |
| if not expr.is_number: | |
| x_degree, y_degree, z_degree = y_index,\ | |
| z_index - x_index - y_index, x_index | |
| x_value = monomial_values[z_index - 1][y_index - 1][x_index][7]\ | |
| if x_degree > 0 else 0 | |
| y_value = monomial_values[z_index - 1][y_index][x_index][7]\ | |
| if y_degree > 0 else 0 | |
| z_value = monomial_values[z_index - 1][y_index][x_index - 1][7]\ | |
| if z_degree > 0 else 0 | |
| value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] \ | |
| + z_degree * z_value * x0[2] | |
| value += left_integral3D(facets, index, expr, | |
| vertices, hp_param, degree) | |
| return value / (len(dims) + degree - 1) | |
| def left_integral3D(facets, index, expr, vertices, hp_param, degree): | |
| """Computes the left integral of Eq 10 in Chin et al. | |
| Explanation | |
| =========== | |
| For the 3D case, this is the sum of the integral values over constituting | |
| line segments of the face (which is accessed by facets[index]) multiplied | |
| by the distance between the first point of facet and that line segment. | |
| Parameters | |
| ========== | |
| facets : | |
| List of faces of the 3-Polytope. | |
| index : | |
| Index of face over which integral is to be calculated. | |
| expr : | |
| Input polynomial. | |
| vertices : | |
| List of vertices that constitute the 3-Polytope. | |
| hp_param : | |
| The hyperplane parameters of the face. | |
| degree : | |
| Degree of the ``expr``. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import left_integral3D | |
| >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ | |
| (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ | |
| [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ | |
| [3, 1, 0, 2], [0, 4, 6, 2]] | |
| >>> facets = cube[1:] | |
| >>> vertices = cube[0] | |
| >>> left_integral3D(facets, 3, 1, vertices, ([0, -1, 0], -5), 0) | |
| -50 | |
| """ | |
| value = S.Zero | |
| facet = facets[index] | |
| x0 = vertices[facet[0]] | |
| facet_len = len(facet) | |
| for i, fac in enumerate(facet): | |
| side = (vertices[fac], vertices[facet[(i + 1) % facet_len]]) | |
| value += distance_to_side(x0, side, hp_param[0]) * \ | |
| lineseg_integrate(facet, i, side, expr, degree) | |
| return value | |
| def gradient_terms(binomial_power=0, no_of_gens=2): | |
| """Returns a list of all the possible monomials between | |
| 0 and y**binomial_power for 2D case and z**binomial_power | |
| for 3D case. | |
| Parameters | |
| ========== | |
| binomial_power : | |
| Power upto which terms are generated. | |
| no_of_gens : | |
| Denotes whether terms are being generated for 2D or 3D case. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import gradient_terms | |
| >>> gradient_terms(2) | |
| [[1, 0, 0, 0], [y, 0, 1, 0], [y**2, 0, 2, 0], [x, 1, 0, 0], | |
| [x*y, 1, 1, 0], [x**2, 2, 0, 0]] | |
| >>> gradient_terms(2, 3) | |
| [[[[1, 0, 0, 0, 0, 0, 0, 0]]], [[[y, 0, 1, 0, 1, 0, 0, 0], | |
| [z, 0, 0, 1, 1, 0, 1, 0]], [[x, 1, 0, 0, 1, 1, 0, 0]]], | |
| [[[y**2, 0, 2, 0, 2, 0, 0, 0], [y*z, 0, 1, 1, 2, 0, 1, 0], | |
| [z**2, 0, 0, 2, 2, 0, 2, 0]], [[x*y, 1, 1, 0, 2, 1, 0, 0], | |
| [x*z, 1, 0, 1, 2, 1, 1, 0]], [[x**2, 2, 0, 0, 2, 2, 0, 0]]]] | |
| """ | |
| if no_of_gens == 2: | |
| count = 0 | |
| terms = [None] * int((binomial_power ** 2 + 3 * binomial_power + 2) / 2) | |
| for x_count in range(0, binomial_power + 1): | |
| for y_count in range(0, binomial_power - x_count + 1): | |
| terms[count] = [x**x_count*y**y_count, | |
| x_count, y_count, 0] | |
| count += 1 | |
| else: | |
| terms = [[[[x ** x_count * y ** y_count * | |
| z ** (z_count - y_count - x_count), | |
| x_count, y_count, z_count - y_count - x_count, | |
| z_count, x_count, z_count - y_count - x_count, 0] | |
| for y_count in range(z_count - x_count, -1, -1)] | |
| for x_count in range(0, z_count + 1)] | |
| for z_count in range(0, binomial_power + 1)] | |
| return terms | |
| def hyperplane_parameters(poly, vertices=None): | |
| """A helper function to return the hyperplane parameters | |
| of which the facets of the polytope are a part of. | |
| Parameters | |
| ========== | |
| poly : | |
| The input 2/3-Polytope. | |
| vertices : | |
| Vertex indices of 3-Polytope. | |
| Examples | |
| ======== | |
| >>> from sympy import Point, Polygon | |
| >>> from sympy.integrals.intpoly import hyperplane_parameters | |
| >>> hyperplane_parameters(Polygon(Point(0, 3), Point(5, 3), Point(1, 1))) | |
| [((0, 1), 3), ((1, -2), -1), ((-2, -1), -3)] | |
| >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ | |
| (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ | |
| [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ | |
| [3, 1, 0, 2], [0, 4, 6, 2]] | |
| >>> hyperplane_parameters(cube[1:], cube[0]) | |
| [([0, -1, 0], -5), ([0, 0, -1], -5), ([-1, 0, 0], -5), | |
| ([0, 1, 0], 0), ([1, 0, 0], 0), ([0, 0, 1], 0)] | |
| """ | |
| if isinstance(poly, Polygon): | |
| vertices = list(poly.vertices) + [poly.vertices[0]] # Close the polygon | |
| params = [None] * (len(vertices) - 1) | |
| for i in range(len(vertices) - 1): | |
| v1 = vertices[i] | |
| v2 = vertices[i + 1] | |
| a1 = v1[1] - v2[1] | |
| a2 = v2[0] - v1[0] | |
| b = v2[0] * v1[1] - v2[1] * v1[0] | |
| factor = gcd_list([a1, a2, b]) | |
| b = S(b) / factor | |
| a = (S(a1) / factor, S(a2) / factor) | |
| params[i] = (a, b) | |
| else: | |
| params = [None] * len(poly) | |
| for i, polygon in enumerate(poly): | |
| v1, v2, v3 = [vertices[vertex] for vertex in polygon[:3]] | |
| normal = cross_product(v1, v2, v3) | |
| b = sum(normal[j] * v1[j] for j in range(0, 3)) | |
| fac = gcd_list(normal) | |
| if fac.is_zero: | |
| fac = 1 | |
| normal = [j / fac for j in normal] | |
| b = b / fac | |
| params[i] = (normal, b) | |
| return params | |
| def cross_product(v1, v2, v3): | |
| """Returns the cross-product of vectors (v2 - v1) and (v3 - v1) | |
| That is : (v2 - v1) X (v3 - v1) | |
| """ | |
| v2 = [v2[j] - v1[j] for j in range(0, 3)] | |
| v3 = [v3[j] - v1[j] for j in range(0, 3)] | |
| return [v3[2] * v2[1] - v3[1] * v2[2], | |
| v3[0] * v2[2] - v3[2] * v2[0], | |
| v3[1] * v2[0] - v3[0] * v2[1]] | |
| def best_origin(a, b, lineseg, expr): | |
| """Helper method for polytope_integrate. Currently not used in the main | |
| algorithm. | |
| Explanation | |
| =========== | |
| Returns a point on the lineseg whose vector inner product with the | |
| divergence of `expr` yields an expression with the least maximum | |
| total power. | |
| Parameters | |
| ========== | |
| a : | |
| Hyperplane parameter denoting direction. | |
| b : | |
| Hyperplane parameter denoting distance. | |
| lineseg : | |
| Line segment on which to find the origin. | |
| expr : | |
| The expression which determines the best point. | |
| Algorithm(currently works only for 2D use case) | |
| =============================================== | |
| 1 > Firstly, check for edge cases. Here that would refer to vertical | |
| or horizontal lines. | |
| 2 > If input expression is a polynomial containing more than one generator | |
| then find out the total power of each of the generators. | |
| x**2 + 3 + x*y + x**4*y**5 ---> {x: 7, y: 6} | |
| If expression is a constant value then pick the first boundary point | |
| of the line segment. | |
| 3 > First check if a point exists on the line segment where the value of | |
| the highest power generator becomes 0. If not check if the value of | |
| the next highest becomes 0. If none becomes 0 within line segment | |
| constraints then pick the first boundary point of the line segment. | |
| Actually, any point lying on the segment can be picked as best origin | |
| in the last case. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import best_origin | |
| >>> from sympy.abc import x, y | |
| >>> from sympy import Point, Segment2D | |
| >>> l = Segment2D(Point(0, 3), Point(1, 1)) | |
| >>> expr = x**3*y**7 | |
| >>> best_origin((2, 1), 3, l, expr) | |
| (0, 3.0) | |
| """ | |
| a1, b1 = lineseg.points[0] | |
| def x_axis_cut(ls): | |
| """Returns the point where the input line segment | |
| intersects the x-axis. | |
| Parameters | |
| ========== | |
| ls : | |
| Line segment | |
| """ | |
| p, q = ls.points | |
| if p.y.is_zero: | |
| return tuple(p) | |
| elif q.y.is_zero: | |
| return tuple(q) | |
| elif p.y/q.y < S.Zero: | |
| return p.y * (p.x - q.x)/(q.y - p.y) + p.x, S.Zero | |
| else: | |
| return () | |
| def y_axis_cut(ls): | |
| """Returns the point where the input line segment | |
| intersects the y-axis. | |
| Parameters | |
| ========== | |
| ls : | |
| Line segment | |
| """ | |
| p, q = ls.points | |
| if p.x.is_zero: | |
| return tuple(p) | |
| elif q.x.is_zero: | |
| return tuple(q) | |
| elif p.x/q.x < S.Zero: | |
| return S.Zero, p.x * (p.y - q.y)/(q.x - p.x) + p.y | |
| else: | |
| return () | |
| gens = (x, y) | |
| power_gens = {} | |
| for i in gens: | |
| power_gens[i] = S.Zero | |
| if len(gens) > 1: | |
| # Special case for vertical and horizontal lines | |
| if len(gens) == 2: | |
| if a[0] == 0: | |
| if y_axis_cut(lineseg): | |
| return S.Zero, b/a[1] | |
| else: | |
| return a1, b1 | |
| elif a[1] == 0: | |
| if x_axis_cut(lineseg): | |
| return b/a[0], S.Zero | |
| else: | |
| return a1, b1 | |
| if isinstance(expr, Expr): # Find the sum total of power of each | |
| if expr.is_Add: # generator and store in a dictionary. | |
| for monomial in expr.args: | |
| if monomial.is_Pow: | |
| if monomial.args[0] in gens: | |
| power_gens[monomial.args[0]] += monomial.args[1] | |
| else: | |
| for univariate in monomial.args: | |
| term_type = len(univariate.args) | |
| if term_type == 0 and univariate in gens: | |
| power_gens[univariate] += 1 | |
| elif term_type == 2 and univariate.args[0] in gens: | |
| power_gens[univariate.args[0]] +=\ | |
| univariate.args[1] | |
| elif expr.is_Mul: | |
| for term in expr.args: | |
| term_type = len(term.args) | |
| if term_type == 0 and term in gens: | |
| power_gens[term] += 1 | |
| elif term_type == 2 and term.args[0] in gens: | |
| power_gens[term.args[0]] += term.args[1] | |
| elif expr.is_Pow: | |
| power_gens[expr.args[0]] = expr.args[1] | |
| elif expr.is_Symbol: | |
| power_gens[expr] += 1 | |
| else: # If `expr` is a constant take first vertex of the line segment. | |
| return a1, b1 | |
| # TODO : This part is quite hacky. Should be made more robust with | |
| # TODO : respect to symbol names and scalable w.r.t higher dimensions. | |
| power_gens = sorted(power_gens.items(), key=lambda k: str(k[0])) | |
| if power_gens[0][1] >= power_gens[1][1]: | |
| if y_axis_cut(lineseg): | |
| x0 = (S.Zero, b / a[1]) | |
| elif x_axis_cut(lineseg): | |
| x0 = (b / a[0], S.Zero) | |
| else: | |
| x0 = (a1, b1) | |
| else: | |
| if x_axis_cut(lineseg): | |
| x0 = (b/a[0], S.Zero) | |
| elif y_axis_cut(lineseg): | |
| x0 = (S.Zero, b/a[1]) | |
| else: | |
| x0 = (a1, b1) | |
| else: | |
| x0 = (b/a[0]) | |
| return x0 | |
| def decompose(expr, separate=False): | |
| """Decomposes an input polynomial into homogeneous ones of | |
| smaller or equal degree. | |
| Explanation | |
| =========== | |
| Returns a dictionary with keys as the degree of the smaller | |
| constituting polynomials. Values are the constituting polynomials. | |
| Parameters | |
| ========== | |
| expr : Expr | |
| Polynomial(SymPy expression). | |
| separate : bool | |
| If True then simply return a list of the constituent monomials | |
| If not then break up the polynomial into constituent homogeneous | |
| polynomials. | |
| Examples | |
| ======== | |
| >>> from sympy.abc import x, y | |
| >>> from sympy.integrals.intpoly import decompose | |
| >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5) | |
| {1: x + y, 2: x**2 + x*y, 5: x**3*y**2 + y**5} | |
| >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5, True) | |
| {x, x**2, y, y**5, x*y, x**3*y**2} | |
| """ | |
| poly_dict = {} | |
| if isinstance(expr, Expr) and not expr.is_number: | |
| if expr.is_Symbol: | |
| poly_dict[1] = expr | |
| elif expr.is_Add: | |
| symbols = expr.atoms(Symbol) | |
| degrees = [(sum(degree_list(monom, *symbols)), monom) | |
| for monom in expr.args] | |
| if separate: | |
| return {monom[1] for monom in degrees} | |
| else: | |
| for monom in degrees: | |
| degree, term = monom | |
| if poly_dict.get(degree): | |
| poly_dict[degree] += term | |
| else: | |
| poly_dict[degree] = term | |
| elif expr.is_Pow: | |
| _, degree = expr.args | |
| poly_dict[degree] = expr | |
| else: # Now expr can only be of `Mul` type | |
| degree = 0 | |
| for term in expr.args: | |
| term_type = len(term.args) | |
| if term_type == 0 and term.is_Symbol: | |
| degree += 1 | |
| elif term_type == 2: | |
| degree += term.args[1] | |
| poly_dict[degree] = expr | |
| else: | |
| poly_dict[0] = expr | |
| if separate: | |
| return set(poly_dict.values()) | |
| return poly_dict | |
| def point_sort(poly, normal=None, clockwise=True): | |
| """Returns the same polygon with points sorted in clockwise or | |
| anti-clockwise order. | |
| Note that it's necessary for input points to be sorted in some order | |
| (clockwise or anti-clockwise) for the integration algorithm to work. | |
| As a convention algorithm has been implemented keeping clockwise | |
| orientation in mind. | |
| Parameters | |
| ========== | |
| poly: | |
| 2D or 3D Polygon. | |
| normal : optional | |
| The normal of the plane which the 3-Polytope is a part of. | |
| clockwise : bool, optional | |
| Returns points sorted in clockwise order if True and | |
| anti-clockwise if False. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import point_sort | |
| >>> from sympy import Point | |
| >>> point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) | |
| [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)] | |
| """ | |
| pts = poly.vertices if isinstance(poly, Polygon) else poly | |
| n = len(pts) | |
| if n < 2: | |
| return list(pts) | |
| order = S.One if clockwise else S.NegativeOne | |
| dim = len(pts[0]) | |
| if dim == 2: | |
| center = Point(sum((vertex.x for vertex in pts)) / n, | |
| sum((vertex.y for vertex in pts)) / n) | |
| else: | |
| center = Point(sum((vertex.x for vertex in pts)) / n, | |
| sum((vertex.y for vertex in pts)) / n, | |
| sum((vertex.z for vertex in pts)) / n) | |
| def compare(a, b): | |
| if a.x - center.x >= S.Zero and b.x - center.x < S.Zero: | |
| return -order | |
| elif a.x - center.x < 0 and b.x - center.x >= 0: | |
| return order | |
| elif a.x - center.x == 0 and b.x - center.x == 0: | |
| if a.y - center.y >= 0 or b.y - center.y >= 0: | |
| return -order if a.y > b.y else order | |
| return -order if b.y > a.y else order | |
| det = (a.x - center.x) * (b.y - center.y) -\ | |
| (b.x - center.x) * (a.y - center.y) | |
| if det < 0: | |
| return -order | |
| elif det > 0: | |
| return order | |
| first = (a.x - center.x) * (a.x - center.x) +\ | |
| (a.y - center.y) * (a.y - center.y) | |
| second = (b.x - center.x) * (b.x - center.x) +\ | |
| (b.y - center.y) * (b.y - center.y) | |
| return -order if first > second else order | |
| def compare3d(a, b): | |
| det = cross_product(center, a, b) | |
| dot_product = sum(det[i] * normal[i] for i in range(0, 3)) | |
| if dot_product < 0: | |
| return -order | |
| elif dot_product > 0: | |
| return order | |
| return sorted(pts, key=cmp_to_key(compare if dim==2 else compare3d)) | |
| def norm(point): | |
| """Returns the Euclidean norm of a point from origin. | |
| Parameters | |
| ========== | |
| point: | |
| This denotes a point in the dimension_al spac_e. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import norm | |
| >>> from sympy import Point | |
| >>> norm(Point(2, 7)) | |
| sqrt(53) | |
| """ | |
| half = S.Half | |
| if isinstance(point, (list, tuple)): | |
| return sum(coord ** 2 for coord in point) ** half | |
| elif isinstance(point, Point): | |
| if isinstance(point, Point2D): | |
| return (point.x ** 2 + point.y ** 2) ** half | |
| else: | |
| return (point.x ** 2 + point.y ** 2 + point.z) ** half | |
| elif isinstance(point, dict): | |
| return sum(i**2 for i in point.values()) ** half | |
| def intersection(geom_1, geom_2, intersection_type): | |
| """Returns intersection between geometric objects. | |
| Explanation | |
| =========== | |
| Note that this function is meant for use in integration_reduction and | |
| at that point in the calling function the lines denoted by the segments | |
| surely intersect within segment boundaries. Coincident lines are taken | |
| to be non-intersecting. Also, the hyperplane intersection for 2D case is | |
| also implemented. | |
| Parameters | |
| ========== | |
| geom_1, geom_2: | |
| The input line segments. | |
| Examples | |
| ======== | |
| >>> from sympy.integrals.intpoly import intersection | |
| >>> from sympy import Point, Segment2D | |
| >>> l1 = Segment2D(Point(1, 1), Point(3, 5)) | |
| >>> l2 = Segment2D(Point(2, 0), Point(2, 5)) | |
| >>> intersection(l1, l2, "segment2D") | |
| (2, 3) | |
| >>> p1 = ((-1, 0), 0) | |
| >>> p2 = ((0, 1), 1) | |
| >>> intersection(p1, p2, "plane2D") | |
| (0, 1) | |
| """ | |
| if intersection_type[:-2] == "segment": | |
| if intersection_type == "segment2D": | |
| x1, y1 = geom_1.points[0] | |
| x2, y2 = geom_1.points[1] | |
| x3, y3 = geom_2.points[0] | |
| x4, y4 = geom_2.points[1] | |
| elif intersection_type == "segment3D": | |
| x1, y1, z1 = geom_1.points[0] | |
| x2, y2, z2 = geom_1.points[1] | |
| x3, y3, z3 = geom_2.points[0] | |
| x4, y4, z4 = geom_2.points[1] | |
| denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) | |
| if denom: | |
| t1 = x1 * y2 - y1 * x2 | |
| t2 = x3 * y4 - x4 * y3 | |
| return (S(t1 * (x3 - x4) - t2 * (x1 - x2)) / denom, | |
| S(t1 * (y3 - y4) - t2 * (y1 - y2)) / denom) | |
| if intersection_type[:-2] == "plane": | |
| if intersection_type == "plane2D": # Intersection of hyperplanes | |
| a1x, a1y = geom_1[0] | |
| a2x, a2y = geom_2[0] | |
| b1, b2 = geom_1[1], geom_2[1] | |
| denom = a1x * a2y - a2x * a1y | |
| if denom: | |
| return (S(b1 * a2y - b2 * a1y) / denom, | |
| S(b2 * a1x - b1 * a2x) / denom) | |
| def is_vertex(ent): | |
| """If the input entity is a vertex return True. | |
| Parameter | |
| ========= | |
| ent : | |
| Denotes a geometric entity representing a point. | |
| Examples | |
| ======== | |
| >>> from sympy import Point | |
| >>> from sympy.integrals.intpoly import is_vertex | |
| >>> is_vertex((2, 3)) | |
| True | |
| >>> is_vertex((2, 3, 6)) | |
| True | |
| >>> is_vertex(Point(2, 3)) | |
| True | |
| """ | |
| if isinstance(ent, tuple): | |
| if len(ent) in [2, 3]: | |
| return True | |
| elif isinstance(ent, Point): | |
| return True | |
| return False | |
| def plot_polytope(poly): | |
| """Plots the 2D polytope using the functions written in plotting | |
| module which in turn uses matplotlib backend. | |
| Parameter | |
| ========= | |
| poly: | |
| Denotes a 2-Polytope. | |
| """ | |
| from sympy.plotting.plot import Plot, List2DSeries | |
| xl = [vertex.x for vertex in poly.vertices] | |
| yl = [vertex.y for vertex in poly.vertices] | |
| xl.append(poly.vertices[0].x) # Closing the polygon | |
| yl.append(poly.vertices[0].y) | |
| l2ds = List2DSeries(xl, yl) | |
| p = Plot(l2ds, axes='label_axes=True') | |
| p.show() | |
| def plot_polynomial(expr): | |
| """Plots the polynomial using the functions written in | |
| plotting module which in turn uses matplotlib backend. | |
| Parameter | |
| ========= | |
| expr: | |
| Denotes a polynomial(SymPy expression). | |
| """ | |
| from sympy.plotting.plot import plot3d, plot | |
| gens = expr.free_symbols | |
| if len(gens) == 2: | |
| plot3d(expr) | |
| else: | |
| plot(expr) | |
Xet Storage Details
- Size:
- 43.3 kB
- Xet hash:
- 57e490c22d44bc5aef9f18da66f8856d249763b38d3c76cf67a2a6edf7c26f31
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.