Beispiel #1
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
Beispiel #2
0
def infer_srtesseler_density(cells, volume_weighted=True, **kwargs):
    """
    adapted from:

        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.

    """
    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()
        tessellation.tessellate(points[['x','y']])
        partition = Partition(points, tessellation)
    #areas = tessellation.cell_volume # the default implementation for cell_volume
                                      # generates a non-infinite estimation for opened cells
    areas = np.full(tessellation.number_of_cells, np.nan)
    indices, densities, unit_polygons = [], [], []
    for i, surface_area in enumerate(areas):
        unknown_area = np.isnan(surface_area) or np.isinf(surface_area) or surface_area == 0
        polygons_required = not is_densest_tessellation and volume_weighted
        if unknown_area or polygons_required:
            hull = convex_hull(partition=partition, cell_index=i)
        if unknown_area:
            if hull is None:
                continue
            density = 1./ hull.volume # should also divide by the number of frames
        else:
            density = 1./ surface_area
        indices.append(i)
        densities.append(density)
        if polygons_required:
            unit_polygons.append(p.Polytope(hull.equations[:,[0,1]], -hull.equations[:,2]))
    unit_density = pd.Series(index=indices, data=densities)
    if is_densest_tessellation:
        density = unit_density
    else:
        indices, densities = [], []
        for i in range(cells.number_of_cells):
            assigned = cells.cell_index == i
            if not np.any(assigned):
                indices.append(i)
                densities.append(0.)
                continue
            local_polygons, = np.nonzero(assigned)
            assert 0 < local_polygons.size
            if volume_weighted:
                hull = convex_hull(partition=cells, cell_index=i, point_assigned=assigned)
                if hull is None:
                    continue
                polygon = p.Polytope(hull.equations[:,[0,1]], -hull.equations[:,2])
                weighted_sum = 0.
                total_area = 0.
                for j in local_polygons:
                    intersection = p.intersect(unit_polygons[j], polygon)
                    total_area += intersection.volume
                    weighted_sum += intersection.volume * unit_density[j]
                average_density = weighted_sum / total_area
            else:
                average_density = unit_density[local_polygons].mean()
            indices.append(i)
            densities.append(average_density)
        density = pd.Series(index=indices, data=densities)
    return pd.DataFrame(dict(density=density))
    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)
Beispiel #4
0
def merge_partition_pair(
    old_regions, ab2,
    cur_mode, prev_modes,
    old_parents, old_ap_labeling
):
    """Merge an Abstraction with the current partition iterate.

    @param old_regions: A list of C{Region} that is from either:
        1. The ppp of the first (initial) L{AbstractPwa} to be merged.
        2. A list of already-merged regions
    @type old_regions: list of C{Region}

    @param ab2: Abstracted piecewise affine dynamics to be merged into the
    @type ab2: L{AbstractPwa}

    @param cur_mode: mode to be merged
    @type cur_mode: tuple

    @param prev_modes: list of modes that have already been merged together
    @type prev_modes: list of tuple

    @param old_parents: dict of modes that have already been merged to dict of
        indices of new regions to indices of regions
    @type old_parents: dict of modes to list of region indices in list
        C{old_regions} or dict of region indices to regions in original ppp for
        that mode

    @param old_ap_labeling: dict of states of already-merged modes to sets of
        propositions for each state
    @type old_ap_labeling: dict of tuples to sets

    @return: the following:
        - C{new_list}, list of new regions
        - C{parents}, same as input param C{old_parents}, except that it
          includes the mode that was just merged and for list of regions in
          return value C{new_list}
        - C{ap_labeling}, same as input param C{old_ap_labeling}, except that it
          includes the mode that was just merged.
    """
    logger.info('merging partitions')

    part2 = ab2.ppp

    modes = prev_modes + [cur_mode]

    new_list = []
    parents = {mode:dict() for mode in modes}
    ap_labeling = dict()

    for i in range(len(old_regions)):
        for j in range(len(part2)):
            isect = pc.intersect(old_regions[i],
                                 part2[j])
            rc, xc = pc.cheby_ball(isect)

            # no intersection ?
            if rc < 1e-5:
                continue
            logger.info('merging region: A' + str(i) +
                        ', with: B' + str(j))

            # if Polytope, make it Region
            if len(isect) == 0:
                isect = pc.Region([isect])

            # label the Region with propositions
            isect.props = old_regions[i].props.copy()

            new_list.append(isect)
            idx = new_list.index(isect)

            # keep track of parents
            for mode in prev_modes:
                parents[mode][idx] = old_parents[mode][i]
            parents[cur_mode][idx] = j

            # union of AP labels from parent states
            ap_label_1 = old_ap_labeling[i]
            ap_label_2 = ab2.ts.states[j]['ap']

            logger.debug('AP label 1: ' + str(ap_label_1))
            logger.debug('AP label 2: ' + str(ap_label_2))

            # original partitions may be different if pwa_partition used
            # but must originate from same initial partition,
            # i.e., have same continuous propositions, checked above
            #
            # so no two intersecting regions can have different AP labels,
            # checked here
            if ap_label_1 != ap_label_2:
                msg = 'Inconsistent AP labels between intersecting regions\n'
                msg += 'of partitions of switched system.'
                raise Exception(msg)

            ap_labeling[idx] = ap_label_1

    return new_list, parents, ap_labeling
Beispiel #5
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