PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/proc/self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/etc/
Upload File :
Current File : //proc/self/root/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/etc/KanExtension.py
class LeftKanExtension:

    # Implementation of algorithms described by Brown and Heyworth (ref.251)
    # and Heyworth (ref.253).

    def __init__(self, mod, A, B, R, X, F):
        # External subsystem dependencies
        #    mod.KnuthBendix
        #    mod.FiniteAutomaton
        #    mod.SolveFSA
        #    mod.Cat
        #       mod.Cat.Function
        #       mod.Cat.Functor
        #       mod.Cat.check_graph
        #       mod.Cat.check_rules

        self.mod = mod
        self.Cat = mod.Cat

        #

        self.Cat.check_graph(A)
        self.Cat.check_graph(B)
        self.Cat.check_rules(R, B)

        #

        self.A = A
        self.B = B
        self.R = [(tuple(g), tuple(h)) for (g, h) in R]
        self.X = X
        self.F = F

        self.general_procedure()

    def general_procedure(self):
        self.initialize_tables()
        self.make_confluent_system()
        self.make_automaton()  # self.make_catalogue()
        self.make_natural_transformation()

    def initialize_tables(self):
        self.obj_to_str_table = {}
        self.str_to_obj_table = {}
        self.make_initial_rules()

    def make_initial_rules(self):

        # Algorithm 6.1 in (251)

        Re = []

        def add_rule(a, b):
            aw = self.make_word(a)
            bw = self.make_word(b)
            if aw != bw:
                Re.append((aw, bw))

        for a in self.A.arrows:
            srca = self.A.source(a)
            tgta = self.A.target(a)
            XA = self.X.fo(srca)
            Xa = self.X.fa(a)
            Fa = tuple(self.F.fa(a))
            Fsrca = self.F.fo(srca)
            Ftgta = self.F.fo(tgta)
            if Fa:
                t = Fsrca
                for b in Fa:
                    srcb = self.B.source(b)
                    if srcb != t:
                        raise ValueError(
                            'Arrow [%s] with source %s does not compose with target %s' % (b, srcb, t))
                    t = self.B.target(b)
                if t != Ftgta:
                    raise ValueError(
                        'Arrow %s with target %s does not compose with %s' % (Fa, t, Ftgta))
            else:
                if Fsrca != Ftgta:
                    raise ValueError(
                        'Source %s does not match target %s' % (Fsrca, Ftgta))
            for x in XA:
                add_rule(((srca, x),) + Fa, ((tgta, Xa(x)),))

        Rk = [(self.make_word(x), self.make_word(y)) for (x, y) in self.R]

        self.Re = Re
        self.Rk = Rk
        self.Rinit = Re + Rk

    def make_confluent_system(self):
        self.rs = self.mod.KnuthBendix(self.Rinit, delim='.')
        self.Rconf = self.rs.reductions

    def make_automaton(self):
        # Make nondeterministic finite automaton

        def target(e):
            if len(e) == 1 and isinstance(e[0], tuple):
                return self.F.fo(e[0][0])
            else:
                return self.B.target(e[-1])

        XA = []
        for A in self.A.objects:
            for x in self.X.fo(A):
                XA.append(((A, x),))

        follows = dict([(B, []) for B in self.B.objects])
        for b, (srcb, tgtb) in list(self.B.arrows.items()):
            follows[srcb].append((b, tgtb))

        IR = dict([(self.make_term(u), self.make_term(v))
                   for u, v in self.Rconf])

        pplR = {}
        for l, r in self.Rconf:
            t = self.make_term(l)
            for i in range(1, len(t)):
                pplR[t[:i]] = 1

        s0 = ('s0',)

        fsa = self.mod.FiniteAutomaton(s0)

        for xi in XA:
            if xi not in IR:
                fsa.add_transition(s0, xi[0], xi)

        for xi in XA:
            for b, tgtb in follows[target(xi)]:
                bterm = (b,)
                xib = xi + bterm
                if xib in pplR:
                    fsa.add_transition(xi, b, xib, tgtb)
                elif (bterm in pplR and xib not in IR):
                    fsa.add_transition(xi, b, bterm, tgtb)
                elif xib not in IR:
                    fsa.add_transition(xi, b, tgtb)

        for Bi in self.B.objects:
            for b, tgtb in follows[Bi]:
                bterm = (b,)
                if bterm in pplR:
                    fsa.add_transition(Bi, b, bterm, tgtb)
                elif bterm not in IR:
                    fsa.add_transition(Bi, b, tgtb)

        for u in pplR:
            if u in XA:
                continue
            for b, tgtb in follows[target(u)]:
                bterm = (b,)
                ub = u + bterm
                if ub in pplR:
                    fsa.add_transition(u, b, ub, tgtb)
                elif self.irreducible(ub):  # ub not in IR:
                    fsa.add_transition(u, b, tgtb)

        def get_RS(Bi):
            finals = {}
            finals[Bi] = 1
            for xi in XA:
                if self.F.fo(xi[0][0]) == Bi:
                    finals[xi] = 1
            for u in pplR:
                if target(u) == Bi:
                    finals[u] = 1

            for c in fsa.get_composites():
                for s in c:
                    if s not in finals:
                        break
                else:
                    finals[c] = 1

            dfa = fsa.get_minimized_dfa(finals)
            regexp = self.mod.SolveFSA(dfa)
            return RegularSet(regexp)

        KB = self.Cat.Function(get_RS, self.B.objects, None)

        Kb = self.Cat.Function(
            lambda a: KanAction(self.B, KB, a, target,
                                self.irreducible, self.reduce),
            self.B.arrows,
            KanAction,
        )

        self.KB = KB
        self.Kb = Kb
        self.K = self.Cat.Functor(KB, Kb)

    def make_catalogue(self):
        # Catalogue the elements of the sets pointed to by extension functor K,
        # according to algorithm described in 7.1 in (251).

        # Precondition:

        # Tables initialized and a confluent system created.
        # The system is assumed to be finite, otherwise we won't terminate.

        # Postcondition:

        # Functor self.K represented as:
        #
        # self.K.tabo = self.KB = dict mapping,
        #               source: {each B in self.B.objects}
        #               target: sets represented as lists
        # self.K.taba = self.Kb = dict, mapping
        #               source: {each a in self.B.arrows}
        #               target: tabulated function, mapping
        #                       source: KB[source of a]
        #                       target: KB[target of a]

        def target(e):
            if len(e) == 1:
                return self.F.fo(e[0][0])
            else:
                return self.B.target(e[-1])

        def add_element(e):
            if self.irreducible(e):
                block.append(e)
                KB[target(e)].append(e)
            else:
                pass

        KB = dict([(B, []) for B in self.B.objects])
        block = []

        for A in self.A.objects:
            for x in self.X.fo(A):
                add_element(((A, x),))

        while block:
            oblock = block
            block = []
            for e in oblock:
                tgt = target(e)
                for a in self.B.arrows:
                    if self.B.source(a) == tgt:
                        add_element(e + (a,))

        Kb = {}

        for a in self.B.arrows:
            src = KB[self.B.source(a)]
            tgt = KB[self.B.target(a)]
            tab = dict([(s, self.reduce(s + (a,))) for s in src])
            Kb[a] = self.Cat.Function(tab, src, tgt)

        KB = self.Cat.Function(KB, self.B.objects, list(KB.values()))
        Kb = self.Cat.Function(Kb, self.B.arrows, list(Kb.values()))

        self.KB = KB
        self.Kb = Kb
        self.K = self.Cat.Functor(KB, Kb)

    def make_natural_transformation(self):

        # Precondition:
        # initial tables should be initialized
        # self.K.fo should exist

        # Postcondition:
        #
        # self.nat[A] for A in self.A.objects

        get_nat_memo = {}

        def get_nat(A):
            if A in get_nat_memo:
                return get_nat_memo[A]

            src = self.X.fo(A)
            tgt = self.K.fo(self.F.fo(A))
            tab = dict([(x, self.reduce(((A, x),))) for x in src])
            get_nat_memo[A] = self.Cat.Function(tab, src, tgt)
            return get_nat_memo[A]

        self.nat = self.Cat.Function(get_nat, self.A.objects, None)

    def make_word(self, x):
        ots = self.obj_to_str
        return '.'.join([ots(e) for e in x if e != ''])

    def obj_to_str(self, x):
        otn = self.obj_to_str_table
        try:
            return otn[x]
        except KeyError:
            assert not (isinstance(x, tuple) and len(x) > 2)
            n = str(len(otn))
            #n = '%d:%s'%(len(otn), x)
            #n = str(x)
            otn[x] = n
            self.str_to_obj_table[n] = x
            return n

    def str_to_obj(self, x):
        return self.str_to_obj_table[x]

    def irreducible(self, x):
        tx = self.make_word(x)
        return tx == self.rs.reduce(tx)

    def reduce(self, x):
        w = self.rs.reduce(self.make_word(x))
        return self.make_term(w)

    def make_term(self, word):
        sto = self.str_to_obj_table
        return tuple([sto[s] for s in word.split('.') if s])


class KanAction:
    def __init__(self, B, KB, a, targetof, irreducible, reduce):
        srca = B.source(a)
        tgta = B.target(a)
        self.src = KB(srca)
        self.tgt = KB(tgta)
        self.a = a
        self.srca = srca
        self.targetof = targetof
        self.irreducible = irreducible
        self.reduce = reduce

    def __call__(self, s):
        if self.targetof(s) != self.srca:
            raise TypeError('''\
Target of %r (= %r) does not match source of %r (= %r)''' % (
                s, self.targetof(s), self.a, self.srca))
        if not self.irreducible(s):
            raise TypeError('''\
Argument %r is reducible to %r; and is thus not in the source set K.fo(%r)''' % (
                s, self.reduce(s), self.srca))
        return self.reduce(s + (self.a,))


class RegularSet:
    # Wraps a regular expression;
    # provides a set protocol for the underlying set of sequences:
    #  o If the RE specifies a finite language, iteration over its strings
    #  [ o set inclusion ]

    is_simplified = 0

    def __init__(self, re):
        self.re = re

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

    def __getitem__(self, x):
        return self.uniform[x]

    def __len__(self):
        return len(self.uniform)

    def get_xs_covered(self, coverage):
        N = coverage
        X = self.re.limited(coverage)
        xs = X.sequni()
        return [tuple(x) for x in xs]

    def get_uniform(self):
        self.simplify()
        return self.re.sequni()

    uniform = property(fget=get_uniform)

    def simplify(self):
        if not self.is_simplified:
            self.re = self.re.simplified()
            self.is_simplified = 1


class ObjectTester:
    def __init__(self, category_tester, object, code):
        self.category_tester = category_tester
        self.functor = category_tester.functor
        self.object = object
        self.code = code

    def get_all_arrows(self):
        return self.category_tester.arrows[self.object]

    def get_intermediate_test_code(self):
        return self.code

    def get_python_test_source_code(self):
        cmap = {
            'aseq': 'assert e[%r] == e[%r]',
            'evalfa': 'e[%r] = fa[%r](e[%r])',
            'asfo': 'assert fo[%r](e[%r])'
        }

        return '\n'.join([cmap[c[0]] % c[1:] for c in self.code])

    def execode(self, arg):
        code = self.get_python_test_source_code()

        e = {'arg': arg}
        d = {'fa': self.functor.fa,
             'fo': self.functor.fo,
             'e': e,
             }
        exec(code, d)
        return e

    def intercode(self, arg):
        e = {'arg': arg}
        fa = self.functor.fa
        fo = self.functor.fo
        for c in self.code:
            a = c[0]
            if a == 'evalfa':
                dst, ar, src = c[1:]
                e[dst] = fa[ar](e[src])
            elif a == 'asfo':
                ob, src = c[1:]
                if not fo[ob](e[src]):
                    raise ValueError('Predicate failed')
            elif a == 'aseq':
                na, nb = c[1:]
                if e[na] != e[nb]:
                    raise ValueError('e[%r] != e[%r]' % (na, nb))
            else:
                raise ValueError('Invalid code: %r' % (a,))

    def test(self, arg):
        return self.intercode(arg)


class CategoryTester:
    def __init__(self, mod, functor, arrows, get_arrow_name=None):
        self.mod = mod
        self.cat = functor.src
        self.functor = functor
        self.arrows = arrows
        if get_arrow_name is not None:
            self.get_arrow_name = get_arrow_name

    def get_arrow_name(self, a):
        return '.'.join(a)

    def get_eval_arrows_code(self, object, argname):
        fa = self.functor.fa

        name = argname
        memo = {(): name}
        memolist = [((), name)]

        codes = []

        def eval_arrow(a):
            if a in memo:
                return memo[a]
            a0 = a[:-1]
            a1 = a[-1]
            name = self.get_arrow_name(a)
            na0 = eval_arrow(a0)
            #codes.append('%s = fa[%r](%s)'%(name, a1, na0))
            codes.append(('evalfa', name, a1, na0))
            memo[a] = name
            memolist.append((a, name))
            return name

        for ar in self.arrows[object]:
            eval_arrow(ar)

        return codes, memolist

    def get_object_tester(self, object):
        code = self.get_test_object_code(object)
        return ObjectTester(self, object, code)

    def get_test_inclusion_code(self, object, ml):
        codes = []
        src = self.functor.fo.src
        for arrow, value in ml:
            ob = object
            if arrow:
                ob = self.cat.graph.target(arrow[-1])
            #codes.append('assert fo[%r](%s)'%(ob, value))
            if src is None or ob in src:
                codes.append(('asfo', ob, value))
        return codes

    def get_test_object_code(self, object):
        argname = 'arg'
        evalcodes, memolist = self.get_eval_arrows_code(object, argname)

        relcodes = self.get_test_relations_code(object, memolist)

        incodes = self.get_test_inclusion_code(object, memolist)

        return evalcodes+relcodes+incodes

    def get_test_relations_code(self, object, memolist):
        codes = []
        cat = self.cat
        fa = self.functor.fa
        memo = dict(memolist)

        def teval_arrow(ar):
            if ar in memo:
                return memo[ar]
            a0 = teval_arrow(ar[:-1])
            name = self.get_arrow_name(ar)
            #codes.append('%s = fa[%r](%s)'%(name, ar[-1], a0))
            codes.append(('evalfa', name, ar[-1], a0))
            memo[ar] = name
            return name

        # Check that the equality relations really match up
        # for all arrows in old memolist, i.e. original unique arrows
        # which is arguably overkill sometimes?..
        for a, b in cat.relations:
            a = tuple(a)
            b = tuple(b)
            src = cat.graph.source(a[0])
            for (arr, val) in memolist:
                if arr:
                    tgt = cat.graph.target(arr[-1])
                else:
                    tgt = object
                if src == tgt:
                    ara = arr + a
                    arb = arr + b
                    if ara != arb:
                        va = teval_arrow(ara)
                        vb = teval_arrow(arb)
                        assert va != vb
                        #codes.append('assert %s == %s'%(va, vb))
                        codes.append(('aseq', va, vb))
        return codes

    def test_object(self, object, value):
        tester = self.get_object_tester(object)
        tester.test(value)
        return tester

    def test_object_fail(self, object, value):
        try:
            self.test_object(object, value)
        except Exception:
            pass
        else:
            raise Exception('Exception excepted')


class _GLUECLAMP_:
    # 'imports'

    def _get_KnuthBendix(self): return self._parent.KnuthBendix.KnuthBendix
    def _get_FiniteAutomaton(self): return self._parent.FSA.FiniteAutomaton
    def _get_SolveFSA(self): return self._parent.RE.SolveFSA
    def _get_Cat(self): return self._parent.Cat

    # Main exported interface is the lke method
    # which provides a context for the LeftKanExtension class.

    def lke(self, A, B, R, X, F):
        return LeftKanExtension(self, A, B, R, X, F)

    # Other functions - examples of applications of Kan extension
    # in alphabetic order

    def arrows_map(self, cat, from_objects=0, coverage=1):
        if from_objects:
            cat = cat.get_dual()

        A = self.Cat.Graph(cat.graph.objects, [])
        B = cat.graph
        R = cat.relations
        X = self.Cat.Functor(lambda x: [1], lambda x: lambda y: y)
        F = self.Cat.Functor(lambda x: x, lambda x: [])
        ke = self.lke(A, B, R, X, F)

        memo = {}

        def get_arrows(object):
            if object in memo:
                return memo[object]
            re = ke.K.fo[object].re.rempretup()
            if from_objects:
                re = re.reversed()
            if str(coverage).startswith('length'):
                maxlen = int(coverage[6:])
                ar = []
                xs = re.get_words_memo()
                for i in range(1, maxlen+1):
                    ar.extend([tuple(x) for x in xs.get_words_of_length(i)])
            else:
                re = re.limited(coverage)
                xs = re.sequni()
                ar = [tuple(x) for x in xs]
            memo[object] = ar
            return ar

        return self.Cat.Function(
            get_arrows,
            src=ke.K.fo.src,
            tgt=None
        )

    def category_tester(self, functor, arrows=None, coverage=1):
        if isinstance(functor, tuple):
            fo, fa, src = functor
            if fo is None:
                def fo(x): return lambda y: 1
            functor = self.Cat.Functor(fo, fa, src)
        if arrows is None:
            arrows = self.arrows_map(
                functor.src, from_objects=1, coverage=coverage)
        return CategoryTester(self, functor, arrows)

    def coequalizer(self, S0, S1, f0, f1):
        # Given
        #
        # S0, S1 sets (objects that can be iterated over)
        # f0, f1 functions from S0 to S1
        #
        # Return a coequalizing function,
        # such that in the following diagram:

        #
        #  S0 ===== S0
        #  |        |
        #  | f0     | f1
        #  |        |
        #  V        V
        #  S1 ===== S1 ==== coequalizing_function.src
        #  |
        #  | coequalizing_function
        #  |
        #  V
        #  coequalizing_function.tgt

        # both paths from S0 to coequalizing_function.tgt will be equivalent,
        # and coequalizing_function.tgt is a colimit of all such sets.
        #
        # The coequalizing_function object is callable with
        # an argument from S1, and has the following attributes:
        #   .src                is identical to S1
        #   .tgt                is a set in iterable form
        #   .asdict()           returns a dict representing the mapping

        objects = [0, 1]
        arrows = {'a0': (0, 1), 'a1': (0, 1)}
        A = self.Cat.Graph(objects, arrows)

        Xo = self.Cat.Function({0: S0, 1: S1}, objects, [S0, S1])
        Xa = self.Cat.Function({'a0': f0, 'a1': f1}, arrows, [f0, f1])
        X = self.Cat.Functor(Xo, Xa)

        colimit_object, colimit_functions = self.colimit(A, X)
        return colimit_functions[1]

    def colimit(self, A, X):
        # According to 9.6 in (ref.251)

        B = self.Cat.Graph([0], {})
        R = []
        F = self.Cat.Functor(lambda x: 0, lambda x: ())

        lka = self.lke(A, B, R, X, F)

        colimit_object = lka.KB[0]
        colimit_functions = lka.nat

        # Reduce elements to a smaller (but isomorphic) form
        # I.E since elements are all of the form
        #       ((A, X),)
        # they can be reduced to the form
        #       (A, X)
        #

        colimit_object = [x[0] for x in colimit_object]

        colimit_functions = dict([
            (A, self.Cat.Function(
                dict([(a, k[0])
                      for (a, k) in list(cof.items())]),
                cof.src,
                colimit_object,
            )
            )
            for (A, cof) in list(colimit_functions.items())])

        return colimit_object, colimit_functions

    def test_arrows(self, functor, object, value):
        # Application of arrow listing to test sequencing
        # Discussed in Notes Mar 9 2005

        tester = self.category_tester(functor)
        return tester.test_object(object, value)