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())
Exemple #2
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)
 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)
Exemple #4
0
 def intersect(self, Z, m):
     """Check the intersection between 2 (probabilistic) zonotopes
     m is the scaling factor for the confidence set
     """
     # These are deterministic zonotopes
     s1 = self.get_confidence_sets(m)[0]
     s2 = Z.get_confidence_sets(m)[0]
     return not pc.is_empty(s1.to_poly().intersect(s2.to_poly()))
Exemple #5
0
    def __init__(self,
                 list_subsys=[],
                 domain=None,
                 time_semantics=None,
                 timestep=None,
                 overwrite_time=True):
        """
        @type overwrite_time: bool
        @param overwrite_time: If true, then overwrites any time data in the
                               objects in C{list_subsys} with the data in 
                               C{time_semantics} and C{timestep} variables. 
                               Otherwise checks that the time data of the
                               objects in C{list_subsys} are consistent with 
                               C{time_semantics} and C{timestep}.
        """

        if domain is None:
            warn("Domain not given to PwaSysDyn()")

        if ((domain is not None) and (not (isinstance(domain, pc.Polytope)
                                           or isinstance(domain, pc.Region)))):
            raise Exception(
                "PwaSysDyn: `domain` has to be a Polytope or Region")

        if len(list_subsys) > 0:
            uncovered_dom = domain.copy()
            n = list_subsys[0].A.shape[1]  # State space dimension
            m = list_subsys[0].B.shape[1]  # Input space dimension
            p = list_subsys[0].E.shape[1]  # Disturbance space dimension
            for subsys in list_subsys:
                uncovered_dom = uncovered_dom.diff(subsys.domain)
                if (n != subsys.A.shape[1] or m != subsys.B.shape[1]
                        or p != subsys.E.shape[1]):
                    raise Exception("PwaSysDyn: state, input, disturbance " +
                                    "dimensions have to be the same for all " +
                                    "subsystems")
            if not pc.is_empty(uncovered_dom):
                raise Exception("PwaSysDyn: subdomains must cover the domain")
            for x in itertools.combinations(list_subsys, 2):
                if pc.is_fulldim(x[0].domain.intersect(x[1].domain)):
                    raise Exception(
                        "PwaSysDyn: subdomains have to be mutually" +
                        " exclusive")

        self.list_subsys = list_subsys
        self.domain = domain

        # Input time semantics
        _check_time_data(time_semantics, timestep)
        if overwrite_time:
            _push_time_data(self.list_subsys, time_semantics, timestep)
        else:
            _check_time_consistency(list_subsys, time_semantics, timestep)
        self.timestep = timestep
        self.time_semantics = time_semantics
Exemple #6
0
    def __init__(self, list_subsys=[], domain=None, time_semantics=None,
                 timestep=None, overwrite_time=True):
        """
        @type overwrite_time: bool
        @param overwrite_time: If true, then overwrites any time data in the
                               objects in C{list_subsys} with the data in
                               C{time_semantics} and C{timestep} variables.
                               Otherwise checks that the time data of the
                               objects in C{list_subsys} are consistent with
                               C{time_semantics} and C{timestep}.
        """

        if domain is None:
            warn("Domain not given to PwaSysDyn()")

        if ((domain is not None) and
            (not (isinstance(domain, pc.Polytope) or
                isinstance(domain, pc.Region))
            )
        ):
            raise Exception("PwaSysDyn: `domain` has to be a Polytope or Region")

        if len(list_subsys) > 0:
            uncovered_dom = domain.copy()
            n = list_subsys[0].A.shape[1]  # State space dimension
            m = list_subsys[0].B.shape[1]  # Input space dimension
            p = list_subsys[0].E.shape[1]  # Disturbance space dimension
            for subsys in list_subsys:
                uncovered_dom = uncovered_dom.diff(subsys.domain)
                if (n!=subsys.A.shape[1] or m!=subsys.B.shape[1] or
                    p!=subsys.E.shape[1]):
                    raise Exception("PwaSysDyn: state, input, disturbance " +
                                    "dimensions have to be the same for all " +
                                     "subsystems")
            if not pc.is_empty(uncovered_dom):
                raise Exception("PwaSysDyn: subdomains must cover the domain")
            for x in itertools.combinations(list_subsys, 2):
                if pc.is_fulldim(x[0].domain.intersect(x[1].domain) ):
                    raise Exception("PwaSysDyn: subdomains have to be mutually"+
                        " exclusive")

        self.list_subsys = list_subsys
        self.domain = domain

        # Input time semantics
        _check_time_data(time_semantics, timestep)
        if overwrite_time:
            _push_time_data(self.list_subsys, time_semantics, timestep)
        else:
            _check_time_consistency(list_subsys, time_semantics, timestep)
        self.timestep = timestep
        self.time_semantics = time_semantics
Exemple #7
0
def find_equilibria(ssd, eps=0):
    """ Finds the polytope that contains the equilibrium points

    @param ssd: The dynamics of the switched system
    @type ssd: L{SwitchedSysDyn}

    @param eps: The value by which the width of all polytopes
    containing equilibrium points is increased.
    @type eps: float

    @return param cont_props: The polytope representations of the atomic 
    propositions of the state space to be used in partitiong 
    @type cont_props: dict of polytope.Polytope

    Warning: Currently, there is no condition for points where 
    the polytope is critically stable. 

    Warning: if there is a region outside the domain, then it is
    unstable. It seems to ignore the regions outside the domain.
    """

    def normalize(A, B):
        """ Normalizes set of equations of the form Ax<=B
        """
        if A.size > 0:
            Anorm = np.sqrt(np.sum(A * A, 1)).flatten()
            pos = np.nonzero(Anorm > 1e-10)[0]
            A = A[pos, :]
            B = B[pos]
            Anorm = Anorm[pos]
            mult = 1 / Anorm
            for i in xrange(A.shape[0]):
                A[i, :] = A[i, :] * mult[i]
            B = B.flatten() * mult
        return A, B

    cont_ss = ssd.cts_ss
    min_outx = cont_ss.b[0]
    min_outy = cont_ss.b[1]
    max_outx = min_outx + 1
    max_outy = min_outy + 1
    abs_tol = 1e-7

    cont_props = dict()

    for mode in ssd.modes:
        cont_dyn = ssd.dynamics[mode].list_subsys[0]
        A = cont_dyn.A
        K = cont_dyn.K.T[0]
        I = np.eye(len(A), dtype=float)
        rank_IA = np.linalg.matrix_rank(I - A)
        concat = np.hstack((I - A, K.reshape(len(A), 1)))
        rank_concat = np.linalg.matrix_rank(concat)
        soln = pc.Polytope()
        props_sym = "eqpnt_" + str(mode[1])

        if rank_IA == rank_concat:
            if rank_IA == len(A):
                equil = np.dot(np.linalg.inv(I - A), K)
                if (
                    equil[0] >= (-cont_ss.b[2])
                    and equil[0] <= cont_ss.b[0]
                    and equil[1] >= (-cont_ss.b[3])
                    and equil[1] <= cont_ss.b[1]
                ):
                    delta = eps + equil / 100
                    soln = pc.box2poly(
                        [[equil[0] - delta[0], equil[0] + delta[0]], [equil[1] - delta[1], equil[1] + delta[1]]]
                    )
                else:
                    soln = pc.box2poly([[min_outx, max_outx], [min_outy, max_outy]])

            elif rank_IA < len(A):
                if eps == 0:
                    eps = abs(min(np.amin(-K), np.amin(A - I)))
                IAn, Kn = normalize(I - A, K)
                soln = pc.Polytope(np.vstack((IAn, -IAn)), np.hstack((Kn + eps, -Kn + eps)))
                relevantsoln = pc.intersect(soln, cont_ss, abs_tol)
                if pc.is_empty(relevantsoln) & ~pc.is_empty(soln):
                    soln = pc.box2poly([[min_outx, max_outx], [min_outy, max_outy]])
                else:
                    soln = relevantsoln

        else:
            # Assuming trajectories go to infinity as there are no
            # equilibrium points
            soln = pc.box2poly([[min_outx, max_outx], [min_outy, max_outy]])
            print str(mode) + " trajectories go to infinity! No solution"

        cont_props[props_sym] = soln

    return cont_props
 def is_empty(self, polytope):
     return (pc.is_empty(polytope) or (polytope.volume == 0.0))
    def compute_calP_in_probs(self, c, d, calP, t, cp1, cp2, actions_taken):
        A_upper = np.array([
            [-1.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [0.0, -1.0, 0.0],
            [0.0, 1.0, 0.0],
            [0.0, 0.0, -1.0],
            [0.0, 0.0, 1.0],  #surrounding box
            [-cp1[0], -cp1[1], -cp1[2]]
        ])

        b_upper = np.array(
            [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -c * self.agents_lst[t].delta])
        p_upper = pc.Polytope(A_upper, b_upper)  #large upper polytope

        A_lower = np.array([
            [-1.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [0.0, -1.0, 0.0],
            [0.0, 1.0, 0.0],
            [0.0, 0.0, -1.0],
            [0.0, 0.0, 1.0],  #surrounding box
            [cp2[0], cp2[1], cp2[2]]
        ])

        b_lower = np.array(
            [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -c * self.agents_lst[t].delta])
        p_lower = pc.Polytope(A_lower, b_lower)  #large lower polytope

        calP_u = []
        calP_l = []
        calP_m = []

        print("actual number of polytopes:")
        print(len(calP))

        for pol in calP:
            p = pol.pol_repr
            if p.volume > 0.01:
                # intersections of the polytope with upper and lower of curr round
                intersect_up = pc.intersect(p, p_upper)
                intersect_lo = pc.intersect(p, p_lower)

                # check whether the intersection is empty-ish (very small vol)
                emptyish_up = self.is_empty(intersect_up) or self.has_tiny_vol(
                    intersect_up)
                emptyish_lo = self.is_empty(intersect_lo) or self.has_tiny_vol(
                    intersect_lo)

                if (emptyish_up and emptyish_lo):
                    calP_m.append(pol)
                elif (emptyish_up):
                    diff_lo = p.diff(
                        p_lower
                    )  # what is left in the diff should go in the middle space unless emptyish
                    if (self.is_empty(diff_lo) or self.has_tiny_vol(diff_lo)
                        ):  # intersection is exactly the polytope
                        # if emptyish, no need to create new polytope
                        pol.updated[t] = 1
                        calP_l.append(pol)
                    else:
                        # otherwise we need to create new polytope
                        upd_lst = pol.updated  #store the history of updates for curr pol
                        upd_lst[
                            t] = 0  # by default assume that you won't update it
                        ratio = 1.0 * diff_lo.volume / p.volume  # how big is the prob that you keep for new pol
                        g_pol1 = Grind_Polytope(diff_lo, ratio * pol.pi,
                                                ratio * pol.weight, d, self.T,
                                                pol.est_loss, pol.loss,
                                                upd_lst)
                        calP_m.append(g_pol1)

                        upd_lst2 = pol.updated
                        upd_lst2[
                            t] = 1  # this part of the pol will be part of the calP_lower
                        g_pol2 = Grind_Polytope(intersect_lo,
                                                (1.0 - ratio) * pol.pi,
                                                (1.0 - ratio) * pol.weight, d,
                                                self.T, pol.est_loss, pol.loss,
                                                upd_lst2)
                        calP_l.append(g_pol2)
                elif (emptyish_lo):
                    diff_up = p.diff(p_upper)
                    if (self.is_empty(diff_up) or self.has_tiny_vol(diff_up)):
                        pol.updated[t] = 1
                        calP_u.append(pol)
                    else:
                        upd_lst = pol.updated
                        upd_lst[t] = 0
                        ratio = 1.0 * diff_up.volume / p.volume
                        g_pol1 = Grind_Polytope(diff_up, ratio * pol.pi,
                                                ratio * pol.weight, d, self.T,
                                                pol.est_loss, pol.loss,
                                                upd_lst)
                        calP_m.append(g_pol1)

                        upd_lst2 = pol.updated
                        upd_lst2[t] = 1
                        g_pol2 = Grind_Polytope(intersect_up,
                                                (1.0 - ratio) * pol.pi,
                                                (1.0 - ratio) * pol.weight, d,
                                                self.T, pol.est_loss, pol.loss,
                                                upd_lst2)
                        calP_u.append(g_pol2)
                else:
                    diff_up = p.diff(p_upper)
                    diff_lo = p.diff(p_lower)
                    ratio1 = 1.0 * intersect_up.volume / p.volume
                    upd_lst = pol.updated
                    upd_lst[t] = 1
                    g_pol1 = Grind_Polytope(intersect_up, ratio1 * pol.pi,
                                            ratio1 * pol.weight, d, self.T,
                                            pol.est_loss, pol.loss, upd_lst)
                    calP_u.append(g_pol1)

                    ratio2 = 1.0 * intersect_lo.volume / p.volume
                    g_pol2 = Grind_Polytope(intersect_lo, ratio2 * pol.pi,
                                            ratio2 * pol.weight, d, self.T,
                                            pol.est_loss, pol.loss, upd_lst)
                    calP_l.append(g_pol2)

                    #if ratio1 > 0 or ratio2 > 0:
                    diff_uplo = pc.intersect(diff_up, diff_lo)
                    if (not self.is_empty(diff_uplo)
                            and not self.has_tiny_vol(diff_uplo)):
                        upd_lst[t] = 0
                        g_pol3 = Grind_Polytope(
                            diff_uplo, (1.0 - ratio1 - ratio2) * pol.pi,
                            (1.0 - ratio1 - ratio2) * pol.weight, d, self.T,
                            pol.est_loss, pol.loss, upd_lst)
                        calP_m.append(g_pol3)
            elif (p.volume == 0):
                # discard point-polytopes
                print("Timestep t=%d polytope w zero vol" % t)
                print(p)
                print("Was it really empty?")
                print pc.is_empty(p)
            else:
                intersect_up = pc.intersect(p, p_upper)
                intersect_lo = pc.intersect(p, p_lower)
                if (self.is_empty(intersect_up)
                        and self.is_empty(intersect_lo)):
                    pol.updated[t] = 0
                    calP_m.append(pol)
                elif (self.is_empty(intersect_lo)
                      or intersect_lo.volume < intersect_up.volume):
                    # should go with upper polytopes set
                    pol.updated[t] = 1
                    calP_u.append(pol)
                elif (self.is_empty(intersect_up)
                      or intersect_up.volume < intersect_lo.volume):
                    # should go with lower polytopes set
                    pol.updated[t] = 1
                    calP_l.append(pol)

        for pol in calP_u:
            if pol.pi <= 0.000001:
                pol.pi = 0.000001
        for pol in calP_m:
            if pol.pi <= 0.000001:
                pol.pi = 0.000001
        for pol in calP_l:
            if pol.pi <= 0.000001:
                pol.pi = 0.000001

        actions_set = []
        upd = []
        pi_lst = []
        tot_up = 0.0
        tot_lo = 0.0
        incl = [
        ]  # indicator function whether the current action belongs in an upper or lower polytope set
        for pol in calP_u:
            actions_set.append(pol.action)
            upd.append(pol.updated)  #size |\calA| x T
            pi_lst.append(pol.pi)
            incl.append(1)
            tot_up += pol.pi

        for pol in calP_m:
            actions_set.append(pol.action)
            upd.append(pol.updated)
            incl.append(0)
            pi_lst.append(pol.pi)

        for pol in calP_l:
            actions_set.append(pol.action)
            upd.append(pol.updated)
            pi_lst.append(pol.pi)
            incl.append(1)
            tot_lo += pol.pi

        # a lower bound in the in probabilities of the actions that are to be updated is
        # the tot prob of the upper and the lower polytopes sets
        in_probs_est = self.compute_in_probs_regr(pi_lst, t, upd,
                                                  actions_taken, actions_set,
                                                  tot_up + tot_lo, incl)

        spammer = 1 if self.agents_lst[t].type == 0 else 0
        j = 0
        for pol in calP_u:
            pol.est_loss += (1.0 * spammer) / in_probs_est[j]
            j += 1

        for pol in calP_m:
            j += 1

        for pol in calP_l:
            pol.est_loss += (1.0 - spammer) / in_probs_est[j]
            j += 1

        return (calP_u, calP_m, calP_l)
Exemple #10
0
def find_equilibria(ssd, eps=0):
    """ Finds the polytope that contains the equilibrium points

    @param ssd: The dynamics of the switched system
    @type ssd: L{SwitchedSysDyn}

    @param eps: The value by which the width of all polytopes
    containing equilibrium points is increased.
    @type eps: float

    @return param cont_props: The polytope representations of the atomic 
    propositions of the state space to be used in partitiong 
    @type cont_props: dict of polytope.Polytope

    Warning: Currently, there is no condition for points where 
    the polytope is critically stable. 

    Warning: if there is a region outside the domain, then it is
    unstable. It seems to ignore the regions outside the domain.
    """
    def normalize(A, B):
        """ Normalizes set of equations of the form Ax<=B
        """
        if A.size > 0:
            Anorm = np.sqrt(np.sum(A * A, 1)).flatten()
            pos = np.nonzero(Anorm > 1e-10)[0]
            A = A[pos, :]
            B = B[pos]
            Anorm = Anorm[pos]
            mult = 1 / Anorm
            for i in xrange(A.shape[0]):
                A[i, :] = A[i, :] * mult[i]
            B = B.flatten() * mult
        return A, B

    cont_ss = ssd.cts_ss
    min_outx = cont_ss.b[0]
    min_outy = cont_ss.b[1]
    max_outx = min_outx + 1
    max_outy = min_outy + 1
    abs_tol = 1e-7

    cont_props = dict()

    for mode in ssd.modes:
        cont_dyn = ssd.dynamics[mode].list_subsys[0]
        A = cont_dyn.A
        K = cont_dyn.K.T[0]
        I = np.eye(len(A), dtype=float)
        rank_IA = np.linalg.matrix_rank(I - A)
        concat = np.hstack((I - A, K.reshape(len(A), 1)))
        rank_concat = np.linalg.matrix_rank(concat)
        soln = pc.Polytope()
        props_sym = 'eqpnt_' + str(mode[1])

        if (rank_IA == rank_concat):
            if (rank_IA == len(A)):
                equil = np.dot(np.linalg.inv(I - A), K)
                if (equil[0] >= (-cont_ss.b[2]) and equil[0] <= cont_ss.b[0]
                        and equil[1] >= (-cont_ss.b[3])
                        and equil[1] <= cont_ss.b[1]):
                    delta = eps + equil / 100
                    soln = pc.box2poly(
                        [[equil[0] - delta[0], equil[0] + delta[0]],
                         [equil[1] - delta[1], equil[1] + delta[1]]])
                else:
                    soln = pc.box2poly([[min_outx, max_outx],
                                        [min_outy, max_outy]])

            elif (rank_IA < len(A)):
                if eps == 0:
                    eps = abs(min(np.amin(-K), np.amin(A - I)))
                IAn, Kn = normalize(I - A, K)
                soln = pc.Polytope(np.vstack((IAn, -IAn)),
                                   np.hstack((Kn + eps, -Kn + eps)))
                relevantsoln = pc.intersect(soln, cont_ss, abs_tol)
                if (pc.is_empty(relevantsoln) & ~pc.is_empty(soln)):
                    soln = pc.box2poly([[min_outx, max_outx],
                                        [min_outy, max_outy]])
                else:
                    soln = relevantsoln

        else:
            #Assuming trajectories go to infinity as there are no
            #equilibrium points
            soln = pc.box2poly([[min_outx, max_outx], [min_outy, max_outy]])
            print str(mode) + " trajectories go to infinity! No solution"

        cont_props[props_sym] = soln

    return cont_props