예제 #1
0
def eval_3diou(dt_floor_coor,
               dt_ceil_coor,
               gt_floor_coor,
               gt_ceil_coor,
               ch=-1.6,
               coorW=1024,
               coorH=512):
    '''
    Evaluate 3D IoU of "convex layout".
    Instead of voxelization, this function use halfspace intersection
    to evaluate the volume.
    Input parameters:
        dt_ceil_coor, dt_floor_coor, gt_ceil_coor, gt_floor_coor
    have to be in shape [N, 2] and in the format of:
        [[x, y], ...]
    listing the corner position from left to right on the equirect image.
    '''
    dt_floor_coor = np.array(dt_floor_coor)
    dt_ceil_coor = np.array(dt_ceil_coor)
    gt_floor_coor = np.array(gt_floor_coor)
    gt_ceil_coor = np.array(gt_ceil_coor)
    assert (dt_floor_coor[:, 0] != dt_ceil_coor[:, 0]).sum() == 0
    assert (gt_floor_coor[:, 0] != gt_ceil_coor[:, 0]).sum() == 0
    N = len(dt_floor_coor)
    dt_floor_xyz = np.hstack([
        np_coor2xy(dt_floor_coor, ch, coorW, coorH),
        np.zeros((N, 1)) + ch,
    ])
    gt_floor_xyz = np.hstack([
        np_coor2xy(gt_floor_coor, ch, coorW, coorH),
        np.zeros((N, 1)) + ch,
    ])
    dt_c = np.sqrt((dt_floor_xyz[:, :2]**2).sum(1))
    gt_c = np.sqrt((gt_floor_xyz[:, :2]**2).sum(1))
    dt_v2 = np_coory2v(dt_ceil_coor[:, 1], coorH)
    gt_v2 = np_coory2v(gt_ceil_coor[:, 1], coorH)
    dt_ceil_z = dt_c * np.tan(dt_v2)
    gt_ceil_z = gt_c * np.tan(gt_v2)

    dt_ceil_xyz = dt_floor_xyz.copy()
    dt_ceil_xyz[:, 2] = dt_ceil_z
    gt_ceil_xyz = gt_floor_xyz.copy()
    gt_ceil_xyz[:, 2] = gt_ceil_z

    dt_halfspaces = xyzlst2halfspaces(dt_floor_xyz, dt_ceil_xyz)
    gt_halfspaces = xyzlst2halfspaces(gt_floor_xyz, gt_ceil_xyz)

    in_halfspaces = HalfspaceIntersection(
        np.concatenate([dt_halfspaces, gt_halfspaces]), np.zeros(3))
    dt_halfspaces = HalfspaceIntersection(dt_halfspaces, np.zeros(3))
    gt_halfspaces = HalfspaceIntersection(gt_halfspaces, np.zeros(3))

    in_volume = ConvexHull(in_halfspaces.intersections).volume
    dt_volume = ConvexHull(dt_halfspaces.intersections).volume
    gt_volume = ConvexHull(gt_halfspaces.intersections).volume
    un_volume = dt_volume + gt_volume - in_volume

    return in_volume / un_volume
예제 #2
0
    def build_polys(self, poly):
        if poly.inner is None:
            A = np.vstack([p.T for p in poly.points])
            poly.inner = ConvexHull(A, incremental=True)
            self.feasible_point = np.sum(A, axis=0) / A.shape[0]
        else:
            try:
                poly.inner.add_points(poly.points[-1].T, restart=False)
            except QhullError:
                print("Incremental processing failed")
                A = np.vstack([p.T for p in poly.points])
                poly.inner = ConvexHull(A, incremental=True)

        if poly.outer is None:
            if poly.inner is None:
                raise AssertionError(
                    "Inner polygon should have been initialized")
            A = np.vstack(poly.directions)
            b = np.vstack(poly.offsets)
            poly.outer = HalfspaceIntersection(np.hstack((A, -b)),
                                               self.feasible_point,
                                               incremental=True)
        else:
            hs = np.zeros((1, poly.outer.halfspaces.shape[1]))
            hs[:, :-1] = poly.directions[-1]
            hs[:, -1] = -poly.offsets[-1]
            try:
                poly.outer.add_halfspaces(hs)
            except QhullError:
                print("Incremental halfspaces failed")
                A = np.vstack(poly.directions)
                b = np.vstack(poly.offsets)

                c = np.zeros((A.shape[1], ))
                c[-1] = -1

                res = linprog(c,
                              A_ub=np.hstack(
                                  (A[:, :-1], np.ones((A.shape[0], 1)))),
                              b_ub=-A[:, -1:],
                              bounds=(None, None))
                if res.success:
                    self.feasible_point = res.x[:-1]
                else:
                    raise RuntimeError("No interior point found")

                poly.outer = HalfspaceIntersection(np.hstack((A, -b)),
                                                   self.feasible_point,
                                                   incremental=True)
예제 #3
0
def to_hsi(r: Cuboid) -> HalfspaceIntersection:
    hs_norms, hs_origins = cube_to_normals(np.array(r.position),
                                           np.array(r.dimensions),
                                           np.array(r.orientation))
    hs_ineqs = halfspaces_to_inequalities(hs_norms, hs_origins)
    in_point = np.array(r.position)
    return HalfspaceIntersection(hs_ineqs, in_point)
예제 #4
0
def proj_hsi_to_plane(hsi: HalfspaceIntersection, p_norm: Vector3D,
                      p_origin: Vector3D) -> Optional[HalfspaceIntersection]:
    projected_halfspaces = []
    rev_rot = rotation_to_euler(p_norm, Vector3D(0, 0, 1))

    for hs in hsi.halfspaces:
        hs_norm = hs[:-1]
        dp = np.dot(hs_norm, p_norm)
        if 1.0 - np.abs(dp) >= 1e-9:
            hs_origin = -hs[-1] * hs[:-1]
            projected_origin = project_to_plane_intersection(
                hs_origin, hs_norm, hs_origin, p_norm, p_origin)

            projected_norm = hs_norm - dp * p_norm
            projected_norm = projected_norm / np.linalg.norm(projected_norm)
            aa_norm = rotate_euler(projected_norm, rev_rot)

            new_b = -np.dot(projected_origin - p_origin, projected_norm)

            projected_halfspaces.append(np.append(aa_norm[:-1], new_b))
    projected_halfspaces = np.array(projected_halfspaces)

    proj_feasible_point = feasible_point(projected_halfspaces)
    if proj_feasible_point is None:
        return None

    return HalfspaceIntersection(projected_halfspaces, proj_feasible_point)
예제 #5
0
    def __post_init__(self):
        self.cross_point_dicts = {}
        large_minus_number = -1e4
        for name, ce in self.charge_energies_dict.items():
            half_spaces = []
            for charge, corr_energy in ce.charge_energies:
                half_spaces.append([-charge, 1, -corr_energy])

            half_spaces.append([-1, 0, self.e_min])
            half_spaces.append([1, 0, -self.e_max])
            half_spaces.append([0, -1, large_minus_number])

            feasible_point = np.array([(self.e_min + self.e_max) / 2, -1e3])

            hs = HalfspaceIntersection(np.array(half_spaces), feasible_point)
            boundary_points = []
            inner_cross_points = []
            for intersection in hs.intersections:
                x, y = np.round(intersection, 8)
                if self.e_min + 0.001 < x < self.e_max - 0.001:
                    inner_cross_points.append([x, y])
                elif y > large_minus_number + 1:
                    boundary_points.append([x, y])

            self.cross_point_dicts[name] = CrossPoints(inner_cross_points,
                                                       boundary_points)
예제 #6
0
    def plot_halfspace(self, x, y, ax, sys, idx_offset=0):

        dim = self.model.dim
        comple_dim = np.asarray(
            [True if i in [x, y] else False for i in range(dim)])

        'Halfspace constraint matrix'
        A = sys.A
        b = sys.b

        phase_intersect = np.hstack((A, -np.asarray([b]).T))
        center_pt = np.asarray(sys.chebyshev_center.center)

        'Run scipy.spatial.HalfspaceIntersection.'
        hs = HalfspaceIntersection(phase_intersect, center_pt)
        vertices = np.asarray(hs.intersections)

        proj_vertices = np.unique(vertices[:, comple_dim], axis=0).tolist()

        'Sort by polar coordinates to ensure proper plotting of boundary'
        proj_vertices.sort(
            key=lambda v: math.atan2(v[1] - center_pt[1], v[0] - center_pt[0]))

        ptope = pat.Polygon(proj_vertices,
                            fill=True,
                            color=f"C{idx_offset}",
                            alpha=0.4)
        ax.add_patch(ptope)

        inter_x, inter_y = zip(*proj_vertices)
        ax.scatter(inter_x, inter_y, s=0.1)
예제 #7
0
    def cross_points(self, ef_min, ef_max, base_ef=0.0):
        large_minus_number = -1e4
        half_spaces = []
        for charge, energy, correction in zip(self.charges, self.energies,
                                              self.corrections):
            corrected_energy = energy + correction
            half_spaces.append([-charge, 1, -corrected_energy])

        half_spaces.append([-1, 0, ef_min])
        half_spaces.append([1, 0, -ef_max])
        half_spaces.append([0, -1, large_minus_number])

        feasible_point = np.array([(ef_min + ef_max) / 2, -1e3])

        hs = HalfspaceIntersection(np.array(half_spaces), feasible_point)
        boundary_points = []
        inner_cross_points = []
        for intersection in hs.intersections:
            x, y = np.round(intersection, 8)
            if ef_min + 0.001 < x < ef_max - 0.001:
                inner_cross_points.append([x - base_ef, y])
            elif y > large_minus_number + 1:
                boundary_points.append([x - base_ef, y])

        return CrossPoints(inner_cross_points, boundary_points)
예제 #8
0
def non_trivial_vertices(halfspaces):
    """
    Returns all vertex, label pairs (ignoring the origin).

    Parameters:

        halfspaces: a numpy array

    Returns:

        generator
    """
    feasible_point = find_feasible_point(halfspaces)
    hs = HalfspaceIntersection(halfspaces, feasible_point)
    hs.close()
    return ((v, labels(v, halfspaces)) for v in hs.intersections if max(v) > 0)
예제 #9
0
def to_hsi(r: Rectangle3D) -> HalfspaceIntersection:
    hs_origins = np.array([[r.width / 2.0, 0], [0, r.length / 2.0],
                           [-r.width / 2.0, 0], [0, -r.length / 2.0]])
    hs_norms = np.array([[-1, 0], [0, -1], [1, 0], [0, 1]])

    hs_ineqs = halfspaces_to_inequalities(hs_norms, hs_origins)
    return HalfspaceIntersection(hs_ineqs, np.array([0.0, 0.0]))
예제 #10
0
 def set_offset(self, offset, face_index):
     '''Sets the offset value of one or all faces.
     @param  offset      The offset value. Must be a float >= 0.0.
     @param  face_index  If < 0, sets *all* faces, otherwise a valid index sets
                         the single, indexed face.
     '''
     if (offset < 0): offset = 0.0
     if (face_index < 0):
         self.deltas[:] = offset
     else:
         self.deltas[face_index] = offset
     temp_planes = self.planes.copy()
     temp_planes[:, 3] -= self.deltas
     hs = HalfspaceIntersection(temp_planes, self.feasible_point)
     verts = hs.intersections  # (N, 3) shape -- each row is a vertex
     # TODO: Due to numerical imprecision, I can end up with vertices in verts that are
     # *almost* the same (and *should* be the same. I should go through and merge them.
     # Implications:
     #
     faces = []
     for i, f in enumerate(self.faces):
         d = temp_planes[i, 3]  # the const for the ith plane
         n = self.normals[:, i]  # The norm for the ith plane, (3,) shape
         dist = np.dot(verts, n) + d  # (N, 3) * (3,) -> (N,)
         indices = np.where(np.abs(dist) < 1e-6)[0]  # (M,) matrix
         if (list(indices)):
             faces.append(orderVertices(list(indices), n, verts))
         else:
             faces.append([])
     self.hull = SimpleMesh(verts, faces, self.normals)
예제 #11
0
    def plot2DPhase(self, x, y):

        Timer.start('Phase')

        x_var, y_var = self.vars[x], self.vars[y]

        'Define the following projected normal vectors.'
        norm_vecs = np.zeros([6, self.dim_sys])
        norm_vecs[0][x] = 1
        norm_vecs[1][y] = 1
        norm_vecs[2][x] = -1
        norm_vecs[3][y] = -1
        norm_vecs[4][x] = 1
        norm_vecs[4][y] = 1
        norm_vecs[5][x] = -1
        norm_vecs[5][y] = -1

        fig, ax = plt.subplots(1)
        comple_dim = [i for i in range(self.dim_sys) if i not in [x, y]]

        'Initialize objective function for Chebyshev intersection LP routine.'
        c = [0 for _ in range(self.dim_sys + 1)]
        c[-1] = 1

        for bund in self.flowpipe:
            bund_A, bund_b = bund.getIntersect()

            'Compute the normal vector offsets'
            bund_off = np.empty([len(norm_vecs), 1])
            for i in range(len(norm_vecs)):
                bund_off[i] = minLinProg(np.negative(norm_vecs[i]), bund_A,
                                         bund_b).fun

            'Remove irrelevant dimensions. Mostly doing this to make HalfspaceIntersection happy.'
            phase_intersect = np.hstack((norm_vecs, bund_off))
            phase_intersect = np.delete(phase_intersect, comple_dim, axis=1)

            'Compute Chebyshev center of intersection.'
            row_norm = np.reshape(np.linalg.norm(norm_vecs, axis=1),
                                  (norm_vecs.shape[0], 1))
            center_A = np.hstack((norm_vecs, row_norm))

            neg_bund_off = np.negative(bund_off)
            center_pt = maxLinProg(c, center_A, list(neg_bund_off.flat)).x
            center_pt = np.asarray(
                [b for b_i, b in enumerate(center_pt) if b_i in [x, y]])

            'Run scipy.spatial.HalfspaceIntersection.'
            hs = HalfspaceIntersection(phase_intersect, center_pt)
            inter_x, inter_y = zip(*hs.intersections)
            ax.set_xlabel('{}'.format(x_var))
            ax.set_ylabel('{}'.format(y_var))
            ax.fill(inter_x, inter_y, 'b')

        fig.show()

        phase_time = Timer.stop('Phase')
        print("Plotting phase for dimensions {}, {} done -- Time Spent: {}".
              format(x_var, y_var, phase_time))
예제 #12
0
def eval_3diou(dt_floor_coor, dt_ceil_coor, gt_floor_coor, gt_ceil_coor, ch=-1.6,
               coorW=1024, coorH=512, floorW=1024, floorH=512):
    ''' Evaluate 3D IoU using halfspace intersection '''
    dt_floor_coor = np.array(dt_floor_coor)
    dt_ceil_coor = np.array(dt_ceil_coor)
    gt_floor_coor = np.array(gt_floor_coor)
    gt_ceil_coor = np.array(gt_ceil_coor)
    assert (dt_floor_coor[:, 0] != dt_ceil_coor[:, 0]).sum() == 0
    assert (gt_floor_coor[:, 0] != gt_ceil_coor[:, 0]).sum() == 0
    N = len(dt_floor_coor)
    dt_floor_xyz = np.hstack([
        post_proc.np_coor2xy(dt_floor_coor, ch, coorW, coorH, floorW=1, floorH=1),
        np.zeros((N, 1)) + ch,
    ])
    gt_floor_xyz = np.hstack([
        post_proc.np_coor2xy(gt_floor_coor, ch, coorW, coorH, floorW=1, floorH=1),
        np.zeros((N, 1)) + ch,
    ])
    dt_c = np.sqrt((dt_floor_xyz[:, :2] ** 2).sum(1))
    gt_c = np.sqrt((gt_floor_xyz[:, :2] ** 2).sum(1))
    dt_v2 = post_proc.np_coory2v(dt_ceil_coor[:, 1], coorH)
    gt_v2 = post_proc.np_coory2v(gt_ceil_coor[:, 1], coorH)
    dt_ceil_z = dt_c * np.tan(dt_v2)
    gt_ceil_z = gt_c * np.tan(gt_v2)

    dt_ceil_xyz = dt_floor_xyz.copy()
    dt_ceil_xyz[:, 2] = dt_ceil_z
    gt_ceil_xyz = gt_floor_xyz.copy()
    gt_ceil_xyz[:, 2] = gt_ceil_z

    dt_halfspaces = xyzlst2halfspaces(dt_floor_xyz, dt_ceil_xyz)
    gt_halfspaces = xyzlst2halfspaces(gt_floor_xyz, gt_ceil_xyz)

    in_halfspaces = HalfspaceIntersection(np.concatenate([dt_halfspaces, gt_halfspaces]),
                                          np.zeros(3))
    dt_halfspaces = HalfspaceIntersection(dt_halfspaces, np.zeros(3))
    gt_halfspaces = HalfspaceIntersection(gt_halfspaces, np.zeros(3))

    in_volume = ConvexHull(in_halfspaces.intersections).volume
    dt_volume = ConvexHull(dt_halfspaces.intersections).volume
    gt_volume = ConvexHull(gt_halfspaces.intersections).volume
    un_volume = dt_volume + gt_volume - in_volume

    return 100 * in_volume / un_volume
예제 #13
0
    def vertices(self):
        """
        Returns the set of vertices of the polyhdron.
        It assumes the polyhedron to be bounded (i.e. to be a polytope) and full dimensional (equality constraints are allowed but inequalities cannot make the polytope lower dimensional).

        Returns
        ----------
        vertices : list of numpy.ndarray
            List of the vertices of the bounded polyhedron (None if the polyhedron is unbounded or empty).
        """

        # check if it has been already checked
        if self._vertices is not None:
            return self._vertices

        # check boundedness
        if not self.bounded:
            return None

        # check full dimensionality
        tol = 1.e-7
        if self.radius < tol:
            return None

        # handle equalities
        if self.C.shape[0] > 0:
            A, b, N, R = self._remove_equalities()
            T = np.hstack((N, R))
            center = np.linalg.inv(T).dot(self.center)
            center = center[:N.shape[1]]
        else:
            A = self.A
            b = self.b
            center = self.center

        # handle 1d cases
        if A.shape[1] == 1:
            p = Polyhedron(A, b)
            p.remove_redundant_inequalities()
            self._vertices = [np.array([p.b[i] / p.A[i, 0]]) for i in [0, 1]]

        # call qhull through scipy
        else:
            halfspaces = np.column_stack((A, -b))
            polyhedron = HalfspaceIntersection(halfspaces, center)
            V = polyhedron.intersections
            self._vertices = [V[i] for i in range(V.shape[0])]

        # go back to the original coordinates in case of equalities
        if self.C.shape[0] > 0:
            r = np.linalg.inv(self.C.dot(R)).dot(self.d)
            self._vertices = [
                T.dot(np.concatenate((v, r))) for v in self._vertices
            ]

        return self._vertices
예제 #14
0
def _intersect(hulls, feas_point=None):
  all_eq = np.vstack([h.equations for h in hulls])

  if feas_point is None:
    #points = np.vstack([h.points[h.vertices, :] for h in hulls])
    #feas_point = np.sum(points, axis=0)/points.shape[0]
    feas_point = feasible_point(all_eq)

  intersected = ConvexHull(HalfspaceIntersection(all_eq, feas_point).intersections)
  return intersected
예제 #15
0
    def find_direction(self, poly, plot=False):
        self.build_polys(poly)

        volumes = []

        ineq = poly.inner.equations

        for line in ineq:
            key = hashlib.sha1(line).hexdigest()
            if key in poly.hull_dic:
                volumes.append(poly.hull_dic[key].volume)
            else:
                #TODO: How to compute outer initial vrep ?
                # We use CDD for now, but is there any way to get
                # initial feasible point ?

                #A_e = cdd.Matrix(np.hstack((-poly.outer.equations[:, -1:],
                #                            -poly.outer.equations[:, :-1])))
                #A_e.rep_type = cdd.RepType.INEQUALITY
                #m = np.hstack((line[-1:], line[:-1]))
                #A_e.extend(cdd.Matrix(m.reshape((1, m.size))))
                #points = np.array(cdd.Polyhedron(A_e).get_generators())[:, 1:]

                A_e = np.vstack((poly.outer.halfspaces, -line))
                c = np.zeros((A_e.shape[1], ))
                c[-1] = -1
                res = linprog(c,
                              A_ub=np.hstack(
                                  (A_e[:, :-1], np.ones((A_e.shape[0], 1)))),
                              b_ub=-A_e[:, -1:],
                              bounds=(None, None))
                if res.success:
                    feasible_point = res.x[:-1]
                    try:
                        poly.hrep_dic[key] = HalfspaceIntersection(
                            A_e, feasible_point, incremental=True)
                        poly.hull_dic[key] = ConvexHull(
                            poly.hrep_dic[key].intersections)
                        volumes.append(poly.hull_dic[key].volume)
                    except QhullError:
                        volumes.append(0.)
                else:
                    print("Error : {}".format(res.message))
                    volumes.append(0.)

                if plot and res.success:
                    poly.reset_fig()
                    poly.plot_polyhedrons()
                    poly.plot_polyhedron(poly.hull_dic[key], 'm', 0.5)
                    poly.show()

        maxv = max(volumes)
        alli = [i for i, v in enumerate(volumes) if v == maxv]
        i = random.choice(alli)
        return ineq[i, :-1]
예제 #16
0
    def test_halfspace_convpg_noIntersection(self):
        hs = HalfSpace(Vector3D(0, 4, 0), Vector3D(0, 1, 0))
        hsi = HalfspaceIntersection(
            np.array([[1, 0, -3], [0, 1, -3], [-1, 0, 0], [0, -1, 0]]),
            np.array([1.0, 1.0]))
        cp = ConvexPolygon3D(hsi=hsi,
                             origin=Vector3D(0, 0, 0),
                             rot=Vector3D(0, 0, 0))
        it = intersect(hs, cp)

        self.assertTrue(isinstance(it, Empty))
예제 #17
0
def visualize(program, steps):
    variable_names_to_idx = {v : i for i,v in enumerate(program.variables.keys())}
    A_ub = np.array(generate_A(program, variable_names_to_idx))
    b_ub = np.array(generate_b(program))

    res = linprog(method='interior-point', c=np.zeros(A_ub.shape[1]), A_ub=A_ub, b_ub=b_ub)
    feasible_point = res.x

    b_ub = np.expand_dims(-1*b_ub, 1)
    halfspaces = np.hstack((A_ub, b_ub))

    N = len(program.variables)
    shape = (N, N + 1)
    v_mat = np.zeros(shape)
    for idx in range(N):
        v_mat[idx, idx] = -1
    halfspaces = np.vstack((halfspaces, v_mat))

    hs = HalfspaceIntersection(halfspaces, feasible_point)
    points = np.around(hs.intersections, 3)
    points = points[:, :2]
    xlim = (-1, max([p[0] for p in points]) + 1)
    ylim = (-1, max([p[1] for p in points]) + 1)

    steps = np.array(steps)
    steps = steps[:, :2]

    figs = []
    for i, (p,q) in enumerate(steps):

        fig = plt.figure()
        ax = fig.add_subplot('111', aspect='equal')
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)

        x = np.linspace(*xlim, 100)

        x, y = zip(*points)
        # points = list(zip(x, y))
        convex_hull = ConvexHull(points)
        polygon = Polygon([points[v] for v in convex_hull.vertices], color="#34495e")
        ax.add_patch(polygon)
        ax.plot(x, y, 'o', color="#e67e22")

        ax.plot(p, q, 'o', markersize=15)

        byarray = io.BytesIO()
        fig.savefig(byarray, format='png', bbox_inches="tight")
        b64 = base64.b64encode(byarray.getvalue()).decode("utf-8").replace("\n", "")
        b64 = 'data:image/png;base64,%s' % b64
        figs.append(b64)

    return figs
예제 #18
0
    def find_point_volume_direction(self, poly, point):
        normals, offset = poly.inner.equations[:, :
                                               -1], poly.inner.equations[:, -1]
        outside = (normals.dot(point) + offset) > 0
        if np.sum(outside) == 0:
            raise ValueError("The point is inside!")
        else:
            volumes = {}
            for i in np.argwhere(outside):
                index = i.item(0)
                line = poly.inner.equations[i, :]
                key = hashlib.sha1(line).hexdigest()
                if key in poly.hull_dic:
                    volumes[index] = poly.hull_dic[key].volume
                else:
                    #TODO: How to compute outer initial vrep ?
                    # We use CDD for now, but is there any way to get
                    # initial feasible point ?

                    #A_e = cdd.Matrix(np.hstack((-poly.outer.equations[:, -1:],
                    #                            -poly.outer.equations[:, :-1])))
                    #A_e.rep_type = cdd.RepType.INEQUALITY
                    #m = np.hstack((line[-1:], line[:-1]))
                    #A_e.extend(cdd.Matrix(m.reshape((1, m.size))))
                    #points = np.array(cdd.Polyhedron(A_e).get_generators())[:, 1:]

                    A_e = np.vstack((poly.outer.halfspaces, -line))
                    c = np.zeros((A_e.shape[1], ))
                    c[-1] = -1
                    res = linprog(c,
                                  A_ub=np.hstack(
                                      (A_e[:, :-1], np.ones(
                                          (A_e.shape[0], 1)))),
                                  b_ub=-A_e[:, -1:],
                                  bounds=(None, None))
                    if res.success:
                        feasible_point = res.x[:-1]
                        try:
                            poly.hrep_dic[key] = HalfspaceIntersection(
                                A_e, feasible_point, incremental=True)
                            poly.hull_dic[key] = ConvexHull(
                                poly.hrep_dic[key].intersections)
                            volumes[index] = poly.hull_dic[key].volume
                        except QhullError:
                            volumes[index] = 0.
                    else:
                        print("Error : {}".format(res.message))
                        volumes[index] = .0

            maxv = max(volumes.values())
            alli = [i for i, v in volumes.items() if v == maxv]
            i = random.choice(alli)
            return normals[i:i + 1, :]
예제 #19
0
    def from_halfspaces(cls, halfspaces, interior_point):
        """Construct a polyhedron from its half-spaces and one interior point.

        Parameters
        ----------
        halfspaces : array-like
            The coefficients of the hgalfspace equations in normal form.
        interior_point : array-like
            A point on the interior.

        Returns
        -------
        :class:`compas.geometry.Polyhedron`

        Examples
        --------
        >>> from compas.geometry import Plane
        >>> left = Plane([-1, 0, 0], [-1, 0, 0])
        >>> right = Plane([+1, 0, 0], [+1, 0, 0])
        >>> top = Plane([0, 0, +1], [0, 0, +1])
        >>> bottom = Plane([0, 0, -1], [0, 0, -1])
        >>> front = Plane([0, -1, 0], [0, -1, 0])
        >>> back = Plane([0, +1, 0], [0, +1, 0])

        >>> import numpy as np
        >>> halfspaces = np.array([left.abcd, right.abcd, top.abcd, bottom.abcd, front.abcd, back.abcd], dtype=float)
        >>> interior = np.array([0, 0, 0], dtype=float)

        >>> p = Polyhedron.from_halfspaces(halfspaces, interior)
        """
        from itertools import combinations
        from numpy import asarray
        from scipy.spatial import HalfspaceIntersection, ConvexHull
        from compas.datastructures import Mesh, mesh_merge_faces
        from compas.geometry import length_vector, dot_vectors, cross_vectors
        halfspaces = asarray(halfspaces, dtype=float)
        interior_point = asarray(interior_point, dtype=float)
        hsi = HalfspaceIntersection(halfspaces, interior_point)
        hull = ConvexHull(hsi.intersections)
        mesh = Mesh.from_vertices_and_faces(
            [hsi.intersections[i] for i in hull.vertices], hull.simplices)
        mesh.unify_cycles()
        to_merge = []
        for a, b in combinations(mesh.faces(), 2):
            na = mesh.face_normal(a)
            nb = mesh.face_normal(b)
            if dot_vectors(na, nb) >= 1:
                if length_vector(cross_vectors(na, nb)) < 1e-6:
                    to_merge.append([a, b])
        for faces in to_merge:
            mesh_merge_faces(mesh, faces)
        vertices, faces = mesh.to_vertices_and_faces()
        return cls(vertices, faces)
예제 #20
0
def erode_hsis(original: HalfspaceIntersection, eroder: HalfspaceIntersection):
    tightest_bs = []
    for hs in original.halfspaces:
        result = linprog(-hs[:-1],
                         eroder.halfspaces[:, :-1],
                         -eroder.halfspaces[:, -1],
                         bounds=(None, None))
        assert result.status == 0
        tightest_bs.append(hs[-1] - result.fun)

    eroded_halfspaces = np.column_stack(
        (original.halfspaces[:, :-1], tightest_bs))
    return HalfspaceIntersection(eroded_halfspaces, original.interior_point)
예제 #21
0
def CHAMP_2D(G, all_parts, gamma_0, gamma_f, single_threaded=False):
    """Calculates the pruned set of partitions from CHAMP on gamma_0 <= gamma <= gamma_f

    :param G: graph of interest
    :param all_parts: partitions to prune
    :param gamma_0: starting gamma value
    :param gamma_f: ending gamma value
    :param single_threaded: if True, run without parallelization
    :return: list of [(domain_gamma_start, domain_gamma_end, membership), ...]
    """

    # TODO: remove this filter once scipy updates their library
    # scipy.linprog currently uses deprecated numpy behavior, so we suppress this warning to avoid output clutter
    warnings.filterwarnings("ignore", category=VisibleDeprecationWarning)

    if len(all_parts) == 0:
        return []

    all_parts = list(all_parts)
    num_partitions = len(all_parts)

    partition_coefficients = partition_coefficients_2D(
        G, all_parts, single_threaded=single_threaded)
    A_hats, P_hats = partition_coefficients

    top = max(A_hats - P_hats * gamma_0)  # Could potentially be optimized
    right = gamma_f  # Could potentially use the max intersection x value
    halfspaces = np.vstack(
        (halfspaces_from_coefficients_2D(*partition_coefficients),
         np.array([[0, 1, -top], [1, 0, -right]])))

    # Could potentially scale axes so Chebyshev center is better for problem
    interior_point = get_interior_point(halfspaces)
    hs = HalfspaceIntersection(halfspaces, interior_point)

    # scipy does not support facets by halfspace directly, so we must compute them
    facets_by_halfspace = defaultdict(list)
    for v, idx in zip(hs.intersections, hs.dual_facets):
        assert np.isfinite(v).all()
        for i in idx:
            if i < num_partitions:
                facets_by_halfspace[i].append(v)

    ranges = []
    for i, intersections in facets_by_halfspace.items():
        x1, x2 = intersections[0][0], intersections[1][0]
        if x1 > x2:
            x1, x2 = x2, x1
        ranges.append((x1, x2, all_parts[i]))

    return sorted(ranges, key=lambda x: x[0])
예제 #22
0
def compute_vertexes(a_mat: types.Matrix, b_vec: types.ColVector,
                     feasible_point: types.ColVector) -> types.Matrix:
    """
    Compute all vertexes of a polyhedron. Constraints have to be expressed as:  A*x + b <= 0.

    :param a_mat: A matrix in A*x + b <= 0.
    :param b_vec: b vector in A*x + b <= 0.
    :param feasible_point: Initial feasible point.
    :return: vertexes: Matrix with rows given by the vertexes of the feasible set.
    """
    halfspaces = np.hstack((a_mat, -b_vec))
    halfspaces_intersections = HalfspaceIntersection(halfspaces,
                                                     feasible_point)
    vertexes = halfspaces_intersections.intersections
    return vertexes
예제 #23
0
def polytope_vertices(A: np.ndarray,
                      b: np.ndarray,
                      interior_pt: np.ndarray = None) -> np.ndarray:
    """Return the vertices of the halfspace intersection Ax <= b.

    Equivalently, return the V-representation of some polytope given the
    H-representation. Provide an interior point to improve computation time.

    Args:
        A (np.ndarray): LHS coefficents of the halfspaces.
        b (np.ndarray): RHS coefficents of the halfspaces.
        interior_pt (np.ndarray): Interior point of the halfspace intersection.

    Returns:
        np.ndarray: Vertices of the halfspace intersection.
    """
    try:
        if interior_pt is None:
            interior_pt = interior_point(A, b)
        interior_pt = interior_pt.astype(float)
        A_b = np.hstack((A, -b))
        vertices = HalfspaceIntersection(A_b, interior_pt).intersections
        vertices = np.round(np.array(vertices), 12)
    except NoInteriorPoint:
        vertices = []
        m, n = A.shape
        for B in itertools.combinations(range(m), n):
            try:
                x = np.linalg.solve(A[B, :], b[B, :])[:, 0]
                if all(np.matmul(A, x) <= b[:, 0] + 1e-12):
                    vertices.append(x)
            except np.linalg.LinAlgError:
                pass
        vertices = np.round(np.array(vertices), 12)
        vertices = np.unique(vertices, axis=0)
    return [np.array([v]).transpose() for v in vertices]
예제 #24
0
    def test_halfspace_convpg_intersection(self):
        hs = HalfSpace(Vector3D(0, 2, 0), Vector3D(0, 1, 0))
        hsi = HalfspaceIntersection(
            np.array([[1, 0, -3], [0, 1, -3], [-1, 0, 0], [0, -1, 0]]),
            np.array([1.0, 1.0]))
        cp = ConvexPolygon3D(hsi=hsi,
                             origin=Vector3D(0, 0, 0),
                             rot=Vector3D(0, 0, 0))
        it = intersect(hs, cp)

        int_point_3d: Vector3D = rotate_euler_v3d(
            Vector3D(*it.hsi.interior_point, 0.0), it.rot) + it.origin

        self.assertTrue(isinstance(it, ConvexPolygon3D))
        self.assertTrue(contains_point(hs, int_point_3d))
        self.assertTrue(contains_point(cp, int_point_3d))
예제 #25
0
    def _get_domains(self) -> Dict[str, np.ndarray]:
        """Returns a dictionary of domains as {formula: np.ndarray}"""
        hyperplanes = self._hyperplanes
        border_hyperplanes = self._border_hyperplanes
        entries = self._hyperplane_entries

        hs_hyperplanes = np.vstack([hyperplanes, border_hyperplanes])
        interior_point = np.min(self.lims, axis=1) + 1e-1
        hs_int = HalfspaceIntersection(hs_hyperplanes, interior_point)

        domains = {entry.composition.reduced_formula: []
                   for entry in entries}  # type: ignore

        for intersection, facet in zip(hs_int.intersections,
                                       hs_int.dual_facets):
            for v in facet:
                if v < len(entries):
                    this_entry = entries[v]
                    formula = this_entry.composition.reduced_formula
                    domains[formula].append(intersection)

        return {k: np.array(v) for k, v in domains.items() if v}
예제 #26
0
def v_cell(i0: int, tacke: List[List[float]]) -> List[List[float]]:

    t0 = tacke[i0]
    half_spaces = []
    for i in range(len(tacke)):
        if i != i0:
            t = tacke[i]
            x1 = t[0]
            x2 = t0[0]
            y1 = t[1]
            y2 = t0[1]
            a = x1 - x2
            b = y1 - y2
            c = (-x1 * x1 + x2 * x2 - y1 * y1 + y2 * y2) / 2
            #if(x1*a + y1*b + c > 0):
            bis_k = [a, b, c]
            half_spaces.append(bis_k)
    #print(np.array(half_spaces,dtype = float))

    hs = HalfspaceIntersection(np.array(half_spaces), np.array(t0))

    ch = ConvexHull(hs.intersections)
    return Polygon([list(ch.points[i]) for i in ch.vertices])
예제 #27
0
    def alt_reduce(self, contingency):
        self = MT.grid
        from scipy.spatial import HalfspaceIntersection
        A = []
        b = []
        for ptdf in contingency:
            ram_array = self.update_ram(ptdf, option="array")
            ram_pos = ram_array[:, 0]
            ram_neg = ram_array[:, 1]
            tmp_A = np.concatenate((-ptdf, ptdf), axis=0)
            tmp_b = np.concatenate((-ram_pos, ram_neg), axis=0)
            A += tmp_A.tolist()
            b += tmp_b.tolist()

        A = np.array(A)
        b = np.array(b).reshape(len(b), 1)
#        len(self.nodes)
        Ab = np.concatenate((A, b), axis=1)

        test = HalfspaceIntersection(Ab, np.zeros(len(self.nodes)), qhull_options="QJ")
#        dir(test)
        nr = test.dual_vertices
        return(Ab, nr)
예제 #28
0
    def get_pourbaix_domains(pourbaix_entries, limits=None):
        """
        Returns a set of pourbaix stable domains (i. e. polygons) in
        pH-V space from a list of pourbaix_entries

        This function works by using scipy's HalfspaceIntersection
        function to construct all of the 2-D polygons that form the
        boundaries of the planes corresponding to individual entry
        gibbs free energies as a function of pH and V. Hyperplanes
        of the form a*pH + b*V + 1 - g(0, 0) are constructed and
        supplied to HalfspaceIntersection, which then finds the
        boundaries of each pourbaix region using the intersection
        points.

        Args:
            pourbaix_entries ([PourbaixEntry]): Pourbaix entries
                with which to construct stable pourbaix domains
            limits ([[float]]): limits in which to do the pourbaix
                analysis

        Returns:
            Returns a dict of the form {entry: [boundary_points]}.
            The list of boundary points are the sides of the N-1
            dim polytope bounding the allowable ph-V range of each entry.
        """
        if limits is None:
            limits = [[-2, 16], [-4, 4]]

        # Get hyperplanes
        hyperplanes = [
            np.array([-PREFAC * entry.npH, -entry.nPhi, 0, -entry.energy]) *
            entry.normalization_factor for entry in pourbaix_entries
        ]
        hyperplanes = np.array(hyperplanes)
        hyperplanes[:, 2] = 1

        max_contribs = np.max(np.abs(hyperplanes), axis=0)
        g_max = np.dot(-max_contribs, [limits[0][1], limits[1][1], 0, 1])

        # Add border hyperplanes and generate HalfspaceIntersection
        border_hyperplanes = [
            [-1, 0, 0, limits[0][0]],
            [1, 0, 0, -limits[0][1]],
            [0, -1, 0, limits[1][0]],
            [0, 1, 0, -limits[1][1]],
            [0, 0, -1, 2 * g_max],
        ]
        hs_hyperplanes = np.vstack([hyperplanes, border_hyperplanes])
        interior_point = np.average(limits, axis=1).tolist() + [g_max]
        hs_int = HalfspaceIntersection(hs_hyperplanes,
                                       np.array(interior_point))

        # organize the boundary points by entry
        pourbaix_domains = {entry: [] for entry in pourbaix_entries}
        for intersection, facet in zip(hs_int.intersections,
                                       hs_int.dual_facets):
            for v in facet:
                if v < len(pourbaix_entries):
                    this_entry = pourbaix_entries[v]
                    pourbaix_domains[this_entry].append(intersection)

        # Remove entries with no pourbaix region
        pourbaix_domains = {k: v for k, v in pourbaix_domains.items() if v}
        pourbaix_domain_vertices = {}

        for entry, points in pourbaix_domains.items():
            points = np.array(points)[:, :2]
            # Initial sort to ensure consistency
            points = points[np.lexsort(np.transpose(points))]
            center = np.average(points, axis=0)
            points_centered = points - center

            # Sort points by cross product of centered points,
            # isn't strictly necessary but useful for plotting tools
            points_centered = sorted(
                points_centered,
                key=cmp_to_key(lambda x, y: x[0] * y[1] - x[1] * y[0]))
            points = points_centered + center

            # Create simplices corresponding to pourbaix boundary
            simplices = [
                Simplex(points[indices])
                for indices in ConvexHull(points).simplices
            ]
            pourbaix_domains[entry] = simplices
            pourbaix_domain_vertices[entry] = points

        return pourbaix_domains, pourbaix_domain_vertices
예제 #29
0
def get_intersection(coef_array, max_pt=None):
    '''
    Calculate the intersection of the halfspaces (planes) that form the convex hull

   :param coef_array: NxM array of M coefficients across each row representing N partitions
   :type coef_array: array
   :param max_pt: Upper bound for the domains (in the xy plane). This will restrict the convex hull \
    to be within the specified range of gamma/omega (such as the range of parameters originally searched using Louvain).
   :type max_pt: (float,float) or float
   :return: dictionary mapping the index of the elements in the convex hull to the points defining the boundary
    of the domain
    '''

    halfspaces = create_halfspaces_from_array(coef_array)
    num_input_halfspaces = len(halfspaces)

    singlelayer = False
    if halfspaces.shape[1] - 1 == 2:  # 2D case, halfspaces.shape is (number of halfspaces, dimension+1)
        singlelayer = True

    # Create Boundary Halfspaces - These will always be included in the convex hull
    # and need to be removed before returning dictionary

    boundary_halfspaces = []
    if not singlelayer:
        # origin boundaries
        boundary_halfspaces.extend([np.array([0, -1.0, 0, 0]), np.array([-1.0, 0, 0, 0])])
        if max_pt is not None:
            boundary_halfspaces.extend([np.array([0, 1.0, 0, -1.0 * max_pt[0]]),
                                        np.array([1.0, 0, 0, -1.0 * max_pt[1]])])
    else:
        boundary_halfspaces.extend([np.array([-1.0, 0, 0]),  # y-axis
                                    np.array([0, -1.0, 0])])  # x-axis
        if max_pt is not None:
            boundary_halfspaces.append(np.array([1.0, 0, -1.0 * max_pt]))

    # We expect infinite vertices in the halfspace intersection, so we can ignore numpy's floating point warnings
    old_settings = np.seterr(divide='ignore', invalid='ignore')

    halfspaces = np.vstack((halfspaces, ) + tuple(boundary_halfspaces))

    if max_pt is None:
        if not singlelayer:
            # in this case, we will calculate max boundary planes later, so we'll impose x, y <= 10.0
            # for the interior point calculation here.
            interior_pt = get_interior_point(np.vstack((halfspaces,) +
                                                       (np.array([0, 1.0, 0, -10.0]), np.array([1.0, 0, 0, -10.0]))))
        else:
            # similarly, in the 2D case, we impose x <= 10.0 for the interior point calculation
            interior_pt = get_interior_point(np.vstack((halfspaces,) + (np.array([1.0, 0, -10.0]),)))
    else:
        interior_pt = get_interior_point(halfspaces)

    # Find boundary intersection of half spaces
    joggled = False
    try:
        hs_inter = HalfspaceIntersection(halfspaces, interior_pt)
    except QhullError:
        warnings.warn("Qhull input might be sub-dimensional, attempting to fix...", RuntimeWarning)

        # move the offset of the the first two boundary halfspaces (x >= 0 and y >= 0) so that
        # the joggled intersections are not outside our boundaries.
        joggled = True
        halfspaces[num_input_halfspaces][-1] = -1e-5
        halfspaces[num_input_halfspaces + 1][-1] = -1e-5
        hs_inter = HalfspaceIntersection(halfspaces, interior_pt, qhull_options="QJ")

    non_inf_vert = np.array([v for v in hs_inter.intersections if np.isfinite(v).all()])
    mx = np.max(non_inf_vert, axis=0)

    if joggled:
        # find largest (x,y) values of halfspace intersections and refuse to continue if too close to (0,0)
        max_xy_intersections = mx[:2]
        if max(max_xy_intersections) < 1e-2:
            raise ValueError("All intersections are less than ({:.3f},{:.3f}). "
                             "Invalid input set, try setting max_pt.".format(*max_xy_intersections))

    # max intersection on y-axis (x=0) implies there are no intersections in gamma direction.
    if np.abs(mx[0]) < np.power(10.0, -15) and np.abs(mx[1]) < np.power(10.0, -15):
        raise ValueError("Max intersection detected at (0,0).  Invalid input set.")

    if np.abs(mx[1]) < np.power(10.0, -15):
        mx[1] = mx[0]
    if np.abs(mx[0]) < np.power(10.0, -15):
        mx[0] = mx[1]

    # At this point we include max boundary planes and recalculate the intersection
    # to correct inf points.  We only do this for single layer
    if max_pt is None:
        if not singlelayer:
            boundary_halfspaces.extend([np.array([0, 1.0, 0, -1.0 * mx[1]]),
                                        np.array([1.0, 0, 0, -1.0 * mx[0]])])
            halfspaces = np.vstack((halfspaces, ) + tuple(boundary_halfspaces[-2:]))

    if not singlelayer:
        # Find boundary intersection of half spaces
        interior_pt = get_interior_point(halfspaces)
        hs_inter = HalfspaceIntersection(halfspaces, interior_pt)

    # revert numpy floating point warnings
    np.seterr(**old_settings)

    # scipy does not support facets by halfspace directly, so we must compute them
    facets_by_halfspace = defaultdict(list)
    for v, idx in zip(hs_inter.intersections, hs_inter.dual_facets):
        if np.isfinite(v).all():
            for i in idx:
                facets_by_halfspace[i].append(v)

    ind_2_domain = {}
    dimension = 2 if singlelayer else 3

    for i, vlist in facets_by_halfspace.items():
        # Empty domains
        if len(vlist) == 0:
            continue

        # these are the boundary planes appended on end
        if not i < num_input_halfspaces:
            continue

        pts = sort_points(vlist)
        pt2rm = []
        for j in range(len(pts) - 1):
            if comp_points(pts[j], pts[j + 1]):
                pt2rm.append(j)
        pt2rm.reverse()
        for j in pt2rm:
            pts.pop(j)
        if len(pts) >= dimension:  # must be at least 2 pts in 2D, 3 pt in 3D, etc.
            ind_2_domain[i] = pts

    # use non-inf vertices to return
    return ind_2_domain
예제 #30
0
from compas_view2.app import App

left = Plane([-1, 0, 0], [-1, 0, 0])
right = Plane([+1, 0, 0], [+1, 0, 0])
top = Plane([0, 0, +1], [0, 0, +1])
bottom = Plane([0, 0, -1], [0, 0, -1])
front = Plane([0, -1, 0], [0, -1, 0])
back = Plane([0, +1, 0], [0, +1, 0])

halfspaces = array(
    [left.abcd, right.abcd, top.abcd, bottom.abcd, front.abcd, back.abcd],
    dtype=float)

interior = array([0, 0, 0], dtype=float)

hsi = HalfspaceIntersection(halfspaces, interior)
hull = ConvexHull(hsi.intersections)

mesh = Mesh.from_vertices_and_faces(
    [hsi.intersections[i] for i in hull.vertices], hull.simplices)
mesh.unify_cycles()

to_merge = []
for a, b in combinations(mesh.faces(), 2):
    na = Vector(*mesh.face_normal(a))
    nb = Vector(*mesh.face_normal(b))
    if na.dot(nb) >= 1:
        if na.cross(nb).length < 1e-6:
            to_merge.append([a, b])

for faces in to_merge: