Пример #1
0
class ShortestPaths:
    def __init__(self, sg, Dst):
        self.sg = sg
        self.Dst = Dst
        self.mod = mod = sg.mod
        self._hiding_tag_ = mod._hiding_tag_
        self.srcname = sg.srcname
        self.top = self

        self.IG = IG = mod.nodegraph()
        Edges = []
        Y = Dst.nodes
        while Y:
            R = sg.G.domain_restricted(Y)
            R.invert()
            IG.update(R)
            Edges.append(R)
            Y = R.get_domain()
        if Edges:
            Edges.pop()
            Edges.reverse()
            self.Src = mod.idset(Edges[0].get_domain())
        else:
            self.Src = mod.iso()

        self.edges = tuple(Edges)
        sets = []
        for i, e in enumerate(Edges):
            if i == 0:
                sets.append(mod.idset(e.get_domain()))
            sets.append(mod.idset(e.get_range()))
        self.sets = tuple(sets)

        mod.OutputHandling.setup_printing(self)

        self.maxpaths = 10

    def __getitem__(self, idx):
        try:
            return next(self.iter(start=idx))
        except StopIteration:
            raise IndexError

    def __iter__(self):
        return self.iter()

    def iter(self, start=0, stop=None):
        return PathsIter(self, start, stop)

    def aslist(self):
        return list(self)

    def copy_but_avoid_edges_at_levels(self, *args):
        avoid = self.edges_at(*args).updated(self.sg.AvoidEdges)
        assert avoid._hiding_tag_ is self.mod._hiding_tag_
        return self.mod.shpaths(self.Dst, self.Src, avoid_edges=avoid)
        # return self.mod.shpaths(self.dst, self.src, avoid_edges=avoid)

    avoided = copy_but_avoid_edges_at_levels

    # The builtin __len__ doesn't always work due to builtin Python restriction to int result:
    # so we don't provide it at all to avoid unsuspected errors sometimes.
    # Use .numpaths attribute instead.
    #   def __len__(self):
    #      return self.numpaths

    def depth(self):
        pass

    def edges_at(self, *args):
        E = self.mod.nodegraph()
        for col in args:
            E.update(self.edges[col])
        assert E._hiding_tag_ == self.mod._parent.View._hiding_tag_
        return E

    def numpaths_from(self, Src):
        try:
            NP = self.NP
        except AttributeError:
            NP = self.mod.nodegraph(is_mapping=True)
            NP.add_edges_n1(self.IG.get_domain(), None)
            for dst in self.Dst.nodes:
                NP.add_edge(dst, 1)
            self.NP = NP
        numedges = self.mod.hv.numedges
        IG = self.IG

        def np(y):
            n = NP[y]
            if n is None:
                n = 0
                for z in IG[y]:
                    sn = NP[z]
                    if sn is None:
                        sn = np(z)
                    n += sn * numedges(y, z)
                NP[y] = n
            return n

        num = 0
        for src in Src.nodes:
            num += np(src)
        return num

    def _get_numpaths(self):
        num = self.numpaths_from(self.Src)
        self.numpaths = num
        return num

    numpaths = property_nondata(fget=_get_numpaths)

    @property
    def maxpaths(self):
        return self.printer.max_more_lines

    @maxpaths.setter
    def maxpaths(self, value):
        self.printer.max_more_lines = value

    def _oh_get_num_lines(self):
        return self.numpaths

    def _oh_get_line_iter(self):
        for el in self:
            yield from el._get_line_iter()

    def _oh_get_more_msg(self, start_lineno, end_lineno):
        nummore = self.numpaths - (end_lineno + 1)
        return '<... %d more paths ...>' % nummore

    def _oh_get_empty_msg(self):
        if self.numpaths:
            return '<No more paths>'
        return None
Пример #2
0
class Classifier:
    def __init__(self, mod, name, cli=None, supers=(), depends=(), with_referrers=False):
        self.mod = mod
        self.name = name
        if cli is not None:
            self.cli = cli
        # Set of all super-classifiers (including self).
        # The partial order is defined in Notes Aug 30 2005.
        self.super_classifiers = mod.ImpSet.immnodeset([self])
        if supers:
            for s in supers:
                self.super_classifiers |= s.super_classifiers
        else:
            # The Unity classifier is super of all, but we must add it only
            # if not supers specified; init of ByUnity itself depends on this.
            self.super_classifiers |= [mod.Use.Unity.classifier]

        # The classifiers that self depends on.https://wx2.qq.com/?&lang=en
        for d in depends:
            if d.with_referrers:
                with_referrers = True
                break

        # True if we need to setup referrers before calling (the) low-level classifier.
        self.with_referrers = with_referrers

        if with_referrers:
            self.call_with_referrers = mod.View.call_with_referrers

    def call_with_referrers(self, x, f):
        # Default is to not use referrers.
        return f(x)

    # This is not redefined by subclass unless they set cli property.
    def _get_cli(self):
        # This may be defined by subclass w/o setting cli property.
        return self.get_cli()

    cli = property_nondata(_get_cli)

    def get_alt(self, kind, alt):
        # Get alternative kind for a kind with self as fam.classifier.
        return self.mod.alt(kind, alt)

    def get_dictof(self, kind):
        name = '%s.dictof' % self.name
        er = self.mod.mker_memoized(
            name,
            lambda:
            self.mod._er_by_(ByDictOwner, self.mod, name, self))

        return er.classifier.dictof(kind)

    def get_kind(self, k):
        # Make an equivalence class from low-level classification
        return self.family(k)

    def get_kindarg(self, kind):
        # Inverse of get_kind
        cla, ka, cmp = kind.get_ckc()
        if cla is not self:
            raise ValueError(
                'get_kindarg: argument with classifier %r expected' % self)
        return ka

    def get_reprname(self):
        return '%s%s' % (self.mod.Use.reprefix, self.name)

    def get_sokind(self, er, *args, **kwds):
        k = er(*args, **kwds)
        return CallableSoKind(er, (k,))

    def get_sokindrepr(self, sokind):
        # Get the representation of a set of kinds
        # from this classifier / eqv. relation.
        return '%s.sokind%s' % (self.get_reprname(),
                                ''.join(['(%s)' % self.get_userkindargrepr(k)
                                         for k in sokind.kinds]))

    def get_tabheader(self, ctx=''):
        # If ctx = 'and', get the table header when used as a part of the 'and' classifier.
        #     It is sometimes a more compact or parenthesised version of the usual tab header.
        return self.get_byname()

    def get_tabrendering(self, cla, ctx=''):
        # If ctx = 'and', get the table rendering when used as a part of the 'and' classifier
        #     sometimes we want to enclose something in parenthesises.
        return cla.brief

    def get_userkind(self, *args, **kwds):
        # Make a kind from user-level arguments
        return self.family(*args, **kwds)

    def get_userkindarg(self, kind):
        return kind.arg

    def get_userkindargrepr(self, kind):
        return repr(self.get_userkindarg(kind))

    def partition(self, iterable):
        items = []
        for k, v in self.partition_cli(iterable):
            k = self.get_kind(k)
            v = self.mod.Use.idset(v, er=self.er)
            items.append((k, v))
        return items

    def partition_cli(self, a):
        ep = self.call_with_referrers(
            a,
            self.cli.epartition)
        return [(k, ep[k]) for k in ep.get_domain()]

    def relimg(self, X):
        p = self.partition_cli(X)
        kinds = [self.get_kind(k) for k, v in p]  # could be more efficient
        return self.mod.Use.union(kinds, maximized=1)

    def select_cli(self, a, b, cmp='=='):
        return self.call_with_referrers(
            a,
            lambda a: self.cli.select(a, b, cmp))

    def select_ids(self, X, k, alt=None):
        r = self.mod.Use.idset(self.select_cli(X.nodes, k, alt))
        return r
Пример #3
0
class ShortestPaths:
    firstpath = 0
    maxpaths = 10

    def __init__(self, sg, Dst):
        self.sg = sg
        self.Dst = Dst
        self.mod = mod = sg.mod
        self._hiding_tag_ = mod._hiding_tag_
        self.srcname = sg.srcname
        self.output = mod.output
        self.moreiterator = None
        self.top = self

        self.IG = IG = mod.nodegraph()
        Edges = []
        Y = Dst.nodes
        while Y:
            R = sg.G.domain_restricted(Y)
            R.invert()
            IG.update(R)
            Edges.append(R)
            Y = R.get_domain()
        if Edges:
            Edges.pop()
            Edges.reverse()
            self.Src = mod.idset(Edges[0].get_domain())
        else:
            self.Src = mod.iso()

        self.edges = tuple(Edges)
        sets = []
        for i, e in enumerate(Edges):
            if i == 0:
                sets.append(mod.idset(e.get_domain()))
            sets.append(mod.idset(e.get_range()))
        self.sets = tuple(sets)

        self.more = MorePrinter(self)

    def __getitem__(self, idx):
        try:
            return next(self.iter(start=idx))
        except StopIteration:
            raise IndexError

    def __iter__(self):
        return self.iter()

    def __repr__(self):
        f = self.mod._root.io.StringIO()
        self.pp(output=f)
        return f.getvalue().rstrip()

    def __str__(self):
        return self.__repr__()

    def iter(self, start=0, stop=None):
        return PathsIter(self, start, stop)

    def aslist(self, maxpaths=None, firstpath=None):
        if maxpaths is None:
            maxpaths = self.maxpaths
        if firstpath is None:
            firstpath = self.firstpath
        li = list(self.iter(firstpath, firstpath + maxpaths))
        if len(li) >= maxpaths:
            more = (self.numpaths - (firstpath + len(li)))
            if more:
                li.append('<... %d more paths ...>' % more)
        return li

    def copy_but_avoid_edges_at_levels(self, *args):
        avoid = self.edges_at(*args).updated(self.sg.AvoidEdges)
        assert avoid._hiding_tag_ is self.mod._hiding_tag_
        return self.mod.shpaths(self.Dst, self.Src, avoid_edges=avoid)
        # return self.mod.shpaths(self.dst, self.src, avoid_edges=avoid)

    avoided = copy_but_avoid_edges_at_levels

    # The builtin __len__ doesn't always work due to builtin Python restriction to int result:
    # so we don't provide it at all to avoid unsuspected errors sometimes.
    # Use .numpaths attribute instead.
    #   def __len__(self):
    #      return self.numpaths

    def depth(self):
        pass

    def edges_at(self, *args):
        E = self.mod.nodegraph()
        for col in args:
            E.update(self.edges[col])
        assert E._hiding_tag_ == self.mod._parent.View._hiding_tag_
        return E

    def numpaths_from(self, Src):
        try:
            NP = self.NP
        except AttributeError:
            NP = self.mod.nodegraph(is_mapping=True)
            NP.add_edges_n1(self.IG.get_domain(), None)
            for dst in self.Dst.nodes:
                NP.add_edge(dst, 1)
            self.NP = NP
        numedges = self.mod.hv.numedges
        IG = self.IG

        def np(y):
            n = NP[y]
            if n is None:
                n = 0
                for z in IG[y]:
                    sn = NP[z]
                    if sn is None:
                        sn = np(z)
                    n += sn * numedges(y, z)
                NP[y] = n
            return n

        num = 0
        for src in Src.nodes:
            num += np(src)
        return num

    def _get_numpaths(self):
        num = self.numpaths_from(self.Src)
        self.numpaths = num
        return num

    numpaths = property_nondata(fget=_get_numpaths)

    def pp(self, start=None, output=None):
        self.moreiterator = None
        self.more(start, output=output)

    def printiter(self, it, output=None):
        if output is None:
            output = self.output
        self.moreiterator = it
        i = 0
        lastindex = None
        while i < self.maxpaths:
            try:
                el = next(it)
            except StopIteration:
                it.reset(0)
                break
            el.pp(output=output)
            i += 1
            lastindex = el.index
        else:
            if lastindex is not None:
                nummore = self.numpaths - (lastindex + 1)
                if nummore == 1:
                    it.next().pp(output=output)
                elif nummore > 1:
                    print('<... %d more paths ...>' % nummore, file=output)