Esempio n. 1
0
    def region_rotation_test(self):
        p = pc.Region([pc.Polytope(self.A, self.b)])
        p1 = pc.Region([pc.Polytope(self.A, self.b)])
        p2 = pc.Region([pc.Polytope(self.Ab2[:, 0:2], self.Ab2[:, 2])])
        p3 = pc.Region([pc.Polytope(self.Ab3[:, 0:2], self.Ab3[:, 2])])
        p4 = pc.Region([pc.Polytope(self.Ab4[:, 0:2], self.Ab4[:, 2])])

        p = p.rotation(0, 1, np.pi / 2)
        print(p.bounding_box)
        assert (p == p2)
        assert (not p == p3)
        assert (not p == p4)
        assert (not p == p1)
        assert_allclose(p.chebXc, [-0.5, 0.5])

        p = p.rotation(0, 1, np.pi / 2)
        assert (p == p3)
        assert_allclose(p.chebXc, [-0.5, -0.5])

        p = p.rotation(0, 1, np.pi / 2)
        assert (p == p4)
        assert_allclose(p.chebXc, [0.5, -0.5])

        p = p.rotation(0, 1, np.pi / 2)
        assert (p == p1)
        assert_allclose(p.chebXc, [0.5, 0.5])
Esempio n. 2
0
    def comparison_test(self):
        p = pc.Polytope(self.A, self.b)
        p2 = pc.Polytope(self.A, 2*self.b)

        assert(p <= p2)
        assert(not p2 <= p)
        assert(not p2 == p)

        r = pc.Region([p])
        r2 = pc.Region([p2])

        assert(r <= r2)
        assert(not r2 <= r)
        assert(not r2 == r)

        # test H-rep -> V-rep -> H-rep
        v = pc.extreme(p)
        p3 = pc.qhull(v)
        assert(p3 == p)

        # test V-rep -> H-rep with d+1 points
        p4 = pc.qhull(np.array([[0, 0], [1, 0], [0, 1]]))
        assert(p4 == pc.Polytope(
            np.array([[1, 1], [0, -1], [0, -1]]),
            np.array([1, 0, 0])))
Esempio n. 3
0
    def region_translation_test(self):
        p = pc.Region([pc.Polytope(self.A, self.b)])
        p1 = pc.Region([pc.Polytope(self.A, self.b)])
        p2 = pc.Region([pc.Polytope(self.Ab2[:, 0:2], self.Ab2[:, 2])])

        p = p.translation([-1, 0])
        assert (p == p2)
        assert (not p == p1)
        p = p.translation([1, 0])
        assert (p == p1)
Esempio n. 4
0
    def region_full_dim_test(self):
        assert not pc.is_fulldim(pc.Region())

        p1 = pc.Polytope(self.A, self.b)
        p2 = pc.Polytope(self.Ab2[:, 0:2], self.Ab2[:, 2])
        reg = pc.Region([p1, p2])
        assert pc.is_fulldim(reg)

        # Adding empty polytopes should not affect the
        # full-dimensional status of this region.
        reg.list_poly.append(pc.Polytope())
        assert pc.is_fulldim(reg)
        reg.list_poly.append(pc.Polytope(self.A, self.b - 1e3))
        assert pc.is_fulldim(reg)
Esempio n. 5
0
def erode(poly, eps):
    """
    Given a polytope compute eps erosion and give polytope under approximation

    For a given polytope a polytopic under approximation of the $eps$-eroded set is computed.
    An e-eroded Pe set of P is defined as:
        Pe = {x |x+n in P forall n in Ball(e)}
    where Ball(e) is the epsilon neighborhood with norm |n|<e

    The current implementation shifts hyper-planes  with eps over there normal,
    / / / / / / / | +   |
     / / / / / / /| eps |
     / / / / / / /| +   |
     / / / / / / /| eps |
     / / / / / / /| +   |

    :param poly: original polytope
    :param eps: positive scalar value with which the polytope is eroded
    :return: polytope
    """
    if isinstance(poly, polytope.Region):
        er_reg = []
        for pol in poly.list_poly:
            assert isinstance(pol, polytope.Polytope)
            er_reg += [erode(pol, eps)]
        return polytope.Region(er_reg)

    A = poly.A
    b = poly.b
    b_e = []
    for A_i, b_i in itertools.product(A, b):
        b_e += [[b_i - eps * np.linalg.norm(A_i, 2)]]

    return polytope.Polytope(A, np.array(b_e))
Esempio n. 6
0
def part2convex(ppp):
    """This function takes a proposition preserving partition and generates
    another proposition preserving partition such that each part in the new
    partition is a convex polytope

    @type ppp: L{PropPreservingPartition}

    @return: refinement into convex polytopes and
        map from new to old Regions
    @rtype: (L{PropPreservingPartition}, list)
    """
    cvxpart = PropPreservingPartition(domain=copy.deepcopy(ppp.domain),
                                      prop_regions=copy.deepcopy(
                                          ppp.prop_regions))
    new2old = []
    for i in xrange(len(ppp.regions)):
        simplified_reg = pc.union(ppp.regions[i],
                                  ppp.regions[i],
                                  check_convex=True)

        for j in xrange(len(simplified_reg)):
            region_now = pc.Region([simplified_reg[j]], ppp.regions[i].props)
            cvxpart.regions.append(region_now)
            new2old += [i]

    cvxpart.adj = pc.find_adjacent_regions(cvxpart).copy()

    return (cvxpart, new2old)
Esempio n. 7
0
 def setUp(self):
     self.A1 = np.eye(2)
     self.A2 = np.array([[0, 1], [0, 0]])
     self.B1 = np.array([[0] ,[1]])
     self.B2 = np.array([[1], [0]])
     self.poly1 = pc.Polytope.from_box([[0, 1], [0, 1]])
     self.poly2 = pc.Polytope.from_box([[1, 2], [0, 1]])
     self.total_box = pc.Region(list_poly=[self.poly1, self.poly2])
     self.Uset = pc.Polytope.from_box([[0, 1]])
     self.env_labels = ('hi', 'hello')
     self.sys_labels = ('mode1',)
     self.disc_domain_size = (2, 1)
     self.LTI1 = hybrid.LtiSysDyn(A=self.A1, B=self.B1,
                                  Uset=self.Uset, domain=self.poly1,
                                  time_semantics='sampled', timestep=.1)
     self.LTI2 = hybrid.LtiSysDyn(A=self.A2, B=self.B2,
                                  Uset=self.Uset, domain=self.poly2,
                                  time_semantics='sampled', timestep=.1)
     self.LTI3 = hybrid.LtiSysDyn(A=self.A1, B=self.B1,
                                  Uset=self.Uset, domain=self.poly2,
                                  time_semantics='sampled', timestep=.1)
     self.LTI4 = hybrid.LtiSysDyn(A=self.A2, B=self.B2,
                                  Uset=self.Uset, domain=self.poly1,
                                  time_semantics='sampled', timestep=.1)
     self.PWA1 = hybrid.PwaSysDyn(list_subsys=[self.LTI1, self.LTI2],
                                  domain=self.total_box,
                                  time_semantics='sampled', timestep=.1)
     self.PWA2 = hybrid.PwaSysDyn(list_subsys=[self.LTI3, self.LTI4],
                                  domain=self.total_box,
                                  time_semantics='sampled', timestep=.1)
     self.dynamics1 = {(self.env_labels[0], self.sys_labels[0]): self.PWA1,
                       (self.env_labels[1], self.sys_labels[0]): self.PWA2}
Esempio n. 8
0
def _solve_closed_loop_bounded_horizon(
        P1, P2, ssys, N, trans_set=None):
    """Under-approximate states in P1 that can reach P2 in <= N steps.

    See docstring of function `_solve_closed_loop_fixed_horizon`
    for details.
    """
    _print_horizon_warning()
    p1 = P1.copy()  # initial set
    p2 = P2.copy()  # terminal set
    if trans_set is None:
        pinit = p1
    else:
        pinit = trans_set
    # backwards in time
    s = pc.Region()
    for i in xrange(N, 0, -1):
        # first step from P1
        if i == 1:
            pinit = p1
        p2 = solve_open_loop(pinit, p2, ssys, 1, trans_set)
        p2 = pc.reduce(p2)
        # running union
        s = s.union(p2, check_convex=True)
        s = pc.reduce(s)
        # empty target polytope ?
        if not pc.is_fulldim(p2):
            break
    if not pc.is_fulldim(s):
        return pc.Polytope()
    s = pc.reduce(s)
    return s
Esempio n. 9
0
 def region_empty_test(self):
     # Note that as of commit a037b555758ed9ee736fa7cb324d300b8d622fb4
     # Region.__init__ deletes empty polytopes from
     # the given list of polytopes at instantiation.
     reg = pc.Region()
     reg.list_poly = [pc.Polytope(), pc.Polytope()]
     assert len(reg) > 0
     assert pc.is_empty(reg)
Esempio n. 10
0
 def setUp(self):
     self.A1 = np.eye(2)
     self.A2 = np.array([[0, 1], [0, 0]])
     self.B1 = np.array([[0] ,[1]])
     self.B2 = np.array([[1], [0]])
     self.poly1 = pc.Polytope.from_box([[0, 1], [0, 1]])
     self.poly2 = pc.Polytope.from_box([[1, 2], [0, 1]])
     self.total_box = pc.Region(list_poly=[self.poly1, self.poly2])
     self.Uset = pc.Polytope.from_box([[0, 1]])
Esempio n. 11
0
def shrinkRegion(origRegion, epsilon):
    """Returns a region where all polytopes in the Region
	origRegion have been shrunk a distance 'epsilon'"""
    list_poly = copy.deepcopy(origRegion.list_poly)
    props = copy.deepcopy(origRegion.props)
    lengthie = len(list_poly)
    for i in range(lengthie):
        list_poly[i] = shrinkPoly(list_poly[i], epsilon)
    return pc.Region(list_poly=list_poly, props=props)
Esempio n. 12
0
def _import_region(node):

	# Get the polytope list and import the polytopes
	polytope_list = node.findall(N_POLYLIST)[0]

	# Import the polytopes
	list_poly = _import_xml(polytope_list)

	return polytope.Region(list_poly=list_poly)
Esempio n. 13
0
 def is_inside_test(self):
     box = [[0.0, 1.0], [0.0, 2.0]]
     p = pc.Polytope.from_box(box)
     point = np.array([0.0, 1.0])
     abs_tol = 0.01
     assert pc.is_inside(p, point)
     assert pc.is_inside(p, point, abs_tol)
     region = pc.Region([p])
     assert pc.is_inside(region, point)
     assert pc.is_inside(region, point, abs_tol)
     point = np.array([2.0, 0.0])
     assert not pc.is_inside(p, point)
     assert not pc.is_inside(p, point, abs_tol)
     region = pc.Region([p])
     assert not pc.is_inside(region, point)
     assert not pc.is_inside(region, point, abs_tol)
     abs_tol = 1.2
     assert pc.is_inside(p, point, abs_tol)
     assert pc.is_inside(region, point, abs_tol)
Esempio n. 14
0
 def unit_polytope(self, i):
     try:
         return self._unit_polytope[i]
     except KeyError:
         r = self.unit_region[i]
         if isinstance(r, pt.Region):
             pass
         else:
             if isinstance(r, (tuple, list)):
                 r = pt.box2poly(list(zip(*r)))
                 self._unit_polytope[i] = r
             r = pt.Region([r])
         return r
Esempio n. 15
0
def prop2part_test():
    state_space = pc.Polytope.from_box(np.array([[0., 2.],[0., 2.]]))

    cont_props = []
    A = []
    b = []

    A.append(np.array([[1., 0.],
                       [-1., 0.],
                       [0., 1.],
                       [0., -1.]]))
    b.append(np.array([[.5, 0., .5, 0.]]).T)
    cont_props.append(pc.Polytope(A[0], b[0]))

    A.append(np.array([[1., 0.],
                       [-1., 0.],
                       [0., 1.],
                       [0., -1.]]))
    b.append(np.array([[2., -1.5, 2., -1.5]]).T)
    cont_props.append(pc.Polytope(A[1], b[1]))

    cont_props_dict = {"C"+str(i) : pc.Polytope(A[i], b[i]) for i in range(2)}

    mypartition = prop2part(state_space, cont_props_dict)
    print(mypartition)

    ref_adjacency = np.array([[1,0,1],[0,1,1],[1,1,1]])
    assert np.all(mypartition.adj.todense() == ref_adjacency)

    assert len(mypartition.regions) == 3

    for reg in mypartition.regions[0:2]:
        assert len(reg.props) == 1
        assert len(reg) == 1

        assert cont_props_dict == mypartition.prop_regions

    assert len(mypartition.regions[2].props) == 0

    assert len(mypartition.regions[2]) == 3
    dum = state_space.copy()
    for reg in mypartition.regions[0:2]:
        dum = dum.diff(reg)
    assert pc.is_empty(dum.diff(mypartition.regions[2]) )
    assert pc.is_empty(mypartition.regions[2].diff(dum) )

    assert(mypartition.preserves_predicates())

    # invalidate it
    mypartition.regions += [pc.Region([pc.Polytope(A[0], b[0])], {})]
    assert(not mypartition.preserves_predicates())
Esempio n. 16
0
    def is_cover(self):
        """Return True if Regions cover domain
        """
        union = pc.Region()
        for region in self.regions:
            union += region

        if not self.domain <= union:
            msg = 'partition does not cover domain.'
            logger.Error(msg)
            warnings.warn(msg)
            return False
        else:
            return True
Esempio n. 17
0
def volumes_for_reachability(part, max_num_poly):
    if len(part) <= max_num_poly:
        return part
    
    vol_list = np.zeros(len(part) )
    for i in xrange(len(part) ):
        vol_list[i] = part[i].volume
    
    ind = np.argsort(-vol_list)
    temp = []
    for i in ind[range(max_num_poly) ]:
        temp.append(part[i] )
    
    part = pc.Region(temp, [])
    return part
Esempio n. 18
0
 def region_contains_test(self):
     A = np.array([[1.0], [-1.0]])
     b = np.array([1.0, 0.0])
     poly = pc.Polytope(A, b)
     polys = [poly]
     reg = pc.Region(polys)
     assert 0.5 in reg
     # small positive tolerance (includes boundary)
     points = np.array([[-1.0, 0.0, 0.5, 1.0, 2.0]])
     c = reg.contains(points)
     c_ = np.array([[False, True, True, True, False]], dtype=bool)
     # zero tolerance (excludes boundary)
     points = np.array([[-1.0, 0.0, 0.5, 1.0, 2.0]])
     c = reg.contains(points, abs_tol=0)
     c_ = np.array([[False, False, True, False, False]], dtype=bool)
     assert np.all(c == c_), c
Esempio n. 19
0
    def get_bounded_region(self, in_c, in_b):
        coefficients = numpy.zeros(
            [len(self.domain.real_vars) * 2 + 1,
             len(self.domain.real_vars)])
        b = numpy.zeros(len(self.domain.real_vars) * 2 + 1)
        for i in range(len(self.domain.real_vars)):
            coefficients[2 * i, i] = -1
            coefficients[2 * i + 1, i] = 1

            lb, ub = self.domain.var_domains[self.domain.real_vars[i]]
            b[2 * i] = -lb
            b[2 * i + 1] = ub

        coefficients[-1, :] = in_c
        b[-1] = in_b

        return pc.Region([pc.Polytope(coefficients, b)])
Esempio n. 20
0
def dilate(poly, eps):
    """
    The function dilates a polytope.

    For a given polytope a polytopic over apoproximation of the $eps$-dilated set is computed.
    An e-dilated Pe set of P is defined as:
        Pe = {x+n|x in P ^ n in Ball(e)}
    where Ball(e) is the epsilon neighborhood with norm |n|<e

    The current implementation is quite crude, hyper-boxes are placed over the original vertices
    and the returned polytope is a qhull of these new vertices.
    :param poly: original polytope
    :param eps: positive scalar value with which the polytope is dilated
    :return: polytope
    """
    if isinstance(poly, polytope.Region):
        dil_reg = []
        for pol in poly.list_poly:
            assert isinstance(pol, polytope.Polytope)
            dil_reg += [dilate(pol, eps)]
        return polytope.Region(dil_reg)

    vertices = extreme(poly)
    dim = len(vertices[0])  # this is the dimensionality of the space
    dil_eps = dim * [[-eps, eps]]
    dil_eps_v = [np.array(n) for n in itertools.product(*dil_eps)
                 ]  # vectors with (+- eps,+- eps, +- eps,...)

    new_vertices = []
    for v, d in itertools.product(vertices, dil_eps_v):

        new_vertices += [[np.array(v).flatten() + np.array(d).flatten()]]

        # make box
        # print("add vertices part:", np.array(v).flatten() +  np.array(d).flatten())
    VV = np.concatenate(new_vertices)
    # print("V", VV)
    return qhull(VV)
Esempio n. 21
0
def solve_closed_loop(
    P1, P2, ssys, N,
    use_all_horizon=False, trans_set=None
):
    """Compute S0 \subseteq P1 from which P2 is closed-loop N-reachable.
    
    @type P1: C{Polytope} or C{Region}
    @type P2: C{Polytope} or C{Region}
    
    @param ssys: system dynamics
    
    @param N: horizon length
    @type N: int > 0
    
    @param use_all_horizon:
        - if True, then take union of S0 sets
        - Otherwise, chain S0 sets (funnel-like)
    @type use_all_horizon: bool
    
    @param trans_set: If provided,
        then intermediate steps are allowed
        to be in trans_set.
        
        Otherwise, P1 is used.
    """
    if use_all_horizon:
        raise ValueError('solve_closed_loop() with use_all_horizon=True '
                         'is still under development\nand currently '
                         'unavailable.')

    p1 = P1.copy() # Initial set
    p2 = P2.copy() # Terminal set
    
    if trans_set is not None:
        Pinit = trans_set
    else:
        Pinit = p1
    
    # backwards in time
    s0 = pc.Region()
    reached = False
    for i in xrange(N, 0, -1):
        # first step from P1
        if i == 1:
            Pinit = p1
        
        p2 = solve_open_loop(Pinit, p2, ssys, 1, trans_set)
        s0 = s0.union(p2, check_convex=True)
        s0 = pc.reduce(s0)
        
        # empty target polytope ?
        if not pc.is_fulldim(p2):
            break
        
        old_reached = reached
        
        # overlaps initial set ?
        if p1.intersect(p2):
            s0 = s0.union(p2, check_convex=True)
            s0 = pc.reduce(s0)
        
        # we went past it -> don't continue
        if old_reached is True and reached is False:
            logger.info('stopped intersecting si')
            #break
        
        if reached is True:
            break
    
    if not pc.is_fulldim(s0):
        return pc.Polytope()
    
    s0 = pc.reduce(s0)
    return s0
Esempio n. 22
0
def pwa_shrunk_partition(pwa_sys, ppp, eps, abs_tol=1e-5):
    """This function takes:
    
      - a piecewise affine system C{pwa_sys} and
      - a proposition-preserving partition C{ppp}
          whose domain is a subset of the domain of C{pwa_sys}
      - a shrinkage factor C{eps}
    
    and returns a *refined* proposition preserving partition
    where in each region a unique subsystem of pwa_sys is active
    and pwa_sys domains are shrunk to account for estimation 
    errors.

    See Also
    ========
    L{pwa_partition}
    
    @type pwa_sys: L{hybrid.PwaSysDyn}
    @type ppp: L{PropPreservingPartition}
    
    @return: new partition and associated maps:
        
        - new partition C{new_ppp}
        - map of C{new_ppp.regions} to C{pwa_sys.list_subsys}
        - map of C{new_ppp.regions} to C{ppp.regions}
    
    @rtype: C{(L{PropPreservingPartition}, list, list)}
    """

    new_list = []
    subsys_list = []
    parents = []
    for i, subsys in enumerate(pwa_sys.list_subsys):
        dom = shrinkPoly(subsys.domain, eps)
        for j, region in enumerate(ppp.regions):
            isect = pc.reduce(region.intersect(dom))

            if pc.is_fulldim(isect):
                rc, xc = pc.cheby_ball(isect)

                if rc < abs_tol:
                    msg = 'One of the regions in the refined PPP is '
                    msg += 'too small, this may cause numerical problems'
                    warnings.warn(msg)

                # not Region yet, but Polytope ?
                if len(isect) == 0:
                    isect = pc.Region([isect])

                # label with AP
                isect.props = region.props.copy()

                # store new Region
                new_list.append(isect)

                # keep track of original Region in ppp.regions
                parents.append(j)

                # index of subsystem active within isect
                subsys_list.append(i)

    # compute spatial adjacency matrix
    n = len(new_list)
    adj = sp.lil_matrix((n, n), dtype=np.int8)
    for i, ri in enumerate(new_list):
        pi = parents[i]
        for j, rj in enumerate(new_list[0:i]):
            pj = parents[j]

            if (ppp.adj[pi, pj] == 1) or (pi == pj):
                # account for shrinkage in adjacency check
                if pc.is_adjacent(ri, rj, 2 * eps):
                    adj[i, j] = 1
                    adj[j, i] = 1
        adj[i, i] = 1

    new_ppp = PropPreservingPartition(domain=ppp.domain,
                                      regions=new_list,
                                      adj=adj,
                                      prop_regions=ppp.prop_regions)
    return (new_ppp, subsys_list, parents)
Esempio n. 23
0
def infer_srtesseler_density(cells, volume_weighted=True, rank=0, **kwargs):
    """
    2D particle density estimation inspired by:

        SR-Tesseler: a method to segment and quantify localization-based
        super-resolution microscopy data.
        Levet, F., Hosy, E., Kechkar, A., Butler, C., Beghin, A., Choquet, C.,
        Sibarita, J.B.
        Nature Methods 2015; 12 (11); 1065-1071.

    This (much) simplified implementation borrows from the above reference the
    same general principle:

    * a Voronoi tessellation is made out of all particle locations (one
      location = one Voronoi cell)
    * for each Voronoi cell (or particle location), the cell may be extended to
      merge with its neighbors (see argument `rank`)
    * the local density is estimated classically as the number of points (of
      merged cells) divided by the total surface area of the merged cells

    """
    points = cells.locations
    is_densest_tessellation = isinstance(
        cells.tessellation, Voronoi
    ) and cells.number_of_cells == len(points)
    if is_densest_tessellation:
        tessellation = cells.tessellation
        partition = cells
    else:
        tessellation = Voronoi()
        # TODO: try 3D
        # coords = [ col for col in 'xyz' if col in points.columns ]
        if "z" in points.columns:
            import warnings

            warnings.warn("ignoring coordinate 'z'")
        tessellation.tessellate(points[["x", "y"]])
        partition = Partition(points, tessellation)
    # estimate the density at each point
    polygons_required = not is_densest_tessellation and volume_weighted
    indices, surface_areas, polygons = [], [], []
    for i in range(tessellation.number_of_cells):
        hull = convex_hull(partition=partition, cell_index=i)
        if hull is None:
            continue
        surface_area = hull.volume
        indices.append(i)
        surface_areas.append(surface_area)
        if polygons_required:
            polygons.append(
                p.Polytope(hull.equations[:, [0, 1]], -hull.equations[:, 2])
            )
    indices, surface_areas = np.array(indices), np.array(surface_areas)
    if rank:
        if 1 < rank:
            raise NotImplementedError("rank > 1")
        index_map = np.full(tessellation.number_of_cells, len(indices))
        index_map[indices] = indices
        extended_areas = np.array(surface_areas)  # copy
        ncells = np.ones_like(surface_areas)
        regions = [[p] for p in polygons]
        for i in indices:
            for j in tessellation.neighbours(i):
                j = index_map[j]
                try:
                    extended_areas[i] += surface_areas[j]
                    ncells[i] += 1
                    if polygons_required:
                        regions[i].append(polygons[j])
                except IndexError:
                    pass
        polygons = [p.Region(ps) for ps in regions]
        local_density = ncells / extended_areas
    else:
        local_density = 1.0 / surface_areas
    local_density = pd.Series(index=indices, data=local_density)
    # sum the estimates within each spatial bin
    if is_densest_tessellation:
        density = local_density
    else:
        if isinstance(cells.cell_index, tuple):
            pt_ids, cell_ids = cells.cell_index
        indices, densities = [], []
        for i in range(cells.number_of_cells):
            if isinstance(cells.cell_index, tuple):
                polygons_i = pt_ids[cell_ids == i]
                if polygons_i.size == 0:
                    indices.append(i)
                    densities.append(0.0)
                    continue
                assigned = np.zeros(len(points), dtype=bool)
                assigned[polygons_i] = True
            else:
                assigned = cells.cell_index == i
                if not np.any(assigned):
                    indices.append(i)
                    densities.append(0.0)
                    continue
                (polygons_i,) = np.nonzero(assigned)
            average_density = local_density[polygons_i].mean()
            indices.append(i)
            densities.append(average_density)
        density = pd.Series(index=indices, data=densities)
    return pd.DataFrame(dict(density=density))
Esempio n. 24
0
 def half_space(self):
     regions = []
     for face in self.faces:
         regions.append(face.half_space)
     return pt.Region(regions)
Esempio n. 25
0
def prop2part(state_space, cont_props_dict):
    """Main function that takes a domain (state_space) and a list of
    propositions (cont_props), and returns a proposition preserving
    partition of the state space.

    See Also
    ========
    L{PropPreservingPartition},
    C{polytope.Polytope}

    @param state_space: problem domain
    @type state_space: C{polytope.Polytope}

    @param cont_props_dict: propositions
    @type cont_props_dict: dict of C{polytope.Polytope}

    @return: state space quotient partition induced by propositions
    @rtype: L{PropPreservingPartition}
    """
    first_poly = []  #Initial Region's polytopes
    first_poly.append(state_space)

    regions = [pc.Region(first_poly)]

    for cur_prop in cont_props_dict:
        cur_prop_poly = cont_props_dict[cur_prop]

        num_reg = len(regions)
        prop_holds_reg = []

        for i in xrange(num_reg):  #i region counter
            region_now = regions[i].copy()
            #loop for prop holds
            prop_holds_reg.append(0)

            prop_now = regions[i].props.copy()

            dummy = region_now.intersect(cur_prop_poly)

            # does cur_prop hold in dummy ?
            if pc.is_fulldim(dummy):
                dum_prop = prop_now.copy()
                dum_prop.add(cur_prop)

                # is dummy a Polytope ?
                if len(dummy) == 0:
                    regions[i] = pc.Region([dummy], dum_prop)
                else:
                    # dummy is a Region
                    dummy.props = dum_prop.copy()
                    regions[i] = dummy.copy()
                prop_holds_reg[-1] = 1
            else:
                #does not hold in the whole region
                # (-> no need for the 2nd loop)
                regions.append(region_now)
                continue

            #loop for prop does not hold
            regions.append(pc.Region([], props=prop_now))
            dummy = region_now.diff(cur_prop_poly)

            if pc.is_fulldim(dummy):
                dum_prop = prop_now.copy()

                # is dummy a Polytope ?
                if len(dummy) == 0:
                    regions[-1] = pc.Region([pc.reduce(dummy)], dum_prop)
                else:
                    # dummy is a Region
                    dummy.props = dum_prop.copy()
                    regions[-1] = dummy.copy()
            else:
                regions.pop()

        count = 0
        for hold_count in xrange(len(prop_holds_reg)):
            if prop_holds_reg[hold_count] == 0:
                regions.pop(hold_count - count)
                count += 1

    mypartition = PropPreservingPartition(
        domain=copy.deepcopy(state_space),
        regions=regions,
        prop_regions=copy.deepcopy(cont_props_dict))

    mypartition.adj = pc.find_adjacent_regions(mypartition).copy()

    return mypartition
Esempio n. 26
0
def add_grid(ppp, grid_size=None, num_grid_pnts=None, abs_tol=1e-10):
    """ This function takes a proposition preserving partition ppp and the size
    of the grid or the number of grids, and returns a refined proposition
    preserving partition with grids.

    Input:

      - `ppp`: a L{PropPreservingPartition} object
      - `grid_size`: the size of the grid,
          type: float or list of float
      - `num_grid_pnts`: the number of grids for each dimension,
          type: integer or list of integer

    Output:

      - A L{PropPreservingPartition} object with grids

    Note: There could be numerical instabilities when the continuous
    propositions in ppp do not align well with the grid resulting in very small
    regions. Performace significantly degrades without glpk.
    """
    if (grid_size != None) & (num_grid_pnts != None):
        raise Exception("add_grid: Only one of the grid size or number of \
                        grid points parameters is allowed to be given.")
    if (grid_size == None) & (num_grid_pnts == None):
        raise Exception("add_grid: At least one of the grid size or number of \
                         grid points parameters must be given.")

    dim = len(ppp.domain.A[0])
    domain_bb = ppp.domain.bounding_box
    size_list = list()
    if grid_size != None:
        if isinstance(grid_size, list):
            if len(grid_size) == dim:
                size_list = grid_size
            else:
                raise Exception(
                    "add_grid: grid_size isn't given in a correct format.")
        elif isinstance(grid_size, float):
            for i in xrange(dim):
                size_list.append(grid_size)
        else:
            raise Exception("add_grid: "
                            "grid_size isn't given in a correct format.")
    else:
        if isinstance(num_grid_pnts, list):
            if len(num_grid_pnts) == dim:
                for i in xrange(dim):
                    if isinstance(num_grid_pnts[i], int):
                        grid_size = (float(domain_bb[1][i]) -
                                     float(domain_bb[0][i])) / num_grid_pnts[i]
                        size_list.append(grid_size)
                    else:
                        raise Exception(
                            "add_grid: "
                            "num_grid_pnts isn't given in a correct format.")
            else:
                raise Exception(
                    "add_grid: "
                    "num_grid_pnts isn't given in a correct format.")
        elif isinstance(num_grid_pnts, int):
            for i in xrange(dim):
                grid_size = (float(domain_bb[1][i]) -
                             float(domain_bb[0][i])) / num_grid_pnts
                size_list.append(grid_size)
        else:
            raise Exception("add_grid: "
                            "num_grid_pnts isn't given in a correct format.")

    j = 0
    list_grid = dict()

    while j < dim:
        list_grid[j] = compute_interval(float(domain_bb[0][j]),
                                        float(domain_bb[1][j]), size_list[j],
                                        abs_tol)
        if j > 0:
            if j == 1:
                re_list = list_grid[j - 1]
                re_list = product_interval(re_list, list_grid[j])
            else:
                re_list = product_interval(re_list, list_grid[j])
        j += 1

    new_list = []
    parent = []
    for i in xrange(len(re_list)):
        temp_list = list()
        j = 0
        while j < dim * 2:
            temp_list.append([re_list[i][j], re_list[i][j + 1]])
            j = j + 2
        for j in xrange(len(ppp.regions)):
            tmp = pc.box2poly(temp_list)
            isect = tmp.intersect(ppp.regions[j], abs_tol)

            #if pc.is_fulldim(isect):
            rc, xc = pc.cheby_ball(isect)
            if rc > abs_tol / 2:
                if rc < abs_tol:
                    print("Warning: "
                          "One of the regions in the refined PPP is too small"
                          ", this may cause numerical problems")
                if len(isect) == 0:
                    isect = pc.Region([isect], [])
                isect.props = ppp.regions[j].props.copy()
                new_list.append(isect)
                parent.append(j)

    adj = sp.lil_matrix((len(new_list), len(new_list)), dtype=np.int8)
    for i in xrange(len(new_list)):
        adj[i, i] = 1
        for j in xrange(i + 1, len(new_list)):
            if (ppp.adj[parent[i], parent[j]] == 1) or \
                    (parent[i] == parent[j]):
                if pc.is_adjacent(new_list[i], new_list[j]):
                    adj[i, j] = 1
                    adj[j, i] = 1

    return PropPreservingPartition(domain=ppp.domain,
                                   regions=new_list,
                                   adj=adj,
                                   prop_regions=ppp.prop_regions)
Esempio n. 27
0
def pwa_partition(pwa_sys, ppp, abs_tol=1e-5):
    """This function takes:

      - a piecewise affine system C{pwa_sys} and
      - a proposition-preserving partition C{ppp}
          whose domain is a subset of the domain of C{pwa_sys}

    and returns a *refined* proposition preserving partition
    where in each region a unique subsystem of pwa_sys is active.

    Reference
    =========
    Modified from Petter Nilsson's code
    implementing merge algorithm in:

    Nilsson et al.
    `Temporal Logic Control of Switched Affine Systems with an
    Application in Fuel Balancing`, ACC 2012.

    See Also
    ========
    L{discretize}

    @type pwa_sys: L{hybrid.PwaSysDyn}
    @type ppp: L{PropPreservingPartition}

    @return: new partition and associated maps:

        - new partition C{new_ppp}
        - map of C{new_ppp.regions} to C{pwa_sys.list_subsys}
        - map of C{new_ppp.regions} to C{ppp.regions}

    @rtype: C{(L{PropPreservingPartition}, list, list)}
    """
    if pc.is_fulldim(ppp.domain.diff(pwa_sys.domain)):
        raise Exception('pwa system is not defined everywhere ' +
                        'in state space')

    # for each subsystem's domain, cut it into pieces
    # each piece is the intersection with
    # a unique Region in ppp.regions
    new_list = []
    subsys_list = []
    parents = []
    for i, subsys in enumerate(pwa_sys.list_subsys):
        for j, region in enumerate(ppp.regions):
            isect = region.intersect(subsys.domain)

            if pc.is_fulldim(isect):
                rc, xc = pc.cheby_ball(isect)

                if rc < abs_tol:
                    msg = 'One of the regions in the refined PPP is '
                    msg += 'too small, this may cause numerical problems'
                    warnings.warn(msg)

                # not Region yet, but Polytope ?
                if len(isect) == 0:
                    isect = pc.Region([isect])

                # label with AP
                isect.props = region.props.copy()

                # store new Region
                new_list.append(isect)

                # keep track of original Region in ppp.regions
                parents.append(j)

                # index of subsystem active within isect
                subsys_list.append(i)

    # compute spatial adjacency matrix
    n = len(new_list)
    adj = sp.lil_matrix((n, n), dtype=np.int8)
    for i, ri in enumerate(new_list):
        pi = parents[i]
        for j, rj in enumerate(new_list[0:i]):
            pj = parents[j]

            if (ppp.adj[pi, pj] == 1) or (pi == pj):
                if pc.is_adjacent(ri, rj):
                    adj[i, j] = 1
                    adj[j, i] = 1
        adj[i, i] = 1

    new_ppp = PropPreservingPartition(domain=ppp.domain,
                                      regions=new_list,
                                      adj=adj,
                                      prop_regions=ppp.prop_regions)
    return (new_ppp, subsys_list, parents)
Esempio n. 28
0
 def add_collection(self, unit_regions, label=None):
     # check if already existing
     if label in self.index:
         if 1 < len(self.index):
             raise RuntimeError(
                 'cannot overwrite a collection if other collections have already been defined'
             )
         self.__reset__()
     #
     i0 = len(self.unit_region)
     self.unit_region += list(unit_regions)
     # first group overlapping unit regions in the collection
     current_index = max(self.group.keys()) + 1 if self.group else 0
     not_an_index = -1
     n = len(unit_regions)
     assignment = np.full(n, not_an_index, dtype=int)
     groups = dict()
     for i in range(n):
         region_i = unit_regions[i]
         if isinstance(region_i, pt.Polytope):
             region_i = pt.Region([region_i])
             _min_i = _max_i = None
         elif isinstance(region_i, pt.Region):
             _min_i = _max_i = None
         else:  #if isinstance(region_i, (tuple, list)):
             _min_i, _max_i = region_i
             region_i = None
         group_with = set()
         if assignment[i] == not_an_index:
             group_index = current_index
             group = set([i0 + i])
         else:
             group_index = assignment[i]
             group_with.add(group_index)
             group = groups[group_index]
             assert i0 + i in group
         for j in range(i + 1, n):
             if i0 + j in group:
                 continue
             region_j = unit_regions[j]
             if isinstance(region_j, (pt.Polytope, pt.Region)):
                 if region_i is None:
                     region_i = pt.box2poly(list(zip(_min_i, _max_i)))
                     self._unit_polytope[i0 + i] = region_i
                 i_and_j_are_adjacent = pt.is_adjacent(region_i, region_j)
             else:  #if isinstance(region_j, (tuple, list)):
                 _min_j, _max_j = region_j
                 if _min_i is None:
                     region_j = pt.box2poly(list(zip(_min_j, _max_j)))
                     self._unit_polytope[i0 + j] = region_j
                     i_and_j_are_adjacent = pt.is_adjacent(
                         region_i, region_j)
                 else:
                     i_and_j_are_adjacent = np.all(
                         _min_i <= _max_j) and np.all(_min_j <= _max_i)
             if i_and_j_are_adjacent:
                 if assignment[j] == not_an_index:
                     group.add(i0 + j)
                 else:
                     other_group_index = assignment[j]
                     group_with.add(other_group_index)
                     group |= groups.pop(other_group_index)
         if group_with:
             group_index = min(group_with)
         else:
             current_index += 1
         groups[group_index] = group
         group = np.array(list(group)) - i0  # indices in `assignment`
         assignment[group] = group_index
     #
     # merge the new and existing groups together
     for g in list(groups.keys()):
         adjacent = set()
         for h in self.group:
             g_and_h_are_adjacent = False
             for i in groups[g]:
                 for j in self.group[h]:
                     if self.adjacent(i, j):
                         g_and_h_are_adjacent = True
                         break
                 if g_and_h_are_adjacent:
                     adjacent.add(h)
                     break
         if adjacent:
             h = min(adjacent)
             for i in adjacent - {h}:
                 self.group[h] |= self.group.pop(i)
             self.group[h] |= groups.pop(g)
             assignment[assignment == g] = h
     if groups:
         self.group.update(groups)
     #
     if label is None:
         label = ''
     self.index[label] = assignment
     #
     self.reverse_index = np.c_[
         np.repeat(np.arange(len(self.index)
                             ), [len(self.index[s]) for s in self.index]),
         np.concatenate([np.arange(len(self.index[s]))
                         for s in self.index])]