mathconvex-hullconvexconvex-polygonscipy-spatial

Evaluate the weights of a convex combination


I'm using the scipy.spatial.ConvexHull API for evaluating the convex hull of a set of points and it works well. Given the code below:

p1 = points[11]
hull = ConvexHull(points)
vertices = [points[i] for i in hull.vertices] 

how can I evaluate the coefficients(weights) of the convex combination of vertices that equals to p1?

Thank you very much, Moshe


Solution

  • Note: if the number of vertices is higher than d+1, where d is the dimension, then the combination will not be unique. In the remainder of the answer I assume that d=2 for simplicity.

    Input:

    Output:

    such that:

    This is a system of three linear equations in the unknown (a0, a1, ..., an), along with n+1 linear inequations. We can solve this system using scipy's linear programming module scipy.optimize.linprog

    Example solution:

    import random                      # generate points
    import scipy.spatial as scispa     # ConvexHull
    import scipy.optimize as sciopt    # linprog
    from scipy.sparse import identity  # identity matrix
    
    points = [(random.randrange(0,100), random.randrange(0,100)) for _ in range(20)]
    p1 = points[11]
    hull = scispa.ConvexHull(points)
    vertices = [points[i] for i in hull.vertices]
    
    c = [1 for _ in vertices]
    A = [[x for x,y in vertices], [y for x,y in vertices], [1 for _ in vertices]]
    b = [p1[0], p1[1], 1]
    s = sciopt.linprog(c, A_eq = A, b_eq = b)
    
    >>> s.x
    array([0.13393774, 0.06470577, 0.07367599, 0.09523271, 0.18924727,
           0.26909487, 0.17410566])
    >>> p1
    (36, 57)
    >>> [sum(a*xi for a,(xi,_) in zip(s.x, vertices)), sum(a*yi for a,(_,yi) in zip(s.x, vertices))]
    [36.00000000719907, 57.00000000671608]
    

    Important note: I began this answer by warning that if there are more than 3 vertices in the plane, or more than d+1 vertices in dimension d, then there will be more than 1 solution to our system of equations. The code above only returns one solution, meaning that an arbitrary choice was made. You have control over this arbitrary choice: scipy.optimize.linprog is an optimisation tool; here it is minimizing the dot-product of the vector c we gave as parameter, and the solution vector s.x. Here I set all coefficients of c to 1, meaning linprog will find a solution that minimizes the sum of coefficients in the solution; try supplying a different vector c and you'll get a different solution.