PNG  IHDRxsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<,tEXtComment File Manager

File Manager

Path: /opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/etc/

Viewing File: RE_Rect.py

""" Support functions for RE simplification.
This module is intended for use by the RE module.
It is in a separate module to keep RE itself cleaner
since the algorithm, 'rectangle selection', is a quite
separate part that depends on some tricky heuristics.

The primary entry function is

chooserects(lines, gauges)

It chooses 'the best' rectangles from lines to base simplification on.
A weight on atoms is given by gauges.

pr() gives some example usages of chooserects.

"""

from guppy.sets import immbitset, mutbitset, immbitrange


class Rect(object):
    __slots__ = 'width', 'lines', 'gainmemo', 'lnos', 'all_lines', 'common_part'

    def __init__(self, width, lines):
        self.width = width
        self.lines = lines
        assert not (width and len(lines) == 1)
        self.gainmemo = {}

    def init2(self, lnobyid, all_lines):
        self.all_lines = all_lines
        self.lnos = immbitset([lnobyid[id(line)] for line in self.lines])
        self.common_part = self.get_common_part()

    def reducelines(self, lnos):
        # Reduce lines of self by removing some lines
        # Argument: lnos, a 'set' of line numbers to remove

        olnos = self.lnos
        lnos = olnos & ~lnos
        if lnos != olnos:
            self.lnos = lnos
            self.lines = [self.all_lines[lno] for lno in lnos]
        if len(lnos) == 1:
            self.width = len(self.lines[0])

    def get_lines(self, pickednos=0):
        lines = []
        for i in self.lnos & ~ pickednos:
            lines.append(self.all_lines[i])
        return lines

    def __repr__(self):
        return '<\n dir = %d\n width = %d\n lnos = %s\n lines = %s\n>' % (
            self.dir, self.width, list(self.lnos), self.lines)


class LeftRect(Rect):
    __slots__ = ()
    dir = 0

    def get_common_part(self):
        return self.lines[0][:self.width]

    def get_uncommons(self, pickednos=0):
        uc = []
        for line in self.get_lines(pickednos):
            uc.append(line[self.width:])
        return uc


class RightRect(Rect, object):
    __slots__ = ()
    dir = -1

    def get_common_part(self):
        lo = -self.width
        if lo == 0:
            return []
        return self.lines[0][lo:]

    def get_uncommons(self, pickednos=0):
        uc = []
        hi = -self.width
        if hi == 0:
            hi = None
        for line in self.get_lines(pickednos):
            uc.append(line[:hi])
        return uc


def sum_gauge(gauge, lst):
    global hits, misses
    if gauge is None:
        return len(lst)
    else:
        gain = 0
        for x in lst:
            gain += gauge(x)
    return gain


def cmp_gauged(xs, ys, gauges):
    for gauge in gauges:
        gx = sum_gauge(gauge, xs)
        gy = sum_gauge(gauge, ys)
        c = cmp(gx, gy)
        if c:
            return c
    return 0


class InducedRect:
    def __init__(self, s, lines, lnos):
        self.s = s
        self.width = s.width
        self.all_lines = s.all_lines
        self.lines = lines
        self.lnos = lnos


class InducedRightRect(InducedRect, RightRect):
    pass


class InducedLeftRect(InducedRect, LeftRect):
    pass


def brect(lines):
    if len(lines) <= 1:
        return [LeftRect(0, lines)]
    newrects = [LeftRect(0, lines), RightRect(0, lines)]
    donerects = []
    while newrects:
        oldrects = newrects
        newrects = []
        for r in oldrects:
            width = r.width
            while 1:
                is_done = 0
                d = {}
                pos = width ^ r.dir
                for line in r.lines:
                    if width < len(line):
                        d.setdefault(line[pos], []).append(line)
                    else:
                        is_done = 1
                if is_done or len(d) != 1:
                    break
                r.width = width = width + 1
            donerects.append(r)
            width += 1
            for k, v in list(d.items()):
                if len(v) > 1:
                    new_r = r.__class__(width, v)
                    newrects.append(new_r)

    return donerects


def choose(rects, lines=[], gauges=[None]):
    def induce(r):
        uncommons = r.get_uncommons()
        if len(uncommons) < 2:
            return
        irs = []
        for s in rects:
            if s.dir != r.dir:
                continue
            pss = []
            uncs = s.get_uncommons(pickednos)
            lnos = s.lnos & ~pickednos
            assert len(uncs) == len(lnos)
            for unc, lno in zip(uncs, lnos):
                if unc in uncommons:
                    pss.append(lno)
            if len(pss) == len(uncommons):
                pslnos = immbitset(pss)
                pss = [lines[lno] for lno in pss]
                if s.dir == -1:
                    c = InducedRightRect
                else:
                    c = InducedLeftRect
                ir = c(s, pss, pslnos)
                irs.append(ir)

        if irs:
            news.extend(irs)

    def overlap(r):
        rlnos = r.lnos
        tonews = []
        for s in rects:
            if s is r:
                continue
            if s.dir != r.dir:
                continue
            slnos = s.lnos
            if not (slnos & rlnos):
                continue
            slnos &= ~ pickednos
            if not slnos:
                # remove
                continue
            scom = s.common_part
            if not scom:
                continue
            for t in rects:
                if t is s:
                    continue
                if t.dir == s.dir:
                    continue
                tlnos = t.lnos & ~pickednos
                if (tlnos & rlnos):
                    continue
                olnos = tlnos & slnos
                if not olnos:
                    continue
                if slnos == tlnos:
                    continue
                tcom = t.common_part
                if not tcom:
                    continue
                c = cmp_gauged(scom, tcom, gauges)
                if c > 0:
                    continue

                break

            else:
                # s is ok
                tonews.append(s)
                rects.remove(s)
        news.extend(tonews)

    def picknext():
        while 1:
            if news:
                r = news[0]
                del news[0]
            else:
                r = None
                for s in list(rects):
                    slnos = s.lnos - pickednos
                    if not slnos:
                        rects.remove(s)
                        continue
                    sn = len(slnos) - 1
                    sw = s.width
                    if r is not None:
                        if not sw:
                            break
                        if not sn:
                            continue
                        if rwn:
                            rmemo = r.gainmemo
                            smemo = s.gainmemo
                            c = 0
                            for gauge in gauges:
                                try:
                                    gr = rmemo[gauge]
                                except KeyError:
                                    gr = sum_gauge(gauge, r.common_part)
                                    rmemo[gauge] = gr
                                gr *= rn
                                try:
                                    gs = smemo[gauge]
                                except KeyError:
                                    gs = sum_gauge(gauge, s.common_part)
                                    smemo[gauge] = gs
                                gs *= sn
                                c = gr - gs
                                if c:
                                    break
                            if c >= 0:
                                continue
                    r = s
                    rlnos = slnos
                    if not sw:
                        break
                    rn = sn
                    rw = sw
                    rwn = sn * sw
                if r is not None:
                    rects.remove(r)
            if r is not None:
                r.reducelines(pickednos)
                if r.lnos:
                    return r

    def cmpinit(x):
        return x.width, x.dir, x.lnos[0]

    if gauges[0] is None:
        gauges = gauges[1:]

    lnobyid = dict([(id(line), i) for i, line in enumerate(lines)])

    orects = rects
    rects = list(orects)

    for r in rects:
        r.init2(lnobyid, lines)

    rects.sort(key=cmpinit, reverse=True)

    allnos = immbitrange(len(lines))

    pickednos = mutbitset()
    pickedrects = []

    news = []
    while pickednos != allnos:
        r = picknext()
        pickednos |= r.lnos
        pickedrects.append(r)
        induce(r)
        overlap(r)

    return pickedrects


def chooserects(lines, gauges=[None]):
    rects = brect(lines)
    choosen = choose(rects, lines, gauges)
    return choosen


def pr():
    x = chooserects(['abc', 'ade'])
    x = chooserects(['abc',
                     'abe',
                     'ace',
                     'xby'])

    print(x)
    x = chooserects(['ab1',
                     'ab2',
                     'ac3',
                     'ac4'])

    print(x)

    # Case where.. (from right).. :
    # the total gain of two rects (bfbf+cfcf = 4) is greater than the gain of another
    # overlapping rect (ffff == 3), although the individual gains are less (= 2).
    # But in this case at least, the end result should likely become the same

    x = chooserects([
        '1bf',
        '2bf',
        '3cf',
        '4cf'])

    print(x)

    # Case where it chooses twice..

    x = chooserects([
        'abc',
        'abd',
        'bcx',
        'bdy'
    ])

    print('TW', x)

    # Case where it didn't choose enough rects

    x = ([
        'abc',
        'abd',
        'e'
    ])

    print(chooserects(x))

    # Case where it should prefer one side or the other
    # i.e. left traditionally

    print(chooserects(['abc', 'axc']))

    # Case where it should give a width 0 rect

    print(chooserects(['a', '']))

    # Case with overlap

    print(chooserects(['abcd', 'abce', 'a', 'f']))

    # Case with induce

    print(chooserects(['abcd', 'abce', 'd', 'e']))

    print(chooserects(['auvw', 'buvw', 'a', 'b']))
    print(chooserects(['axuvw', 'bxuvw', 'axy', 'bxy', 'cy']))


def tmany():
    for i in range(100):
        x = chooserects(['abc',
                         'abe',
                         'ace',
                         'xby'])
b IDATxytVսϓ22 A@IR :hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-EIENT ;@xT.i%-X}SvS5.r/UHz^_$-W"w)Ɗ/@Z &IoX P$K}JzX:;` &, ŋui,e6mX ԵrKb1ԗ)DADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADA݀!I*]R;I2$eZ#ORZSrr6mteffu*((Pu'v{DIߔ4^pIm'77WEEE;vƎ4-$]'RI{\I&G :IHJ DWBB=\WR޽m o$K(V9ABB.}jѢv`^?IOȅ} ڶmG}T#FJ`56$-ھ}FI&v;0(h;Б38CӧOWf!;A i:F_m9s&|q%=#wZprrrla A &P\\СC[A#! {olF} `E2}MK/vV)i{4BffV\|ۭX`b@kɶ@%i$K z5zhmX[IXZ` 'b%$r5M4º/l ԃߖxhʔ)[@=} K6IM}^5k㏷݆z ΗÿO:gdGBmyT/@+Vɶ纽z񕏵l.y޴it뭷zV0[Y^>Wsqs}\/@$(T7f.InݺiR$푔n.~?H))\ZRW'Mo~v Ov6oԃxz! S,&xm/yɞԟ?'uaSѽb,8GלKboi&3t7Y,)JJ c[nzӳdE&KsZLӄ I?@&%ӟ۶mSMMњ0iؐSZ,|J+N ~,0A0!5%Q-YQQa3}$_vVrf9f?S8`zDADADADADADADADADAdqP,تmMmg1V?rSI꒟]u|l RCyEf٢9 jURbztѰ!m5~tGj2DhG*{H9)꒟ר3:(+3\?/;TUݭʴ~S6lڧUJ*i$d(#=Yݺd{,p|3B))q:vN0Y.jkק6;SɶVzHJJЀ-utѹսk>QUU\޲~]fFnK?&ߡ5b=z9)^|u_k-[y%ZNU6 7Mi:]ۦtk[n X(e6Bb."8cۭ|~teuuw|ήI-5"~Uk;ZicEmN/:]M> cQ^uiƞ??Ңpc#TUU3UakNwA`:Y_V-8.KKfRitv޲* 9S6ֿj,ՃNOMߤ]z^fOh|<>@Å5 _/Iu?{SY4hK/2]4%it5q]GGe2%iR| W&f*^]??vq[LgE_3f}Fxu~}qd-ږFxu~I N>\;͗O֊:̗WJ@BhW=y|GgwܷH_NY?)Tdi'?խwhlmQi !SUUsw4kӺe4rfxu-[nHtMFj}H_u~w>)oV}(T'ebʒv3_[+vn@Ȭ\S}ot}w=kHFnxg S 0eޢm~l}uqZfFoZuuEg `zt~? b;t%>WTkķh[2eG8LIWx,^\thrl^Ϊ{=dž<}qV@ ⠨Wy^LF_>0UkDuʫuCs$)Iv:IK;6ֲ4{^6եm+l3>݆uM 9u?>Zc }g~qhKwڭeFMM~pМuqǿz6Tb@8@Y|jx](^]gf}M"tG -w.@vOqh~/HII`S[l.6nØXL9vUcOoB\xoǤ'T&IǍQw_wpv[kmO{w~>#=P1Pɞa-we:iǏlHo׈꒟f9SzH?+shk%Fs:qVhqY`jvO'ρ?PyX3lх]˾uV{ݞ]1,MzYNW~̈́ joYn}ȚF߾׮mS]F z+EDxm/d{F{-W-4wY듏:??_gPf ^3ecg ҵs8R2מz@TANGj)}CNi/R~}c:5{!ZHӋӾ6}T]G]7W6^n 9*,YqOZj:P?Q DFL|?-^.Ɵ7}fFh׶xe2Pscz1&5\cn[=Vn[ĶE鎀uˌd3GII k;lNmشOuuRVfBE]ۣeӶu :X-[(er4~LHi6:Ѻ@ԅrST0trk%$Č0ez" *z"T/X9|8.C5Feg}CQ%͞ˣJvL/?j^h&9xF`њZ(&yF&Iݻfg#W;3^{Wo^4'vV[[K';+mӍִ]AC@W?1^{එyh +^]fm~iԵ]AB@WTk̏t uR?l.OIHiYyԶ]Aˀ7c:q}ힽaf6Z~қm(+sK4{^6}T*UUu]n.:kx{:2 _m=sAߤU@?Z-Vކеz왍Nэ{|5 pڶn b p-@sPg]0G7fy-M{GCF'%{4`=$-Ge\ eU:m+Zt'WjO!OAF@ik&t݆ϥ_ e}=]"Wz_.͜E3leWFih|t-wZۍ-uw=6YN{6|} |*={Ѽn.S.z1zjۻTH]흾 DuDvmvK.`V]yY~sI@t?/ϓ. m&["+P?MzovVЫG3-GRR[(!!\_,^%?v@ҵő m`Y)tem8GMx.))A]Y i`ViW`?^~!S#^+ѽGZj?Vģ0.))A꨷lzL*]OXrY`DBBLOj{-MH'ii-ϰ ok7^ )쭡b]UXSְmռY|5*cֽk0B7镹%ڽP#8nȎq}mJr23_>lE5$iwui+ H~F`IjƵ@q \ @#qG0".0" l`„.0! ,AQHN6qzkKJ#o;`Xv2>,tێJJ7Z/*A .@fفjMzkg @TvZH3Zxu6Ra'%O?/dQ5xYkU]Rֽkق@DaS^RSּ5|BeHNN͘p HvcYcC5:y #`οb;z2.!kr}gUWkyZn=f Pvsn3p~;4p˚=ē~NmI] ¾ 0lH[_L hsh_ғߤc_њec)g7VIZ5yrgk̞W#IjӪv>՞y睝M8[|]\շ8M6%|@PZڨI-m>=k='aiRo-x?>Q.}`Ȏ:Wsmu u > .@,&;+!!˱tﭧDQwRW\vF\~Q7>spYw$%A~;~}6¾ g&if_=j,v+UL1(tWake:@Ș>j$Gq2t7S?vL|]u/ .(0E6Mk6hiۺzښOrifޱxm/Gx> Lal%%~{lBsR4*}{0Z/tNIɚpV^#Lf:u@k#RSu =S^ZyuR/.@n&΃z~B=0eg뺆#,Þ[B/?H uUf7y Wy}Bwegל`Wh(||`l`.;Ws?V@"c:iɍL֯PGv6zctM̠':wuW;d=;EveD}9J@B(0iհ bvP1{\P&G7D޴Iy_$-Qjm~Yrr&]CDv%bh|Yzni_ˆR;kg}nJOIIwyuL}{ЌNj}:+3Y?:WJ/N+Rzd=hb;dj͒suݔ@NKMԄ jqzC5@y°hL m;*5ezᕏ=ep XL n?מ:r`۵tŤZ|1v`V뽧_csج'ߤ%oTuumk%%%h)uy]Nk[n 'b2 l.=͜E%gf$[c;s:V-͞WߤWh-j7]4=F-X]>ZLSi[Y*We;Zan(ӇW|e(HNNP5[= r4tP &0<pc#`vTNV GFqvTi*Tyam$ߏWyE*VJKMTfFw>'$-ؽ.Ho.8c"@DADADADADADADADADA~j*֘,N;Pi3599h=goضLgiJ5փy~}&Zd9p֚ e:|hL``b/d9p? fgg+%%hMgXosج, ΩOl0Zh=xdjLmhݻoO[g_l,8a]٭+ӧ0$I]c]:粹:Teꢢ"5a^Kgh,&= =՟^߶“ߢE ܹS J}I%:8 IDAT~,9/ʃPW'Mo}zNƍ쨓zPbNZ~^z=4mswg;5 Y~SVMRXUյڱRf?s:w ;6H:ºi5-maM&O3;1IKeamZh͛7+##v+c ~u~ca]GnF'ټL~PPPbn voC4R,ӟgg %hq}@#M4IÇ Oy^xMZx ) yOw@HkN˖-Sǎmb]X@n+i͖!++K3gd\$mt$^YfJ\8PRF)77Wא!Cl$i:@@_oG I{$# 8磌ŋ91A (Im7֭>}ߴJq7ޗt^ -[ԩSj*}%]&' -ɓ'ꫯVzzvB#;a 7@GxI{j޼ƌ.LÇWBB7`O"I$/@R @eee@۷>}0,ɒ2$53Xs|cS~rpTYYY} kHc %&k.], @ADADADADADADADADA@lT<%''*Lo^={رc5h %$+CnܸQ3fҥK}vUVVs9G R,_{xˇ3o߾;TTTd}馛]uuuG~iԩ@4bnvmvfϞ /Peeeq}}za I~,誫{UWW뮻}_~YƍSMMMYχ֝waw\ďcxꩧtEƍկ_?۷5@u?1kNׯWzz/wy>}zj3 k(ٺuq_Zvf̘:~ ABQ&r|!%KҥKgԞ={<_X-z !CyFUUz~ ABQIIIjݺW$UXXDٳZ~ ABQƍecW$<(~<RSSvZujjjԧOZQu@4 8m&&&jԩg$ď1h ͟?_{768@g =@`)))5o6m3)ѣƌJ;wҿUTT /KZR{~a=@0o<*狔iFɶ[ˎ;T]]OX@?K.ۈxN pppppppppppppppppPfl߾] ,{ァk۶mڿo5BTӦMӴiӴ|r DB2e|An!Dy'tkΝ[A $***t5' "!駟oaDnΝ:t֭[gDШQ06qD;@ x M6v(PiizmZ4ew"@̴ixf [~-Fٱc&IZ2|n!?$@{[HTɏ#@hȎI# _m(F /6Z3z'\r,r!;w2Z3j=~GY7"I$iI.p_"?pN`y DD?: _  Gÿab7J !Bx@0 Bo cG@`1C[@0G @`0C_u V1 aCX>W ` | `!<S `"<. `#c`?cAC4 ?c p#~@0?:08&_MQ1J h#?/`7;I  q 7a wQ A 1 Hp !#<8/#@1Ul7=S=K.4Z?E_$i@!1!E4?`P_  @Bă10#: "aU,xbFY1 [n|n #'vEH:`xb #vD4Y hi.i&EΖv#O H4IŶ}:Ikh @tZRF#(tXҙzZ ?I3l7q@õ|ۍ1,GpuY Ꮿ@hJv#xxk$ v#9 5 }_$c S#=+"K{F*m7`#%H:NRSp6I?sIՖ{Ap$I$I:QRv2$Z @UJ*$]<FO4IENDB`