예제 #1
0
def non_regular_pyramid_3d():
    f_0 = Hyperplane(np.array([-1, 0, -1]), 0)
    f_1 = Hyperplane(np.array([0, -1, -1]), 0)
    f_2 = Hyperplane(np.array([0, 1, -1]), 0)
    f_3 = Hyperplane(np.array([1, 0, -1]), 0)
    f_4 = Hyperplane(np.array([0, 0, 1]), -1)

    hyperplanes = [f_0, f_1, f_2, f_3, f_4]
    p_0 = {(0, -1), (1, -1), (2, -1), (3, -1), (4, -1)}
    return Cell_Decomposition(hyperplanes, [p_0])
예제 #2
0
def simplex():
    a_0 = Hyperplane(np.array([1, 0, 0]), 0)
    a_1 = Hyperplane(np.array([0, 1, 0]), 0)
    a_2 = Hyperplane(np.array([0, 0, 1]), 0)
    a_3 = Hyperplane(np.array([-1, -1, -1]), 1)

    hyperplanes = [a_0, a_1, a_2, a_3]

    simplex = {(0, 1), (1, 1), (2, 1), (3, 1)}
    return Cell_Decomposition(hyperplanes, [simplex])
예제 #3
0
def triangles_meeting_in_one_point():
    # geometry: |><|
    h0 = Hyperplane(np.array([1, 0]), 0)
    h1 = Hyperplane(np.array([1, 0]), -1)
    h2 = Hyperplane(np.array([1, -1]), 0)
    h3 = Hyperplane(np.array([1, 1]), -1)
    hyperplanes = [h0, h1, h2, h3]
    poly1 = {(0, 1), (2, -1), (3, -1)}
    poly2 = {(1, -1), (2, 1), (3, 1)}
    return Cell_Decomposition(hyperplanes, [poly1, poly2])
예제 #4
0
def unbounded_non_regular():
    a_0 = Hyperplane(np.array([-1, 1]), 0)
    a_1 = Hyperplane(np.array([1, 1]), 0)
    a_2 = Hyperplane(np.array([-(1 / 2), -1]), 0)
    a_3 = Hyperplane(np.array([1 / 2, -1]), 0)

    hyperplanes = [a_0, a_1, a_2, a_3]

    left_poly = {(1, -1), (2, -1)}
    right_poly = {(0, -1), (3, -1)}
    return Cell_Decomposition(hyperplanes, [left_poly, right_poly])
예제 #5
0
def translated_triangles():
    # geometry: <\<\ two congruent triangles that meet in 0
    h0 = Hyperplane(np.array([0, 1]), 0)
    h1 = Hyperplane(np.array([-1, 1]), -1)
    h2 = Hyperplane(np.array([1, 1]), 0)
    h3 = Hyperplane(np.array([-1, 1]), 0)
    h4 = Hyperplane(np.array([1, 1]), -1)

    hyperplanes = [h0, h1, h2, h3, h4]
    poly1 = {(0, 1), (1, -1), (2, -1)}
    poly2 = {(0, 1), (3, -1), (4, -1)}
    return Cell_Decomposition(hyperplanes, [poly1, poly2])
예제 #6
0
def paper_example():
    f_0 = Hyperplane(np.array([6, 11]), -100)
    f_1 = Hyperplane(np.array([2, 1]), -28)
    f_2 = Hyperplane(np.array([2, -3]), 4)
    f_3 = Hyperplane(np.array([-2, 7]), -52)

    hyperplanes = [f_0, f_1, f_2, f_3]

    p_0 = set([(0, 1), (1, -1), (3, -1)])
    p_1 = set([(0, 1), (2, -1), (3, -1)])

    return Cell_Decomposition(hyperplanes, [p_0, p_1])
def test_halfspace_restriction_4():
    """
    Halfspace restriction can create new events even if hyperplane is already in cd.hyperplanes.
    Case: From two vertex cones that neutralized each other in original cd only one is valid in
    restricted cd.
    Here vertex at (0,1) is not part of original cd but of restricted cd.
    """
    a_0 = Hyperplane(np.array([1, 0, ]), 0)
    a_1 = Hyperplane(np.array([0, 1]), 0)
    a_2 = Hyperplane(np.array([1, 0]), -1)
    a_3 = Hyperplane(np.array([0, 1]), -1)

    b_0 = Hyperplane(np.array([1, 0, ]), 0.5)
    b_1 = Hyperplane(np.array([0, 1]), -0.5)
    b_2 = Hyperplane(np.array([1, 0]), -0.5)
    b_3 = Hyperplane(np.array([0, 1]), -1.5)

    hyperplanes = [a_0, a_1, a_2, a_3, b_0, b_1, b_2, b_3]
    cube_1 = {(0, 1), (1, 1), (2, -1), (3, -1)}
    cube_2 = {(4, 1), (5, 1), (6, -1), (7, -1)}

    cube_2_restricted = {(4, 1), (5, 1), (6, -1), (7, -1), (3, -1)}
    cd = Cell_Decomposition(hyperplanes, [cube_1, cube_2])
    cd.restrict_to_halfspace(a_3, -1)
    s = Sweep(cd.events)
    cd2 = Cell_Decomposition(hyperplanes, [cube_1, cube_2_restricted])
    s2 = Sweep(cd2.events)
    assert round(s2.calculate_volume(), 5) == 1.25
    assert round(s.calculate_volume(), 5) == 1.25
예제 #8
0
def move_cuts(cuts, cd, tolerance=0.01):
    moved_cuts = []
    for cut in cuts:
        min_dist = tolerance + 1e-3
        min_hyp = None
        if not cut[1]:
            logging.warning('no hyperplanes active at cut: <[}>'.format(
                str(cut[0])))
            moved_cuts.append(cut[0])
            continue
        for hyperplane_ind in cut[1]:
            hyperplane = cd.hyperplanes[hyperplane_ind]
            dist = vector_distance(hyperplane.a, cut[0].a)
            [min_dist,
             min_hyp] = [dist, hyperplane_ind
                         ] if dist < min_dist else [min_dist, min_hyp]
        if min_dist < tolerance:
            logging.debug('hyperplane moved: {} -> {}, dist: {:0.4f}'.format(
                str(cut[0]), str(cd.hyperplanes[min_hyp]), min_dist))
            moved_cuts.append(
                Hyperplane(cd.hyperplanes[min_hyp].a,
                           cd.hyperplanes[min_hyp].b))
        else:
            moved_cuts.append(cut[0])
    return moved_cuts
예제 #9
0
def polytopes_from_json(filepath,
                        description=PolytopeDescription.INNER_DESCRIPTION):
    """
    Method to read polytope points from JSON file.
     Input format is {disj: {polyID1: [...], ..., polyIDk: [...]}}
     If polytopes are given in outer description the elements polyID: [[a1, ..., ad, b],...,[...]]
     correspond to the halfspace a1x1 + ... + adxd + b <= 0
    """
    polys = []
    disj = load_json(filepath)
    for disjID, _ply in disj.items():
        logging.info("Reading polytopes of disjunction {}"
                     " which are given in {}".format(disjID, description.name))

        if description == PolytopeDescription.INNER_DESCRIPTION:

            for i, (plyID, ply) in enumerate(_ply.items()):
                poly_vertices = set([
                    Vertex.vertex_from_coordinates(np.array(coordinates))
                    for coordinates in ply
                ])
                polys.append(Polytope(vertices=poly_vertices))

        elif description == PolytopeDescription.OUTER_DESCRIPTION:

            for i, (plyID, ply) in enumerate(_ply.items()):
                halfspaces = [(Hyperplane(np.array(hyp_vec[:-1]),
                                          hyp_vec[-1]), -1) for hyp_vec in ply]
                polys.append(Polytope(halfspaces=halfspaces))

    return polys
def test_halfspace_restriction():
    h0 = Hyperplane(np.array([0, 1]), -1)
    h1 = Hyperplane(np.array([0, 1]), 0)
    h2 = Hyperplane(np.array([1, 0]), 0)
    h3 = Hyperplane(np.array([1, 0]), -1)
    h4 = Hyperplane(np.array([1, 1]), 0)

    hyperplanes_final = (h0, h1, h2, h3, h4)
    polytope = {(0, -1), (1, 1), (2, 1)}
    polytope_final = {(0, -1), (1, 1), (2, 1), (3, -1), (4, 1)}
    cd = Cell_Decomposition(hyperplanes_final, [polytope_final])
    cd1 = Cell_Decomposition((h0, h1, h2), [polytope])
    cd1.restrict_to_halfspace(h3, -1)
    cd1.restrict_to_halfspace(h4, 1)
    assert set(cd1.events).issubset(set(cd.events))
    assert set(cd.events).issubset(set(cd1.events))
    assert np.isclose(Sweep(cd.events).calculate_volume(), Sweep(cd1.events).calculate_volume())
def test_both_halfspace_restriction(simplex_in_cube):
    '''
    test restricts cell decomposition to other halfspace of shared hyperplane of simplex and
    unit cube. All events lay on the hyperplane or outside of the restriction halfspace.
    No cone can be legal for events on the halfspace.
    '''
    cut_plane = Hyperplane(np.array([1, 0]), 1)
    simplex_in_cube.restrict_to_halfspace(cut_plane, -1)
    assert len(simplex_in_cube.events) == 0
예제 #12
0
def cube_simplex_overlapping_3d_2():
    c_0 = Hyperplane(np.array([1, 0, 0]), 0)
    c_1 = Hyperplane(np.array([0, 1, 0]), 0)
    c_2 = Hyperplane(np.array([0, 0, 1]), 0)
    c_3 = Hyperplane(np.array([1, 0, 0]), -1)
    c_4 = Hyperplane(np.array([0, 1, 0]), -1)
    c_5 = Hyperplane(np.array([0, 0, 1]), -1)

    s_0 = Hyperplane(np.array([1, 1, 1]), -4)
    s_1 = Hyperplane(np.array([1, 0, 0]), -0.5)
    s_2 = Hyperplane(np.array([0, 1, 0]), -0.5)
    s_3 = Hyperplane(np.array([0, 0, 1]), -0.5)

    hyperplanes = [c_0, c_1, c_2, c_3, c_4, c_5, s_0, s_1, s_2, s_3]

    simplex = {(6, -1), (7, 1), (8, 1), (9, 1)}
    unit_cube = {(0, 1), (1, 1), (2, 1), (3, -1), (4, -1), (5, -1)}
    return Cell_Decomposition(hyperplanes, [unit_cube, simplex])
예제 #13
0
def cube_simplex_overlapping_3d_imprecise():
    k = 1e+12
    c_0 = Hyperplane(np.array([k, 0, 0]), 0)
    c_1 = Hyperplane(np.array([0, k, 0]), 0)
    c_2 = Hyperplane(np.array([0, 0, k]), 0)
    c_3 = Hyperplane(np.array([k, 0, 0]), -k)
    c_4 = Hyperplane(np.array([0, k, 0]), -k)
    c_5 = Hyperplane(np.array([0, 0, k]), -k)

    s_0 = Hyperplane(np.array([k, k, k]), -3.5 * k)
    s_1 = Hyperplane(np.array([k, 0, 0]), -0.5 * k)
    s_2 = Hyperplane(np.array([0, k, 0]), -0.5 * k)
    s_3 = Hyperplane(np.array([0, 0, k]), -0.5 * k)

    hyperplanes = [c_0, c_1, c_2, c_3, c_4, c_5, s_0, s_1, s_2, s_3]

    simplex = {(6, -1), (7, 1), (8, 1), (9, 1)}
    unit_cube = {(0, 1), (1, 1), (2, 1), (3, -1), (4, -1), (5, -1)}
    return Cell_Decomposition(hyperplanes, [unit_cube, simplex])
def test_halfspace_restriction_2():
    a_0 = Hyperplane(np.array([1, 0, ]), 0)
    a_1 = Hyperplane(np.array([0, 1]), 0)
    a_2 = Hyperplane(np.array([1, 1]), -1)
    a_3 = Hyperplane(np.array([1, 0]), -1)
    a_4 = Hyperplane(np.array([0, 1]), -1)
    hyperplanes_start = [a_0, a_1, a_2, a_3]
    hyperplanes_final = [a_0, a_1, a_2, a_3, a_4]

    simplex = {(0, 1), (1, 1), (2, -1)}
    unit_cube_start = {(0, 1), (1, 1), (3, -1)}
    unit_cube = {(0, 1), (1, 1), (3, -1), (4, -1)}

    cd = Cell_Decomposition(hyperplanes_final, [simplex, unit_cube])
    cd1 = Cell_Decomposition(hyperplanes_start, [simplex, unit_cube_start])
    cd1.restrict_to_halfspace(a_4, -1)

    assert set(cd.events).issubset(set(cd1.events))
    assert set(cd1.events).issubset(set(cd.events))
    assert round(Sweep(cd.events).calculate_volume(), 8) == round(
        Sweep(cd1.events).calculate_volume(), 8)
예제 #15
0
def overlapping_simplices_2():
    s_0 = Hyperplane(np.array([1, 0, 0]), 0)
    s_1 = Hyperplane(np.array([0, 1, 0]), 0)
    s_2 = Hyperplane(np.array([0, 0, 1]), 0)
    s_3 = Hyperplane(np.array([1, 1, 1]), -8)

    s_4 = Hyperplane(np.array([0, 0, 1]), -1)
    s_5 = Hyperplane(np.array([0, 1, 0]), -1)
    s_6 = Hyperplane(np.array([1, 0, 0]), -1)
    s_7 = Hyperplane(np.array([1, 1, -1]), -3)

    hyperplanes = [s_0, s_1, s_2, s_3, s_4, s_5, s_6, s_7]
    simplex_1 = {(0, 1), (1, 1), (2, 1), (3, -1)}
    simplex_2 = {(4, -1), (5, 1), (6, 1), (7, -1)}
    polytopes = [simplex_1, simplex_2]
    return Cell_Decomposition(hyperplanes, polytopes)
예제 #16
0
def simplex_cube_disconnected():
    s_0 = Hyperplane(np.array([1, 0]), 0)
    s_1 = Hyperplane(np.array([0, 1]), 0)
    s_2 = Hyperplane(np.array([1, 1]), -1)

    c_0 = Hyperplane(np.array([1, 0]), -2)
    c_1 = Hyperplane(np.array([0, 1]), -2)
    c_2 = Hyperplane(np.array([1, 0]), -3)
    c_3 = Hyperplane(np.array([0, 1]), -3)
    hyperplanes = [s_0, s_1, s_2, c_0, c_1, c_2, c_3]
    simplex = {(0, 1), (1, 1), (2, -1)}
    cube = {(3, 1), (4, 1), (5, -1), (6, -1)}
    return Cell_Decomposition(hyperplanes, [simplex, cube])
예제 #17
0
def simplex_in_cube_3d():
    a_0 = Hyperplane(np.array([1, 0, 0]), 0)
    a_1 = Hyperplane(np.array([0, 1, 0]), 0)
    a_2 = Hyperplane(np.array([0, 0, 1]), 0)
    a_3 = Hyperplane(np.array([-1, -1, -1]), 1)
    a_4 = Hyperplane(np.array([1, 0, 0]), -1)
    a_5 = Hyperplane(np.array([0, 1, 0]), -1)
    a_6 = Hyperplane(np.array([0, 0, 1]), -1)

    hyperplanes = [a_0, a_1, a_2, a_3, a_4, a_5, a_6]

    simplex = {(0, 1), (1, 1), (2, 1), (3, 1)}
    unit_cube = {(0, 1), (1, 1), (2, 1), (4, -1), (5, -1), (6, -1)}
    return Cell_Decomposition(hyperplanes, [unit_cube, simplex])
예제 #18
0
def cube_simplex_overlapping_2d():
    c_0 = Hyperplane(np.array([1, 0]), 0)
    c_1 = Hyperplane(np.array([0, 1]), 0)
    c_2 = Hyperplane(np.array([1, 0]), -1)
    c_3 = Hyperplane(np.array([0, 1]), -1)

    s_0 = Hyperplane(np.array([1, 0]), -0.5)
    s_1 = Hyperplane(np.array([0, 1]), -0.5)
    s_2 = Hyperplane(np.array([1, 1]), -1.5)
    hyperplanes = [c_0, c_1, c_2, c_3, s_0, s_1, s_2]

    simplex = {(4, 1), (5, 1), (6, -1)}
    unit_cube = {(0, 1), (1, 1), (2, -1), (3, -1)}
    return Cell_Decomposition(hyperplanes, [unit_cube, simplex])
예제 #19
0
def unit_cube():
    a_0 = Hyperplane(np.array([1, 0, 0]), 0)
    a_1 = Hyperplane(np.array([0, 1, 0]), 0)
    a_2 = Hyperplane(np.array([0, 0, 1]), 0)
    a_3 = Hyperplane(np.array([1, 0, 0]), -1)
    a_4 = Hyperplane(np.array([0, 1, 0]), -1)
    a_5 = Hyperplane(np.array([0, 0, 1]), -1)

    hyperplanes = [a_0, a_1, a_2, a_3, a_4, a_5]

    unit_cube = {(0, 1), (1, 1), (2, 1), (3, -1), (4, -1), (5, -1)}
    return Cell_Decomposition(hyperplanes, [unit_cube])
예제 #20
0
파일: facet.py 프로젝트: LovisAnderson/hacd
def facet_cuts(ACDNode, nr_cuts=10):
    """
    Method returns best cuts whereby cuts are drawn from the defining Hyperplanes.
    They are scored by the derivation of the convexification error
    :param ACDNode: ACDnode which carries cell decompositions for
    :param nr_cuts: The best nr_of_cuts are returned.
    :return: best nr_cuts as list of hyperplane objects
    """

    cuts = []
    for ind, hyperplane in enumerate(ACDNode.union_cd.hyperplanes):
        union_sweep, conv_sweep = get_sweeps(ACDNode, hyperplane)

        diff_delta = diff_delta_at_facet(union_sweep, conv_sweep, ind)
        logging.debug('cut: <{}> ; difference delta: {}'.format(str(hyperplane), diff_delta))
        cuts.append((Hyperplane(hyperplane.a, hyperplane.b), diff_delta))
    cuts = sorted(cuts, key=lambda x: x[1], reverse=True)
    return list(zip(*cuts[:nr_cuts])[0])
예제 #21
0
def sweep_cuts(node, n=10, sweeps_per_orthant=100):
    """
    Method to generate cuts via Sweep-Plane.
    :param node: Node for which cuts are to be generated
    :param n: Number of cuts to be returned.
    :param sweeps_per_orthant: Number of sweeps that are tried
    :return: a list of the best n cuts
    """

    assert isinstance(n, int) and n > 0
    nr_sweeps = sweeps_per_orthant * 2**node.dim
    # Generate random sweep planes.
    logging.debug("-- generating {} random sweep planes...".format(nr_sweeps))
    sweepplanes = ana.random_normed_directions(nr_sweeps, node.dim)

    # Apply sweep plane algorithm to the union of polytopes and their convex hull.
    logging.debug("-- applying sweep plane algorithm...")
    sweeps_polys, sweeps_convhull = ana.convex_hull_and_union_sweeps(
        node.union_cd, node.convex_cd, sweepplanes)
    cut_data = ana.cut_data(sweeps_polys, sweeps_convhull)

    # Choose cuts that are distinct (enough -> see tolerance in method)
    logging.info("-- selecting {} best cuts...".format(n))

    # tolerance dependant on dimension and nr of cuts (n)
    close_vector_tolerance = 0.005 / np.sqrt(n) * 2**node.dim
    best_cuts = get_best_distinct_cuts(cut_data,
                                       nr_of_cuts=n,
                                       tolerance=close_vector_tolerance)
    cuts_with_hyperplanes = [[
        Hyperplane(sweep['direction'], -sweep['cut_lambda']),
        sweep['active_hyperplanes']
    ] for _, sweep in best_cuts.iterrows()]
    # Move cuts to closest hyperplanes if close enough, tolerance
    cuts = move_cuts(cuts_with_hyperplanes,
                     node.union_cd,
                     tolerance=close_vector_tolerance * 0.5)

    # Return n best cut suggestions (sorted according to score).
    return cuts
예제 #22
0
def hole_2d():
    hyperplanes = OrderedSet()
    a1 = np.array([1, 0])
    a2 = np.array([-1, 0])

    a3 = np.array([0, 1])
    a4 = np.array([0, -1])

    p1 = Hyperplane(a1, 0)
    p2 = Hyperplane(a2, -1)
    p3 = Hyperplane(a3, -1)
    p4 = Hyperplane(a4, 0)
    P1 = set(zip(range(4), [-1] * 4))

    q1 = Hyperplane(a1, -1)
    q2 = Hyperplane(a2, 0)
    q3 = Hyperplane(a3, 0)
    q4 = Hyperplane(a4, -1)
    P2 = set()
    for h in [q1, q2, q3, q4]:
        ind = hyperplanes.add(h)
        P2.add((ind, -1))

    r1 = Hyperplane(a1, -2)
    r2 = Hyperplane(a2, 1)
    r3 = Hyperplane(a3, -1)
    r4 = Hyperplane(a4, 0)
    P3 = set()
    for h in [r1, r2, r3, r4]:
        ind = hyperplanes.add(h)
        P3.add((ind, -1))

    s1 = Hyperplane(a1, -1)
    s2 = Hyperplane(a2, 0)
    s3 = Hyperplane(a3, -2)
    s4 = Hyperplane(a4, 1)
    P4 = set()
    for h in [s1, s2, s3, s4]:
        ind = hyperplanes.add(h)
        P4.add((ind, -1))

    return Cell_Decomposition(hyperplanes, [P1, P2, P3, P4])
예제 #23
0
def hole_3d():
    a1 = np.array([1, 0, 0])
    a2 = np.array([-1, 0, 0])

    a3 = np.array([0, 1, 0])
    a4 = np.array([0, -1, 0])

    a5 = np.array([0, 0, 1])
    a6 = np.array([0, 0, -1])

    p0 = Hyperplane(a5, -1)
    p1 = Hyperplane(a6, 0)

    p2 = Hyperplane(a1, 0)
    p3 = Hyperplane(a2, -1)
    p4 = Hyperplane(a3, -1)
    p5 = Hyperplane(a4, 0)
    P1 = set(zip(range(6), [-1] * 6))

    q1 = Hyperplane(a1, -1)
    q2 = Hyperplane(a2, 0)
    q3 = Hyperplane(a3, 0)
    q4 = Hyperplane(a4, -1)
    P2 = set(zip(range(2), [-1] * 2) + zip(range(6, 10), [-1] * 4))

    r1 = Hyperplane(a1, -2)
    r2 = Hyperplane(a2, 1)
    r3 = Hyperplane(a3, -1)
    r4 = Hyperplane(a4, 0)
    P3 = set(zip(range(2), [-1] * 2) + zip(range(10, 14), [-1] * 4))

    s1 = Hyperplane(a1, -1)
    s2 = Hyperplane(a2, 0)
    s3 = Hyperplane(a3, -2)
    s4 = Hyperplane(a4, 1)
    P4 = set(zip(range(2), [-1] * 2) + zip(range(14, 18), [-1] * 4))
    hyperplanes = [p0, p1, p2, p3, p4, p5, q1, q2, q3, q4, r1, r2, r3, r4, s1, s2, s3, s4]

    return Cell_Decomposition(hyperplanes, [P1, P2, P3, P4])
예제 #24
0
def hole_4d():
    hyperplanes = OrderedSet()
    a1 = np.array([1, 0, 0, 0])
    a2 = np.array([-1, 0, 0, 0])

    a3 = np.array([0, 1, 0, 0])
    a4 = np.array([0, -1, 0, 0])

    a5 = np.array([0, 0, 1, 0])
    a6 = np.array([0, 0, -1, 0])

    a7 = np.array([0, 0, 0, 1])
    a8 = np.array([0, 0, 0, -1])

    p0 = Hyperplane(a5, -1)
    p1 = Hyperplane(a6, 0)
    p2 = Hyperplane(a7, -1)
    p3 = Hyperplane(a8, 0)

    p4 = Hyperplane(a1, 0)
    p5 = Hyperplane(a2, -1)
    p6 = Hyperplane(a3, -1)
    p7 = Hyperplane(a4, 0)

    P1 = set()
    for h in [p0, p1, p2, p3, p4, p5, p6, p7]:
        index = hyperplanes.add(h)
        P1.add((index, -1))

    q1 = Hyperplane(a1, -1)
    q2 = Hyperplane(a2, 0)
    q3 = Hyperplane(a3, 0)
    q4 = Hyperplane(a4, -1)

    P2 = set()
    for h in [p0, p1, p2, p3, q1, q2, q3, q4]:
        index = hyperplanes.add(h)
        P2.add((index, -1))

    r1 = Hyperplane(a1, -2)
    r2 = Hyperplane(a2, 1)
    r3 = Hyperplane(a3, -1)
    r4 = Hyperplane(a4, 0)
    P3 = set()
    for h in [p0, p1, p2, p3, r1, r2, r3, r4]:
        index = hyperplanes.add(h)
        P3.add((index, -1))

    s1 = Hyperplane(a1, -1)
    s2 = Hyperplane(a2, 0)
    s3 = Hyperplane(a3, -2)
    s4 = Hyperplane(a4, 1)
    P4 = set()
    for h in [p0, p1, p2, p3, s1, s2, s3, s4]:
        index = hyperplanes.add(h)
        P4.add((index, -1))

    return Cell_Decomposition(hyperplanes, [P1, P2, P3, P4])
def test_halfspace_restriction_3(translated_triangles):
    a = Hyperplane(np.array([1., 0., ]), 0.)
    translated_triangles.restrict_to_halfspace(a, 1)
    assert (len(translated_triangles.events)) == 3
    s = Sweep(translated_triangles.events)
    assert round(s.calculate_volume(), 6) == 0.25