From f7777befb4bf8fcdc54e210d2251262e9a8c164b Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Fri, 12 Jul 2024 00:23:55 +0800 Subject: [PATCH 1/3] update --- Makefile | 24 +++++++ docs/Project.toml | 1 + docs/make.jl | 7 +- docs/src/assets/matmul.png | Bin 0 -> 32634 bytes docs/src/assets/perm.svg | 36 ++++++++++ docs/src/assets/starcontract.png | Bin 0 -> 57503 bytes docs/src/assets/tensors.svg | 112 +++++++++++++++++++++++++++++++ docs/src/background.md | 63 +++++++++++++++++ docs/src/basic.md | 61 +++++++++++++++++ docs/src/extending.md | 48 ------------- docs/src/implementation.md | 107 ----------------------------- docs/src/index.md | 42 +++--------- 12 files changed, 310 insertions(+), 191 deletions(-) create mode 100644 Makefile create mode 100644 docs/src/assets/matmul.png create mode 100644 docs/src/assets/perm.svg create mode 100644 docs/src/assets/starcontract.png create mode 100644 docs/src/assets/tensors.svg create mode 100644 docs/src/background.md create mode 100644 docs/src/basic.md delete mode 100644 docs/src/extending.md delete mode 100644 docs/src/implementation.md diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4b77896 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +JL = julia --project + +default: init test + +init: + $(JL) -e 'using Pkg; Pkg.precompile(); Pkg.activate("docs"); Pkg.develop(path="."), Pkg.precompile()' + +update: + $(JL) -e 'using Pkg; Pkg.update(); Pkg.precompile(); Pkg.activate("docs"); Pkg.update(); Pkg.precompile()' + +test: + $(JL) -e 'using Pkg; Pkg.test()' + +coverage: + $(JL) -e 'using Pkg; Pkg.test(; coverage=true)' + +serve: + $(JL) -e 'using Pkg; Pkg.activate("docs"); using LiveServer; servedocs(;skip_dirs=["docs/src/assets", "docs/src/generated"])' + +clean: + rm -rf docs/build + find . -name "*.cov" -type f -print0 | xargs -0 /bin/rm -f + +.PHONY: init test coverage serve clean update \ No newline at end of file diff --git a/docs/Project.toml b/docs/Project.toml index 8f7ee43..3964eda 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,6 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922" OMEinsumContractionOrders = "6f22d1fd-8eed-4bb7-9776-e7d684900715" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" diff --git a/docs/make.jl b/docs/make.jl index ba56981..2808f69 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,11 +5,10 @@ makedocs(; format=Documenter.HTML(), pages=[ "Home" => "index.md", - "Parsing" => "parsing.md", - "Implementations" => "implementation.md", + "Background: Tensor Networks" => "background.md", + "Basic Usage" => "basic.md", "Contraction order optimization" => "contractionorder.md", - "Extending OMEinsum" => "extending.md", - "DocStrings" => "docstrings.md" + "Manual" => "docstrings.md" ], repo="https://github.com/under-Peter/OMEinsum.jl/blob/{commit}{path}#L{line}", sitename="OMEinsum.jl", diff --git a/docs/src/assets/matmul.png b/docs/src/assets/matmul.png new file mode 100644 index 0000000000000000000000000000000000000000..f16d4eca05521f639bf183a7a8e9939088bfa32a GIT binary patch literal 32634 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 a2^5%KgzZ0gj0P+AKe9I!Z)9J;@BLr=QYQ8Q literal 0 HcmV?d00001 diff --git a/docs/src/assets/perm.svg b/docs/src/assets/perm.svg new file mode 100644 index 0000000..d572238 --- /dev/null +++ b/docs/src/assets/perm.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/assets/starcontract.png b/docs/src/assets/starcontract.png new file mode 100644 index 0000000000000000000000000000000000000000..43e5a8c1dc0b4e4a15ada5569b4aeaf949f8f6b5 GIT binary patch literal 57503 zcmeFZcRZKv`#+9UqM;%s>XnfYLbiBSWRI+rRiv`_-fe{JvZ;)h5kfYVEy~_x?~Jn7 z_qe*>_x-wb_x}98zkk1v&;58*?$dRh=W!nAF`vhAUY?5b68lK0NeKuD_DM;KDG?Ct ziXk8%(k0miBZ=iZmI(;-?KQ5pfyu_WYJ ztn`>1x&I-oGzpvgPg8mZ!b_f<tBPebO+Aei&sZwIe?OD`$W%=@ z#aA1hm0st*?v)wQyPH-c-7lSH2(UsQD7~!|_Yqi%uLQif>2^iQlJr6IzH`_exKc{; z+(KbaRu&eTQm*#RqQU|~^6O457vmScY;N5+zj9yr1c4+)nZdfSHhbA_!qQ}WT`3U) zv14W;JUVATr4yO#*-Jj~h$|wtRFx|tzSL=$*MigdsRp6q)j>0KlH**UlSl#b~EPU-5P z$7QTjS1)UyI6ks>?9x=(=&pwsjY%w?pJAfYtWJ1C_JE)K6XkvR!y{G$nAQjOu^5hX zY6kD5xCE|@lcg$zreBxdq`5}7#QI|a8%Fy@X`-Z_!aQj8h2yO|nsj9pPuWNx?m0-F ze0l0cDDCn1tYgYAs(p`U`Ah2Ep3}h6(39_6WBr+N-&#uXS!3~eJ~Q*;_ITM-OqV>D zM(u5xnDEAmgpd>tD?m7Pzn)#s$vXAk<%_k1LNhVI^j${x>k9nVt~Rz zKB(~o-{B$RT6^xNTJxm3!FqEKopUjitM>W)qAch$i2I?fuH{=J1w)0=qd$ zo}4S_ZtY;^;Vi~$PinzVvO{22o8=@U^?V3H6!yyUff-G8hjYC&>iQd7Q73PgaG$Mu z$a-u%Mq-!A*MOsvdohp6A3V*;CH(%tslR`AVs|okec6RwqjNn`vq4`k+Kc7Nk1=#d zF`Nxprx;fMx@X}*P@d!(Csi(Gvvv7~g<0bMU<<8o0{(C8Uk{KiJ&MvgRjXFPR!cg_ zG+k2n?MXsx7QK-F)%kOoCp$(){U>ZE(k`=PYHqzaDV}0*dF9T5h4rcEjmwKG>HF3? z4rx54Ev?sO%J|WKFop13`k*>}>tovB{@9iUvEuw)Mdek4)sF=~x-B1f&dih@5oi%y z;CH$DbC@i?y0^jo!gXOSy3bXg@1}pFx>)+{sl6}#(R%rMc7m#64zISh@OvwEI~q*Z z>g%?45X=nj*s5pUF{eq$HNjFcw*e#7croKzf!{#P^JCUt>&rQ*L z1QMlE=DReBLqFJ8_*&l3Igu=~b+AH(p_>+3<6GU5!ese^YPdM;x;B>4|LV4zQu z+(mckb(QRG5v9jL^pnr)B==<=Ft{X7H|oECh} zMAnacNS|Y9KPvJJa$U*p7oVvm^hT``Q4o3^x=0;xu1G_ zPI@{$WqL|mR$1nH$n&*ACX+)Tos_1MNYcZskSuTO2r^ zm68-Yk}PG1y=u6FzuexJ$=DG{BQ+A35EvTpJ|Mh0v`TB}3x%8)PkHzuiR!q|uTo;0 zugWWbzuKFK!-XX|CSFMTX$Q} z*5r$=>5Vsy%z5q@sTiI&=x!csdu`;~_^kPJi)Kom@{hth?~h2;O0z0@zg11i7M~1i z)f2qJm+)>}c-47TZPmarl=o`ajqq2IZ?xizGzzo|6eMIS#hEVN4U>OUe>GBGOSVlq z^i}w)0u{TG@B4ZbK0SM!@p#W;HflA#shad9$4?9EKZzaRI6D1In{;WsJGOh`?j%Q> z+1C;?_v7uy#E#4IwBI!EjIqmIG=JM)*#G9!(t#4ar_`OtDvs8l>(*_*({6U#n8KKW z_lA*mO=6pRTl*LOTKhM1oP#G0=X?5je!cys+9GgtFYPXG|4-_l?&<%0Ngek1g|r-B zcuu%0?>k;^K31+SJ=?wr-TLzid^!fby1jRA>2kK}#*3$x)5>HrHgPpsW)EMlT~cdR z^Hd{Cp-#z9T}TmVebk!Wx@4TlTgZLn?V)Kw=w zr`Qe0HQ$2|51ybGqsK{fTPs@K6rkX578JH_w%KcU*3#JAS)ft(c1_hV{TJW$k)es8 z!K{|??`Kl4#=i2p!sF*SZ9MwfD$Tl>H%w6Q-p_~zpI170?FA&7yt&<$Zwh>Ew7zu? zthUtk$PK8Cwho&1M@?uCy9OrJJ=0~s6ZHdQzwGpRj(=dTp{b6$&#GipM|;0^hqh2r zex zI1T-NKjly3WHtvPDLbj-j~qFk!#;I2S1XsH(BZ5gul1By#uD9Gda;B1{4oKC^XTSX zgKV0E58hgE{sX=#-eYm}WvkVd2E$2&eAJ@v< z%jV1KU;9hF3t&HeoPjLxxUwYk9_B8k)ykc|8a!!6g_Fwxb9|@O6<+Z6uZunK6gccB zA15~;FZf(qQckw#!7;l8oU6_eW-z;?tyj#u?r#>@De2}fa(0$E@$B+Bo?8Z2yUO7o)UEj~`{v*!=UDSwYjF+Ut?a96H5^5XBPwcF z7xg*K<{s%tY~+u$c`%O4bcW`$^`t+`mCc%}u>6wOS|j2jyS86$uLb>PMQZq14Ut z&puJVheW9*jx6%jce++ggct%ILM6Evhsb6=k>up`%$KsyjRkTOR ztr#^|-V*F$4U5`eIyp_C7)TiN>Blksh=Fw`j;8~kStP!R-YP$KRlA!Y@xj(iL(%Na z$Y}zn_a6tTniG6>W4uVQ5xcPxekX7b?((eUDXBf3rAcQVF}h(&z04|9M6p{zd+K4u6n${`z-Ez+-~l@PCKkk9`c$-%sy~iP`b@&qTWLJA#YK zm!+iOUu8W@eSK4_duGsAB=M;MVmgi=ZjvoL>~fr`4dx}2<_o|y^z zt=ne0`t0^5=Eyt*!uEpjqlv!tEsVX1v8k1y{RO&TPYA-#$S?;T=GPTN{{}Vvu=n>6+PCU!bEy7W(JE zzv$GrH^8rCYW1IO!3H^y-*9lUpX2yvZg^D~85LACu-7-fE@of?JcBhvcsb7r|9bvk zzrnAFdQ%<$CMT}|FZxx~uYP}3)k@#;vY832X)S_3um8M^{^fsO6y`v-j$*}MeEu~G zj20mk=J@B(L`X+O8foAhX$-^^RN!BbGUPu(PWbE0U;iRMOExRHD|{v(z!FG_T~x6r zoa(X5q8!c>oqZC23G?*KE*>$g@jX+;%M^R#uKBc+u~ejG#N5<1p1b=~TV{&qkW+Je zy4~41x>EyH0{%`ZtwVz`FSAN}vV24OJ!?*wB1 zR~UXV=YNF(k-`5JhW{0Ye{9A7e_{A~W~a#d?5Es~#V)-^lxk1kmTU^{+Iy5dQqaaQ z=*Vfgf2MXP@JIm%aNV2Q4{u*Ry2*qWnw2wViq|UcM!V!Bw(+#8(`(!JKT@}<ULiUv>_hN1?PCvi?UQby+-6~Kb`TRQ z){YDtqf9?e^V>+cneXKT7qW)VZZ21fR($*LK<0!p1KJ09yrCk;vK0k$@4-9AL_&`y zc_Fs?3rpPr+z#J7cIz(n*l{?>`r~&7#yLbAOOX9jtsXU9%r4^Zd81M7uvaDS@s4+Q zg@1hJZio~2Zsy#HB8-GwotKcXInzNP96zH63)PDYPPRX1`b1ASO=XC4uatAR9^~t> zR<@pMx42q&a+}LYUk67u{N9QYE(rjH#J zEjzxvLG5|y+P9Z?qdbk$@=jOy9H%lXoVya+Ajj8p-f`(WZNXHg%+K*ArjokJZSjvP zJH{P1zq45cbxh?%Glf6oY2b|KmIwW)PA<1vjDKtW$E)k_?syBz z5G6Dzh`Kbm&R4$R)YE-e$IFWAIJHfYR)Nro(NROxoR*k#292-BKoR<@6GGTDD(d+9 zXx66QDd65QMcLD>E=*oi5gm9+Kaf9}_J1=U(CD_g-mdG-MykNYn99)K^kMf&&CKK> z<|MZF-I-(UUtAa89lhXaeYFnFFJh8r1uTK8sOYuBcsWQqsLAg!v!uJ*G5vbL?v@ z=gm_0nW;PPdu+X*oOI0{i_k7|6rVQ~IgSzv2;sqe*3>sjqJ;K*Oeu&Zy@N|{n~odp zansyeh4VG64Os?Ff6ml>2*!9g!-JWXC$f!OY{<=PIp;cqheaC*u->vitxQJS_ zQE8Nnu$(dPbr>x#r_!OB?t1SxH(2R5+N2;A9;)qV5MlmtPm*t++t$X%K$WB&q$nE5 zG3nii35>Tog-XyM}-r@l4qER!x<&(tZ9t+^_CKZ?lr^@5XS;bz6x|FuPM z0WE!BNl?=dY2MsiUwOpzrg(Y4J5JthAz7z_-3f56u4$+7DilLX9AG9MY27H5B%dJr@{mzV#uZ!|{`bhK{OK?}O6!GY zXg)pO$2yUv@!pj4*2jl&VYDa?laN*hS+wmuiPzfHre z=%}cx^Y04&2iYHzz1dsn@MuQVWufJocqFY&^HqyFo;He>Db(axcdRW?I(61Z3@`QA zdg3Uz&6RfNA9c!F`)CEvL&WnO$GZJBUUvVvbXo3yGWX!* zI!5&x-sZqzdKg2X(!o#t2&L^bq*Lji_RkFkDjc!N*<78hoP1lN{kx=ffK$#~I8TjY zm%zanLUyKEMs4hO>Lacgsw$mWVR|IUOIxzQl*{+fYX^VX0kCrz7(#0;b zlL{9WRIW-KH%`A;2%;v=BZQ)e9P_*gA`>TN`a^hzfsq!l8lfoOI&ajP5+}cFKh4o= zS~jZx+8_sPu($asYC0A5o6U(=GloMn;`4LYz8C1t6fMdBzCjJxU{2H(6l#LmO*9%| zB_H9sI-VpSFCR%wD`@?@6~p}TwJy^Flf5TJ3KIj7V0ClhtsCXmiZA@2pWg0hBsu`beXs?Gf=N_%95;&DOx2?_J z)#>&h7^C>@eaVK2rfrA5IPH0ZMuvbH(bSwyLvfq!r}3vHcM^|$i9QJ-(4AAptBcd` zI}MYUyZSa4rvpk*;WGvs^9+=OYk(T<(pJeB-ZrnzY;De{-+DwDXVzDYM5uzhUDoF+ z^(txYWNAyj=TAZ~;QKqjV}xP0`CRH?l*%}getyA8zX-vO{eUOa5uc!kigrCV*QScs zzIz+?ZR$n4EP4)UDD?HJY1y>cPo}<)GwI6dV_!oB+;9ptXE5$8^l7mu;?-R}J{=Gh zHZ7d1XePMewD@c^+D%0Dq=>VBf2^<;Y%x2vHPU6qRQ4p@>|_OA3k5Hz|)j1fo7tNA5`Amsq>onEjlPfHor<8 ziQ4=y`B5QTW8=)~(~NJst-f3sgk5V`pLG~ucDOMSA8vX>MP{?zvX+g0<+RFVYpVC} zQzE&;{PBVvC^@V>bIxL*Y^*ceXaYA<7hb97cR|g*MceY6!~8gyYTw-_>|@5d!CX)l z(*_HR>!VZ#Y}#XRpge_nLMY8mryz)iILG-)!O4`vccUEc>^*u86UJ+D!}{~~SnzxbxZYbuJw7Oo>XRSkHC9K=+T46C zN1KCcD7)4`kg~kzr~N`_1Frq-K-n@7?|EQg&0CNCs8RL%*!i-iT#LbhqNQGMj*@k* ze4EK5$IS{Y`gPV8r$f!NKcO~4j`{i(=6HO>PIQ~2##=scOg>~JF^0|_a;StFbz;bD z|2qlZHT`WF|CcBK&+!DScX)ZGEupO2fovjT(Qvw$YBD8TIV1&H z8S)$1p+YWqtQJ^`{M*eaCzU7-ud1?#$D_wMVa$guaU8$5dsFac#U|M~Hxw!JKuXOg zmN9f>{uxZ|%d6B+@fH!lI5r^JRFDc~)1OPg5+|;SE1)ddc|fvM^fWAfF#aQUii5B$ zwa(2Zl#_^IfhANkWW!Ks*-ZoByA12FFp4^oAS6>4(V$0X>V&Yw&aXWIX!5)PZ8)+c zL*{R_2YYD)=Z|yRuvS2gnLx?NP>;6mKK@;gEjY&&W;~nzY|yI|A&NZ}AB(c_nDhwP z+3-WFW2hrrp#Vv-(y|sutvU$O!;`kaixL4Ih{SL!jJy|7o5f*auRFb8i=)Q=fGWCU z^N_$XfQKEmEF~Z~stI5#>6Q$ z(F%nvhgB(G+3BIEt2qTLJi&3IS4}sDclCc*@}j5{fPi4w*&_>us$pLNrpDu?&ntzW z&qo4F&|=@(DT|t~>MdjeB}T8f@sAOQTn4C><{mpL33bO-z_QOS?n5u34+0guU}uMV zm4tx^>XtiDBZktzb>&(EE|e6jK@p-_)Jk1ND4{r0 z0IyD!nf@dG@Ph{MuDOgr6`OP&nDXK7*%xa{KCxsfJ#Gk#;0HpxWSwR8P zLN0UTA0uhL2CwQ|Y(qVU{bSM%dSaP%^ahG`F%8HrrW?cg|2Z*_PLSf3k^C^qe})K& zS{OlO(-s=pP-8N1h-`#aw@{lPIqwc66F%=j>)2yJjd&umg-}pFHijLxp~W?U+J(v+ zc$Fnot_d~P`~t=*jx<~2nS9!#{>e&w{Zx z!Imdb)DhQ!DQAgJ^+zq6h%kz1%v1_*DhNCfE%WwhM~PWXK8SHkk!wB^erqwj@K|<+ z?;TXdq;w0;ah(FsCUT6T15iBNhTVk3zZgULBi-1QM0+y{G3df)}s|r2^cVE1b4mBnN2JeO=>s=I|urZpzD9dW< zP?R;&mTic zF%H@fRNs&#n4rd_VGq&;iQ5k16tHt&(lpBOkOXPLtG2p)Xdh5|2%eK+utbMOE#PHv z@hy$4C{nVadj!`K%)^0S)(0qQk)-O)LMcF1FzDU2+E_Hj697)(-o{L#9>XZQ0ZTUa z`JfIK>kEf1aAR*OigjP_0d+pM<8l%I$P?BCq}b3(tIq46Ap(yH5GU0($MF!<7$Y2F z2*J=f)Fz0j!5_B}RGFf54EqVufcnnJZCVxzddz;z2ESQioDwiExHjGZHD)LaV|rwU zf_NdLMw~^)7SZQu6e+?$%6vMhBZ~1DZeYNjpj{|kbT74pa|{Wue}tcoWaui$Sfy&i zVbnH!S^2+X#kNu`Cd+Fx@)dVGwE>hL0ftpj!% zx_ZhzM;!$Vm<81jbOxwOuSZrXKy!moxq8OeYfpb#A&N%FWkI#S@9w)J6`!xaLn=O; zMkAkJa03);+`)At+fa46EnnYTeZ`3_PA;4`1JFGQz!P+f7FxZt+q8wkc#J}d{Ygb zN(iEglpkGxzB;LILpF%g5o}BYVy^0x!q5D(pvMHcdan5`1cT+&EqiLeI-a06ROQd< zvij4DCtCPaHq6dBDO9>lZN%(0lCNZN=P~`^5(m16#Do62A|5ZWJ zFwJB9UihQ_1%Nm$QpQ;gS1h0wU$MD1^9zD(S$KO3Jy8&ncd=g|L<^u2#vy+k5HT+( z8)VPoiUOGQ6^-G*pa6C{z)YwvLg3vjheMH$K+ceMwbAN+!Lb;mc&`hs4reM&o^5l~ zI3(h(Q!)tphZ&G@$VLeZu;-7(<@P^5j?_(SFT4b(?@EGvBy!vuKh1h<+I$wLyQqi~ z7_6l?vkhBtV<*UtoPBzX`%W3)h}mOX%*yd)fD>I^=7Y-3$E}lY>lO_*wfXOma-kXB% z-sw1*I#?;XX~CdyLDf(us?~9^3qR;uDTzvC9DG z)57F8a3cY2jayssWFE>SR zQa~wZvoYd34O&wF5cSS8&O#Nh%%YN($`9%)N<6K}*WMzf`#7BvSAXFRm1&Ln<~FD- zkW*<{UoG6)T$72YCuL1hv}f#_aobwE*Me&~^u-SCr-^ak2vkj2<8|U7ld7!CtfZ)n`Lu#dkL%jBKe6Su{?+CH zFwG%qO`3R-fHE^k-HDRbmbU{47CoR9$P`)6KlltOp@rI;vPGOT>n%hiV<6>Sz1N<@ zr=3TGZe-m%=(han->MyO1*qL(uAHh8YFo!apNoyU3=$#-kS-wAYg!8h@>ZyTmyk#m zqA{G8ej_T7b0#^fnR^at7CNGx7g}hVmS$2;dF`xl!;h`azO5fVueL5a!XXc~m2BDw zLt~VUKjnnzdjA0^gMNPsJqYtcU#w6Lg^yik+Sv<&3Mp6Oa(aUO4;lQmN9Y)PBU?P)eM1vF?{jm>J*)ttaby zzM5u5gNi)evDz@JgVr$@y!Wi~EQPlygudtMJ);%MsrSvd9zTRsTZ}=R z+@7rusbL*(HkyHQ`?KVWwKyorJ$9}?Pawn;w0>oLpeStt%xa=6ZUOK!e3 zn(Qla>o)(iuOY{z3%30B@;B)D@^o43V5;ytsZ)9EAOiaL8zcp*-AJmpqCv$G?$}8f$kn2F@co=m@Hj4e?(U@MLR2HW~-&%D2IMAWqTf- z>cbSFQaAfQKC+ldN~qXLrKvb-1FqE*9^?|G(2dc zAw8&RvAp*f@2~WCia_^`WK@;|l*DCt=Rcj?JQoE8w02;(%!z9$C8bEe!jlt@_dZ7o zy&t-XxE@V7X+}S0ypTapDF?)Gg((k3@D>2dt>FDKdThJO6R*CKwheeFFSQIsxtw`Y zhWd@QCBK*4cS8yr5L3kuB>dKehdqIuoBGZR_;X84FI`{x0cEJgGle(as<1*aiJe%P zR>=0Oje6={qUxn6C}4&PMnBAl@JjD%%tig&cc;*T_U{}bW@2Xmli}v<6Vadui6{GM z2atX))1Lfb;WTv-k0BdpL?@Au%O(&hfz9@RB6}++4Rbyu9WYB@@T5oa3k1L-KzLwaOD%wSDPGzuUMX$A}9 zOfg<7EHSgt+$83A;(~5xmO+xK8k9|uB9(E$bWV~U={{C-M7mZ+qjl!vk@)IXBvR~} z&qe3p#4Lz~dzkNpKfNjs?0ioGgXSvKZPhZv|E|mhR8kyQ`z5o8>ztP^R_byXjif4B z>zR?JRoZ4C#Nn(cZ`mp1MJ<>LOg;C&)VnY29aW_sI|gydX)F%18C*o%ck7=)pGXC` z$`C`$$_bTuTp3tNE*n|ADuH+gBVqTYo(uT%`>TB4kf0D9(C4yRt>Aj-%Y`M)l&nT+ z%I}TSR8-4gfK^Fi@6?55FUO8GCn+;jLhnnYU_2^-hPos`KRj8vYj|4*VpZtyL$^te z&&Oi0;*B8m&&d@+ix1MX)y(+}4Z%Y!nuT-IY>kDj}Ut=98eImka2^I!lByBtq5bb%sOTkDzL3%~7t z9~2P`B~6y_$sV*l91vN?@V4K4unhG`|-b5I=s7aeKH>ySMF z<@fjZ8edCIyx8XasR89|QEdE<2ZN!tVQu=oPB)xuk~~rtM=G#cW_=J3RV7J*fo$rI8s3&1JFmGo-=6(v~XkYBq3B1U&oK1)N`WR#hh0v3fB%cGF zen)u>gRbSgxjnD*LfFBwKiCUIN|tA>pl^d60;WP0t!;wzZyJG>5+@uOkPtzI3VJ>L zIQ1$hikX5069LJi(zd@9VOhhRq+PPLF;fYC^Z0aUwhXN@evbh9=7Gu&AK}IKaC*>? zFenK4oVXy^QjJ7x*EB7}acPPdh^$8IecaaGyLm&m-G!E)U|){ijj;Hwi^~Ja<7?QA zo$(4pc_eYNOCj|}wwGP61CyZjm}39_p5kI6sGi$R0aZ!2I^Ub=*puRHCR;)G@f;%| zKLZIcE+W6;^gn_Rr(%-Rar(-$qy7^^NSvbSx-y)Ue`#S4V%zfVW=;%N`YG^47sk!J z4wV0`ky;UeK@|ZTAADnX%txXxB5TG!zxN2WlzXwJ9W^UjP)o^fy#a)@FwcgTtTXNx z7<#VqLv;DW0aAthRM64iX+-c6&CCjXI1e-yEq1bgFWK5uVS@9ytqBr?&`8SAcmD=> z9J06F8qP=fy3H@sxGwj5hfbp)1Z)gaamZ|-#;2uN{hiPregfRXGo)XLrxBDK6qzqh zCX^i-TUt2Gq4TQ@Oq25A@umcYXEXv_+xxQqU1ISdCDVii$>K9-rw%Q>bzXK=*GChZ@o^LVC(hS3{k~I$|Hz{Gfw}oD~a88 zJ}|lr@;>DSL*}1T9o!K0Df`<7Ix+RBb%K_?Li(u3Z(TQC1$3d(4{#KuJGMa|X<_j^ z%yeXXCszy&$e(2*bs*jY?A)0Kt+Yt{mNG4aLOGIQB{^nOh(M72(P((&^UK4CD}>bU zOceae9-OSS{H^5F94~r5VJ=YalWaG#&N$R>Q3k>nEM`C1Z!EM8LQd%k;J|ucY}^*u zg;B81LI|KFz99VlCxA0od}&@9vN>?EJJiLXnpp^mh5;xGR&Hy@+X)uT*Alm_T)2m! zWakPAl3t)3uT)EN-gDvcA4m|$^9bTs%1f^y(iX5WmU=Xl6blE;D=#?y`qJ0zXL{xQJFU^ydK>99XbN$CiogTQ@j0$R_*S^DV zo)h1dn&pQc*tn2@s7c52n+=}Znzj@Vz`_@1HSyhg7&D?!E!*qsi|jOFubv~J}N4+%OdG;sA3}PR~dGprEaT1=o;7hND_RZ5YD{v$gM(jN;8{I{#W*yML;NUfGY@@cSC+o_faJ3~Ltw)gjg>B5`#GKveP=QM zLz-4W1?1AoD%HtbkN4At;YO3p8^o!~tC^xB49B5$+MC{&pYAtXsRrVo!r-$lw5V2Q zJA7L9%*5^N7B%lA<%BC>7riE0imgT??J5982o0-XFPJ)XKy=+4S6uiAI?2kRb1gJq zIEkt6dd&~sJD*=5_XKd|ed{B9{=#f`x5b?QDu8?JIwD!T(u7k@e!*v^-4OX6xPsuA z-iF!fzgpP=Xblgm0bEFFp64O(HB*tLS%$sm))QLk;$BncCnnFEAb6yNu+R4q8P$;< zh~8c2+V%W?YufyS3|;gXDiA>sSKI@J#JtssWZ*1E^TI{~m5wtfZ^!LG+4xXm{^XQQ zX{7TnX%4|b;7TyJ@S!7hpqxw`X~L@ZAJ4_lXW%_^F6= zHYV*4xR%QJRx|lcYTArwwn-N+awn=|DH<+qSey-sFRaN57c2$;j5gQuVE!q*TL9XyI%)+(y}>Ak71Ta;7kfmQY| zv`h`j$%p=8kiT~0cXbmNTB-w?DgiR4Mu1qu6fi4-j}M$YAs2RDindnol*5MhJauvT zdouQ1jJ(LoP={H#BW*jGPeAjkqudPa%?mIK?tmG3wqiyF zu?ygN5F2;a^-SAZb(1Ds@{?ZR2c!fE-+$}!z75$x&83E;cpqbl`5JrqNi*x9Z+8Fm7WDxyr&|wY8Xo zfGav%t8HeX>-g{-noa)Iy@eenMsOZ=aIi}IXe_HvSwI~1W}@XrB53jT&rEw}5y@@0 zY17h!i(JW_Oi|L;Q;Jt7I88dU;x5At83$qTKfiT1SN+S$s3_h7V0&{sXypZY+z~Iz!{^Mr69)-y1S>(PPiL-*suJxQB^GkmEKF(f%Aef;={Z19zzh!@gHU6DT$W;8Gy zsv{qn4|kEu5EP@@E(_#dkbvdG{hi`H-!p63 z=fJ>HZI56vNJo)cKn2P=-tqvwD+d@~yICCW6zD=hP(0hPM_?lHm2|PZIb2Gxn98WU z!HEIuVyYk>PfDCich#o)Tz`@X0Fae=F zu8!fWOtIUxR&=ZYfC|HkJg4!sNm3F7atUawa&dxQcn#SX=lZ+e;MNPkgQh~rj>x=Z zaZ6B34qTzA*l|GkIdvLnr~glXXDeJ-4qu-$cPq%AO6@-h(e@ilnSaCCxj-P`c)=C8QA+Qilo<9N%%3$>E|7{+ z=yhnulP_?7CA2b20Z-9u$Lm90Rd%kf%qh&MG3KD)ss6#SB3&*OSXbu zAP9lKFs+KAjJ8GlySrbMo>*!iMTF`$iq?;T7J1@r=x=G9a-XNi!#j%fL>z^)mk>pg zsT+a3#20bws&7LOE7oc9zGnb}=+D;Fpitf?*T3y%ED3K(x&H1_5mXjm_P*#WWyweN_@+7Na-}lF6cjMFB#~IoLxi$koC=cFN7-zi&c0_L3nAH;ElXoGfyAhx2ZI z1Vy!Ba_W({h4a#g!%Nb0;GnT>zxB&McG7U_iZR@JvptmtuMjNLnu`x}STM5y42wZU zNy+X6zxho~n-0-7oZs;a1|!g*=@gW z{ABlL>eot+gnh32?F`r52nYzawiLehIsg5wqN$!eg>tHErE`@wb+@a8^{b9@1zI02 zdK$#cZ4h$k;7e)d%lf2`&T!o!O?quzO%wN;E9iQFLyh^qt)-5wrQUi0r)Z(5TQgR! zlRy05MPEo=&|1oWzcH1qh6~?fyL6F&keD3%*Iypb$#c#7?}P2XtgEZr-KmUIVeZJY zO3?Vc=QyKu&~v!M)1%S?Fse)oPE~I1^{zW#qS)Y8U(h-PZt= ztX@N5CuA*>Jc3K#%U|yy}ZEc|3dmeg&svrg#hS1aBs4eZf z_F(Lj69JG%c%P1q(1bfxcNrRlyC7271&LVv-4`a?xKNrv#1P|LQ(gY|Apl(@#icdD ztZWkB&ztpjOBNHCJl<;k1|wXq>-GZHW6w47t*c*o zY>}1l6TfmLzr14`Z-|}QutYU&aheBEB7z~iH{TC64W3k^Aa*Um6*zexp1Av(<+)uF z5)$5NQWPlxP>J&N@(O^g<+xPp!$UVd;O;8T2)S)K8?@kp$Fok$g;hbD%^k19|DVed z9w&hsg*M2U39kC#p2M#J(T%rHCxZ5kaOCb=MPkHOn!@CJ!?CB)nt7JTnkI&;11r@v zaIPDxN(u6`)j`aGecz9#kWHSy53lm{xI)?&r*oWQ`x*4X8LYE?UO>qP$^BB`n0TA? z{8<2`LsN80dbvN_lI)=ob=4%LID_Hj>&4j1B=2FL|!zuone~wx%zQfG(~sh*^0E z+ON))@8MUDfl1~eObcV_%g~c}DdLjPERWwD^3!Yr!Jad26P9SzHpZND{CN*P1Cx++ z`j_!^U6TWmH0hKmy-rlJxtbirp`#6%dB2*4)(?Y9Us|Pj*<e{Um2nm2BBqXvHMD>U6wWURVe#u>_G7g{HsDY$c&H}YZ znE6lh-Q3{;nR^Y`23el!Xwj0X?mXqp+ts>2=rJPbLkfXvM->?T9+n6eRhE_hCnsMk zy^%Jx;6+(1EP)3W&Ykoj*AhynF;zr&zeEMoiF;K+1Ar`#17Oeka4$QapKy(=tgK9O zxF*=gU{Tnp3ryDvIFWxzJRwLtCHWoG``aWQzKlV)WB2~^stjCQjYpZ4V=wJ&5+PbV za+Fi|AylfmRHU@l#sS<71%NPY5v70#ZA2jTEaWxaJGMy_7!UFD)mctUrphLeW0^t{ z;4_wGLUEUbM#Nbi5=VL}cFl9DxnM-NZha(Hj=&Ry{6v0+@Q|WMz=#Oy^xCoC0G2?! zp?d2OB&Y$EC!9W8p1ioW2Z7NtZ+;+BF1H-5H%XZchC~xKfO;3>j*TIf#O{<1Tl<%>g>zEsWayU5u939M+yuMU2+~(1w+wJyXDSk1>984(u<7N$qVzp6^I zBi{zmg5E5@-?(`X;pUN1R}@Epo8U?jn|>WC{Ykt@N^b%Hx|N1Y)4%}YYu`XYL%`{3 zs0~0nQYbV#wE(ZT*(S_aFv&!0^&2R`P4_GX;YS48a(+lk*(dYv7t@s8s#*80!hw7^ z2oOLHIH2D75hR9zX1*JAbaZEz4x@}4B2wTdS-uW*qx>Y{@jdVj9x4cf59c}jh)+_} zuMG+2F=~|r^McT;hHV?h>68?YQ8-620xXmXaBf2hGit-2tXd!f9dDQtccTvS;-Rso z1V8AD6$-H{ftI@4KfEY0W zdu=E7O`x@koESpBXA3c{Z*|NZmf#ylwGi7df__ z|24119++3vPVw0Gd2d&dALBQVX(J70(@=x-o{U-P_0u-Jc7J{kxai(^)W){|EHXb#xp4?)^!Uw8PLh~E(SmYl1pk;=gk zM_0#Od~kbtwqM)FCY4F)iljK zU5A@Em892zt6Vw62v|=@CHZ+W8UahO&Kwg~_^1fy%({+Po8t{olb|zKKTdK^q1+c} z_S6}m+_&gbB%1P{kU`*OyB! z`YBMds624xrJIOQ_enI9)%&!f^+qCs%J&X_G#Et^8Tfut(B&ul%e$rkrKo{A zD}z?P_1uX{`M>A*HCt&tLVUMS^S*!PCLlacinw*ij-N3|Ilr<8^G6RgeZDK}x9cN1 z9<%L{4R+nyup4hp4d;y1cDDN*#*+*v;Pn#@L;lPA^-iKxkOcFM1k9B0*l89|ymxTl zAVwq`Y9k@=VZd^Yy!$)JYM?Sj4;6%fr%#{S`|W!ZnXldY^dSAS9Gzlkf!=u4B&Bk7 z(PaC%fq!p-8MYA7sNB3Q0w$#qwpT>tW3uh7Lb~l6nNZ#<@=)TEr=zDoEZm#4J3`n& zsn=ym>zJr(VT6c_;D@Xb19>KAD2}sb4pp)M+XtrepB>Zv^ z%QiVaTcyK~-&FR1Aa@hXP}EE z5PD){E-6nNY=GM^WB3N2b}@3!(FjjGu>Cm5;5dpEhp4w{AX7SAdO^+;u&a|68OtJ& zeM*B3cnx27f+)wY3i|yH_4Vhp!#xC%mz;W!KSu~CL&_dFCdgyl{`KgBHI(<5R%!Nc z_oxww-gy>XiNuE$EUA|?|TbKv=l7uD1lVesJ zF5e*Y)Ca!^7gD0DAZieo5M|66vv!(5KE_xU_0a;o1$XyX-~j~k*Aj(M`&~T3@3NW& z4bQF1R^Y7|RMjM|1Vg|Mc@!%^($U>e#ti^}&Y(rlxcek{$GBIo^kMmmJ_%nMsrljW zxr6)1+ulY4EPeyzCeT>~E`;Lcn1D#05^}lbs8_uxTKFZuLCnr&F(9TV)~w^U5u6eR zS4nO_=FbFD7y>~``3Cd#%-6TUkzH?V4$KlMu$}f=dqp1!C9P9yOEU_KJjp6abkK1d z3inW?#l*xi-+uB$tpGuVGP2w3(L_GfZue8FPd?oA~gcr(q7T{9OWh#LpvB$D*xbQr)8Oz;5~3av>`R8Rr?efW-G zPonvEmrh^&=CR~EbBsIaxbJ*^4){YAlszA)2L|=rNa&bsP6|ZweMqpMXL>^$5t?*z zI?&cjujvhTp@!utpL%-wgMqD)yuzlHufncVY`hi^-`SHuG#EO6GV0=55~Wv0!fTAu4he%s)VY+_f=<8E-J*d{RMkg|o?NQz zI`0~$+1Mb9G+Up&o+$}Tehp?%Df6}zvnnoVPC|52WP2p&j-3Z-VC?hdM(G*0^f8f} z?*=waXI%pF(^GtDeb2$yNP;wVN6S)ve?H~2rS~aJnGwx9EXEpw)kpF=jfc>~%Wq3P zJT4DctdME5akVAV<#lGy=10?__JU{yGZls~*z$7PHU;551gv~jAH#xvm^=q$;A76D z0Y6FxVwoZQKED>Mb_z9t`#YdVAh{%w4fP}m0|p)?#Mq(&RCtGw9FiD<+om3P86_a{ zI1GdQM&BQz2TANBC_U-F4Xt)!rWRCN1bM$|TQm~kA`2<=+E?owy?){`sMF(FVTfo2pXyQT>MN$kzeOn^rK|e`&5&>~f zoesT(4|CwB07NWannyfFAK)SdNYxkDST!`MWPu)a!T zAwM;G1IFy&gGXq^7ErM-7IPMnDsjFhNz?{DO2F&OKY7?tQ4Rs&8k|a|S)U>|>Pd3R z$3W`s7>n(8=$jtwRbW2+#l^TImv6F32SJ@fhKeoRP{{BVXGbJK`iDX(6r}}1)8NK{8DgwfsWq!Xi32) z!uq5wQU8an>yGELecSO+MnfSXQX*T)O2#+Ydu6X8du3&Yc2;D|-ehOXsF0EDQD#Lp z*^=>|7kcviKJWY2`}oOy-`6;=^E}SuIId)!eXsv89iDV?#wpTo{~stqk?z%O9LK)j zqzO=hCoz(axc&F}qp(tytm;9j_;(1Z#o&h)o#ZOG`={@nDvV06qregIzrRVt3E}>c zQB^zB{=aGy3ZH7cOjfvm`n+&pqUjFQSndB!49x*}6t?F_*8R_?u|YpHZr)!c!RuMW zPv0~U?Rz{#8Z;?}#fql;|0>=k_|&uA@tpf>dmA_tNN4r13eN2RsA*XKjYlgmRQsP_ zZ46Ix6Ki<1|Az;>3<(1~rMRgs?4K1+Dj0yzd1`6I`}gm|moP0hQ+K}j{GAreQ~2iu z^G8#h_s`1zSCbsTeg?T*h&rSHe}XE`#szp+k0NdI{U2~2?O(j{{{IOTXjfvrqu>8h zyb$SwU;lpoTe;Qrqnz7D@BSTmxu z|A(F!4wMBD`*-Xg!0H$n)#=adodo;e{~ciGDo)EhS^L%s%?MgmZe$&p{j+N039IUm z{fQgAbvxkuO5jwm{jR?sy~T+_ zk!nIfVsrmdLqmchl`wnz!ToRb6a_``w}V`4N)Oq^fiSmNulT^ZTc3;Ex0QNmtX`^>muwa(iAHB*Z-LlRd^|jE-ICSe}5ATM~MlZlzczxKL;gV z5=wO%kCbBXpOan**i?Re4>JBUD!nLF_hqMk-8U%@Q(*R5r`0t7^QoWELe1PtDBAa% zGy$;E({Ma{|1*4eI2d^Tfq+un{m;jdgC7oOmi{OF&#vqj=KUXlA%Y*`Vnu8HcLh?zAK=II?hh(h#t>9&9k&%-_rE{h z5wxn>o)_$ES7706K~VN)$KC&n7-;yz_8&Ub`S+lN|IZCU5KqFj{}cX*B+#-je0PUp z{{Z$X!>9`Uex$j-0KquHS|`ZaN-5kotqia`-}Wb302%7RyKc}mIs9i-8PEs3`y~4wGYpmZ!iO^+^#I-Z3V{Z%I7-Mv7pisr zjjULMZ3c0u41I;5LiGQgnFmcTN$8{a3PDvL2G#u|FKXF;2lkyjEY-E;E39IB!y-gb zA{g}>TDKK~;pKO}Kkj>9()+}I{qAgksoxV@)Z&Cj@mgMyHicI!3KNl=Qm?R?ZAR*k zYn0k1Tl5t*OK{H&R%oHdF+kmmrlQczK@D0zX^9(|>WV;(6J%7+jgy~yzmE)o%?>O6 z=a2qB1&=Uh7$}nY(CGLKO~d||!|P%t>}NiSiik*n=K4EzV+f0e67>D(p$&Z8U0)oc zr#TE{H=D@ur}D#V^WXD<(MdZ&LPce{Vc|39m2zsL#sF&AfyjYSKbe;j;#Nk zh)RUhXvt^)3C(9&;;cQU`i9r_<<7KEbY6eUfH3v6G=}f-QG!vg6yom#0>*Ue#@86U zUQ`#dmOqmEtboyr1Pu4F8)y{r-G4i_g)vX7FB!x5k0yb_A2sgUOn)={ed-E?)Z5#F z36J-FM06f2nqHn*4!T`0K!7H8^o-!?q{teNKH$1Y0i6yS;N0zLinP$Wv)s6lOXfv{ zPXBLIGK)&*5&94Tka(bzX1QaQWsuw;MS273^^rdVj)0~lpm7ycQm6losL-{A)zpvG z|EETqzVH)d%%_h1;G8$?NebdA1gnA@n#ESEzz}}{K(*6VUta99s0Wr*9#%)EjL}O9 z2i}bvxO~|DS{OCdt^IAv$CWwd^4MkM*W%dsZsDcnFN!Xku;PHTD?0)xT`;tiOrGBV zcT?!o!klqW9?tmlqqoGocW0x3QYH(c2R5ONpAYny6OMgcI%4I)f51MgBs(@LpQvPt+zMbMiw6pSxe>U$J(-xC)!ML?HaC)6ckZd(Q?|at^})AfF0@Apk4%JLP6?^B%+c zfC_dQHAO`seC?`xI`B~!;0A!8SdXnM4R>Ko{VsW{_K;`7npOeyTY`h`m#`!+Y!AXZ zLYh2tR>0s_ZJ{G~Ui<6zG0@s&0{fyRJd~S*gQH>0?(c!=Ifvr%rx(n7an17qjz6^k z6OcAu06oxKa7oGxwV_2sMahr-K@c|F4Mr>Q_?s0aSJ=|;aqW_t{9b&dWKAJYEPA<6vi6%YoUWmWH)U>@j?5?2Wv|HQWClg42v~ggH|WQen}Y&$wSErv%Is-zRo}PRn&(al8T?`Rg3! z-7K`^%b-xF%h2S@p8|Gr5XbGt^OH_Tg{x7jGCg>`vqcTbB|^X)pb-{r#4w$MR0X(p zi-CBA4nl=d{|75-Q8RBT8 zVQ=dDx=DRZqtV$GCS&WFn21^tE4lDmuA>+_6|kG0A}W_%v8h(illCX!KqEQ4UUnv> z@i>O&8NA#Jyt=Rc#JmoZ!Tg}+T!70_=+y7(y#5ItYQ$9Ubv$o<-%n!LGw6bRBlNTV z6!o8xkM=|4McnJ_-LzP2f3Za@lq+2{v-*SJd6Bdh27=m?9omtyKa1di3f$WKO{shW z4zKf0Z#s@D5Xy?ULq7yx6)xPeCUZ|5oHh44-%E594;^7Q2R6?RtwB@!sT`pzw2qwm zBI%@0Li6Ui{Zu!rMG7>~S?cjw}D>OkVI_q}OIQimi{^i}0P3=y})r zsNsDUT-`JjZZ!wo(0T3(pjE))3eI)56VyHI$OlMJaAKKHBfT&tHGHbS^fe+|&r|CF z1a3f41~(3UaMdoE_VxGYPB{ZqQR6qV-DHaBM1hmodzIJmZ?5^jkeCHi+_4DzMgdu2 zXXdhDC+N+h+g(EWofn+0vaozZ1R55|txj0G`j9dk$uy|J2sk}AxPa}5(4Ex5I5tMo z-a_-ROGg`6o8`$H1|z+oggXn`!1cRNKBNjiA|N-v zFzFJoj|%ZW0mF-i0Jv}sPVcW&GOj`^ff-bo0cmMzG~J!|io1&^95O0kg*#l35WwC_qKi+x25BMr#uou zD}Gd?%s#y{;|3we-{koW3SU^~!uD!BuVMW0FGr9Vs2E$GfBqq~&r}inXYS6|vPE#H zOAzxp$+{pFr%dX9Mo1S3eBYK&InwBp!QytDz@H2};RT#kAGt>^Kq$xwGlh6ME`3TP z-*6sYW{Xsz3ALla0AuTji(C5;DV%!7=ePJB^ZwS?0V43HByqmm?7d>{lWIRoo+R)F zS%4Vsnxz0NDL+N|GBy&rdssUC_kf3y(7`idFFM$WJWBN6we*$N9LEcWBpoAZcg6!B z8r0HoAKRs8&z|MI5e43vArOKWmOA9MW-pwos)mfwudNE2zt2a#0s{l~x7|l%>IDE=GID1t| zuf#AA77%+$Bk$Iu9?e2%%7OPG%lczpx(RGx(g(tsOzxBCdbJ#yVF}jbQ=M+Rt8@r& zy#93bi7u@L$sjpUdxwlPg|+bT9A12N`l_Q0qBX#5EHhn#CMPKFjNi-}|7ACM-i5aq zwCsJbmj`kamq7b1kNR=tubC{+?JI+;#o6^Akj`N9%>)VJ_*q9Ej$W7Sp^o1vhm*AR zfguj&4|b)FGm)dU(1u2x(if~++`u#nx?nTgf5o&rGeSgMTuT?DSJ288Utqm2>6S!O z#mVl!SMb2zLf048MIKhY(fY6h;!QG`%c+(>qq~k7s_x;62L=Ab@-*m`L?LocI|yCf zIhszKREIRXGe=JkC6Ug#^b&|A4`I5vU;g54Y<$_7SF<2l3<6eV(zICAzvcbI2v~I& zr)(m3K``jkg4C7a`s2fSnU!oOvz2EZX8S+e3cU@+AE!74lbYYd7!Q_M?9i0dZnS#$ z83H^eoB#}luG`ypz~fkP?Kw02xoPZ%L{Y=8!&Ihi=;<*8dYXRgkn)LC&hXZcM zmG+Dq%(4AGK4>Dop0fc9!BQZn0S}NiRJMD0#eO7c>#Fp8m8bv44D@(`1kkZy1eH$+ z9A}7<@E^($f__J5-=6%l7G*F!uHfADX#8bEjOdyA2?|j-(-!+{i_YMPJ*Q?Zs|&p$ z8O9c!sh%ec(gDlDm#5Ib^nBu(U8puzrCgQ;2fjhew)G&C!wW!ed0J_54L{0rr3vna zJdc*>s4UQ2*&s)Y*JE+O`}Yh$$x6RK@1Fso#GmdfmSeJ5p~aDdsd9HF5f-2N%e4FQBehpV$Hqx4={S|M2X9C24cSFgNJ1kg~>TXkhO;X z##@)iq+W0V62@(?iwfm2?Mw?qN8cXHZYL!cLBu*|u$5v>cwJ%auQ=G}MM`YMwZqRVUs4js`ML+TnImm|`0OL-za? z7Ke>9Z(!>IH|nDVr^bM+xWw{A#|JaAOAwD~rg5QaWeH)r@q+k*TsR8|VCc1qECPXM z2oJ)0111cIM8p$KIT~LZw#4WFle^JHA?D&=3OpN3hxWy_Kgh`nk$S%2v%uljHtv{Y zsAExGk4m30wxWL+z(@!;9SHF1739?9P5B&8o*@W5ZVImwWFDkl9tLEO3odYY?_(*d_?y(9K5gLgUr3YB=^w%*%4VJ*(*+D|AML{h$D zn&|rgH(UC5vE90M66$~laCA1Q_`uQiIrruRl^orHU6wDA6*gbtAnrz=5 z&f{lws#rS5GJw8gJK4#oTtUHOHSM4y((!ih7zfz>B4kmdV$rh7y91H?+EebkBitKR z59Opxm!Tgn@v|)KGV0*UiYhQ8P_D3_Uzw}g*4-uCBLEAJ46zlJI3;i1K=~dpLkhl# zel*%CLx2pY-Ypg61IJ`xzxcnWBAyx?M_<1z7EtbDBQVtK_<+6un->gYLck$F5th9H z@Z<%tA$SA=C8)zemF?gfJlYRYT4mtU0@7F&TSFS zC|7+C8!S!20U>Et$phU-15l*sSMR=9l00tKzs$5Yt^wdtlijqlRd8E#Ke+F%%kFG0;1CuP(FJ|!x=jY$y|!J;Cu}+ zB;O>vWO$-R>hqA7z3?he`CiLx;I?Dc~NOgD8)ay`x{UEiBoJYV>{ zYF<0Cz5o7sF86lRNwjlEb-R^w4f7mqKbtLn~7*d7glozg+w2>)votLw2bU(hq#?Vy zx%btQm>xGK&4M&gJN0+6Y?k&ES!%&YFXF(RxeQSJbKcMv7n)#TpgQuG0rgG;Vgv80 zpylpZ(>%ql+TJQ3$4dnsWqFtI5Z(~b{UKVmv3`2|8Yh%pj|~og&KsINS3eh9$BulA z=-7)8OxTFt3fMqoq;i4?{x7Jr&I8LEee{Jm+7btmmn-SU3G6znna(PZO-LC9HvJ2|-G;Ap8MB;(7v_;0uUf8qq>joOuNpVbf5o84SN z`3(&41NEy`Gt6E9c1wbmST>AVH8Xr1kGEUsQX5*$L`3Q!YUs??>FYcpD*;m^-ku_B z4uPc<8<6rKApVh?pLQua$H%9MQ1X_GeSgY%OfQsR1TVAUrkb6J?-fTkm!fP;`O(r@ zKf%oShmSq|v0Kxh-P>GNQ+}YDqst2J4$pTLOg3fJAmye#xKHzhhbp$O?HvV(H)|7D4K{$c;j+!T_fudfDGTBgmPZ7n zw))a(`KcHL@IudE^>7mir;|X%nc`G(5cq1=GU930YCM)-RIExzPkvAYQ#K`}WK*t) zb(v&rI#iJI4?a!6VK2zc8X@YiuiK3P-eS8nuJ{X7HNGt$o}USWnXL!rwMbR*pxdJC z1Z*9S*>{Y1;kfn>tzi^Ul(M?&(3}ba1d8ANj=9HAV55!*35&YIj=nVr@RRRDF;G&1 z^wFlsa|Pz+rQe+CCV8Te-Yt*1@gCvnmQ$M=NmHK4(dLuY#lpR{jSIPmlIMr?ok8Cs zMotfYA~hgI`)-8yonC`b>CDh?VK^}~}6+X!hKO1e z*%%ULeqy>Z;0mVd!?LTurDRx}&jh(I^?X0I8^EFjc@*Q&{o&r!f7+pa}T@Jb7YQ04mgx)l=G z*5QrG3;q%TMH{_Zwzi}SB{V^p_&AExa&*7Vh|*R#LNV*x=I7D|l5ug!TLRLi4t=As z?jST5)@Eghr&XwQbN&n+mIR8Vs+MJNe^dNmyVw7WM?Gp1*AQ+5LLDV@0$h9)kiORz zk1CV1tzRieF{4mnaQ>w+p?cbHz2ojSx**bPEB;{61PLW8s1*DL>^q0Rb)d-YXNI+p z2edr=%?Lvr9#=z2@AqVwuQ|p)3565C<9AgHhsy8fkg#fYqJ;Rx`M8c*Bv!Sh;HEkf z3GnuLofgSM9v~XxFsM6B`zz&H{K(1Z3@gyfB}|!=o{V0Q33AP2zf8iYBm$!|<|5H5 zG_~XdD}=a(EX{shbY>fn1>6dMm1-VrzI93Q&t^(0+YlkyQ9n>!*A0qJ2qb@#NjyY5 z{My=7fLd!d;m9(O0kkN2nLz*bUiGA>qz<4$(GM3QWtY7KAGRUX#m_WptLvHx zr!ppj`2o`BB8Mm<4*p`S%KWGQS$8a!(-_l0x`uVfLggTPbS4b?uUdrNlb>2YLxQux zYJ;*;I9DbeDc#cqpzBk7iW2X<+AzxTfyN&p*K^z%Oo8GUXGc8!$0vrWs@$M#O9_*L z$+?|*Gp!*UQMaLrBeux!KiB4PG;{oL#2+sJhovBY$MyyA+V%GLE_S&j>7mwnK6n8B zqm6Nu-^YKv{UHUNJ?_%BGU&MGx~rl5c;Q?ZN-WZ%amnTLo#i}(e9c3JXFZzUX#1y zvB^%E$cGCoe3rk(CjIdK!?lhwj+HDg(OJ8%de-q7$5?@+ZXwibcaw2TH_uy;$!9nL0 zps*2>PKf#q1tHSYt|{q5fn0apvc-Hdk_u!7i-%wPVP4?Ak-hY4+i0q4AYNhV>~C=F zvyurL`y2zuUL%M-SjBT)sb99Pyr7fzB@28*m1)JMlXvoY7A~*{d5q!l4N|aq8tevW?n=Rb$Ns_;H?Q` zde)$_@taWETwe}?c4_1{Il}RE89qLDn46T0DNX~vvQohGQ`{SlAcNlp*rJ*-*&Uoy zX-?&#&{}E$hep}1jtN1BFY;33`0C5f2yt~_b09gtn=X0TAi?OT3i-a>91SndGn=># zkoXQNhnnYG&s|H%bXFyMJiK$p`$o%p%avjC>lng*OPQRCBrkK~!Nu~xS4mU2hOp`4 zrn}>@)nD8A5lKW>$!#?_gPM<`N`@-$d1*Sng$EzIWN8CWW zfi$GVPqvP7I!vmdoECTKHd9Mm|GKN+*1hYyjX0Wq)I9#Jc3@`jyvJa}5tKCU!W<*I z{X{4ACgE5<N;rbfZB+ zM}y63B-_%lgu-zFj6_Om;l)d_RV655jg{#Ea){bX zzt|7@HLaqbpAILB2 zd$Q=1b&4P{&r|w4QJVIC!I0ZTW(*~W5^Ch?d!f8g53hvYNhc?@LpQ%N?iF5a5VOtq zx+4Y@iY<&PP#H5qFG*td_Jeyd*{_oA(R*;sl^9xe+*Xy!1Q{4o9v?< z%Lp$UM0Lv+kT3stOVFR@oFCTEEV5u+9BWxU{G@pWE{@(2DbIZ2YCH6ekLx*`rhrB7 z#U@iN;ji(|fQR0O{L;!jvqNP<>nnJ&Ir_Zz@?^*1eESQi8znj!;7-J0_d{m)EW-56 zbvSJB`)p|q0)EhvJ5y|M>sAtMUnG)M)^V7;>V8Kg^)#UfoTkrF&-_kt`<&M1R-r37 z_;HU*)5Y8dTz#SS`Z4FnpB-~O6`hyw9 z;rtr+>`+UB-S?@}zrL#53s6KS7(+@dw&*~>7ws+QBd8CTvn0-cUKWasYb&ISib`uM z?h#rar|mH!kKJDTeyr&@&Q4i?gXM0M)gkDTz0K*oVA$p`fr8gCq+}t`0|{qa1}(UE zw!uijH_IhC5s`<1!QS591nNQjdYY{hW}t>6%Kd#|RZP!q{t+@7Oz8k0X3Ms~mf%*R zHNXUXmn->uJSg~`a>wicl}UHL+b zjk<+AP*hOIC^2jO#|FBNqh}TgZb3svTs*V>cGf4Syt`}iwV<0T&=+LO3pQ10@nld& zjE~LtE+4oODVLF>P4UpZa@bj3BX~|Pxo?OMg7%jCO4#8qR|a)YwGn_ZlwHaM%chQE zbe)2STB{P2$tcEGSx*E_P4V5()N4t2W-aTfEPNd!eq|HLX<)Z3%Ue|A6gfAUF;@p_HsIQX@VZ>GYF@lE*3-aef|O zzo*sH-O5E{fAg+v+2nPpp5^QIoB_p8zOUOT^o-h=wM{$$6GO9%t)0V>tyrNJ4_+Mi)wUMOeAI! z@!-~wO`USiWG{9gcn@~3O(i4B@&a_Ia%E?qD>l~w8jL*^O-tYTbP=2fS4%9F7taf+M($Hugd+m_Sny%H_oqnC=e2`0CGLw2SZ z4w%mAfXQ@FlKGvB*!cM4J(2gCOGBY&)&K!Q`#R8*M6n@@A=#{`D@3Lv_9VVR-do!3 zvGS^;V97@0-V3Ha;9pq}W{JLiz(djkIUD6T)A`@`RJXTKP6U9{mZ4q{@eG{}oM}za z+8$s^?qCK?w~;k8{D|xU^LH;k)0{}G-4%|>ozVZQQ8;@Jc{3Skdee&gpJFxZ&5fVO zT-#3FfNkUWQdd;`)8R9M{34pvmCYv5M*v0h$0L{_f*uj+k`Sou8o&^bZawbW8O_OC zv#Qn&E^Ke8r#Nrb;59vJHdyW3oC9TU1H!^HQsl%<3b}(PFrY9|8iw+{Ze2d+$rK&| zmE^T+)oR#?z5-4tO*6K9WoqKT_>#w~n%6H+KoOh51P781N{M#x(8ase%ebLJ+Z)QA zUl>JG^?h{4E){(OeS0pa|3J&or{g6~^9gxd$}%#(TFF5R*wOxGJq|(+6t_0lE1@4T z4;uJ9#D)Rf)TW$!PiDib2xI|bS3f?)Iz4(4IbR`kD!fiKHI*Dtx4v5+!74utoTO?C z70BK|sEh^Q8(y}$Lu2^k!Iz=X4tUOY~CR5cmK1T_X;>D+rhu^zY%T%*~v4z8=|oL2q4mhR$N zu5fC~bSzv+m+f5E^FnSFkYoR}9`=Z>g!~{K=wOVq6udUWp7ZU|y6?5xYI3saZa{Tx z{bWz2QGFZ^)YEOUDoCCHxpmK@GI2i&I`+!71g-DjOn$u$H&VxkKG~k?xqfK+kZfQ} z5!+EC($lVUoyXHhSJMxnM99|sI&}1WM-sFy*6?T(XRhnJ!Fi{vl{s~O!bLJB8L}ft zo`hR+6N?;N$XnX1St+?fkCVQ$7Pu(xpnZ<{<$Bez?}SHfwu=PioJ2i zX2@!#r^mI5sjvo1Tt?DPQwh;k-yL<_B9aIa$|0HF@-=PjM9C7o#N>0W^^M4NTM_WV zluayI5(A`^LoCHrE39=aWWHn=hz79Er}&=9y^NIc_+);r|Mf=M?Wfvhxh-JxbPk8( zc7=}A4Yw=D#n-n3AdPAQ|E_+kq{QD2n-`+RK5Io>ym^28@G(UDINCOsb&^%{6g$I2 z*-buS9>-{5APhkwoWMS!xSOimWB`{sb>;LjYAv5;fZm#r1n@(ApK$USm$AK@{w1Ws zXZa}m@~|c>q0!|m?Vj%&zns4n&o$ha{lVqC;oPE7S`_HH4l{S4p-^@mZkQ7yV-rm^ zhUQH{lz^)$!qC8}&G?Nn{)7ZZR^9m|)wN|fxLqGp6=wPLy87QUR~Zu|*Naa{{BrGf z7Ov9J3k`y*wjmee1BvUKMbI)SzB;*nsmxy{w<+Yh_(;p~IoxuJ{-HzI>DwL@GB25J@Z04Y|F;{hg|o;I;U zpV({w?BjBsBxn*Q*bP0Ap4jV7nan~+8c2yO;BW#}d6M-|Wr|MO)}w6V;gJOE{He~! zY`P3Ht_am87e3*h?`swwSXa--Ap#`dmxkAfb`!o*f0=sR5_#3E4s9xpHqeP4TH+kQ zh+An@i0JdR9>mglV2%2*T+Vf+D9k%-M@h^? z@Halu82S)Mqr54ArDk5gmN_Ld!Ej-7n}!vdrW}G(co$eB>)S^{vX4z_z-G;i-^EcCYpNx4r`=a`+1d%g!pMAQ|8!a z%jT3a*7lQq-A!Ta@>`Fn>{IA(81(#;rd^tE@uff#l}grx_Q7J1_{x45PrK%RRkbJ3 z#;g?VXJiwHn8Mg-2`70R%!1O2eLSg7DDYL>hV)w7Y`h_dsTL(oyu?DtqL z4+J&!W=NO}Pb*^)cxqdD_p!za$%BV5EhNsDZ^)(&b);8kz9>z3fFF*NDYiUy?WJ19 zd7f;lOH}f}Pbohi2cC`0&Tx5x3~Bd}xqvva*$Z?f${l4}LCE5e*k1x{TE2bqKo&FW zOA~kcvd=87UZbjz-aYrL(;>P=eX;9AV`dZXIrXg@Ze~gx|Hq^y!8&EClO#rzY}n7+ zd*SdQ`3#D9Gg>d&mN->{sgySOow;xtS}I2wvco83vQx%O~3aP02*4VQ66$xbny>rc5RD zmaS!1KBD|6jLr0GJ<{{bMMLTSTTOXt?Z>a7%z4_Vek;qmdKFsPCb9JD4)YT=B(fY6 zDh{fmLCRp9QS@c>Y53OFxMM2X(#y7^qd{fI${w#xE1(gv5AJ|QPd`o{;9aXkt(M|M z+(`8?AYc3@;%X|%ncgOQhpU--rWwJa!_X)VhB~VD*7K)wXL-yz8K5ste6n?-_wf-* zBR-p^yA`7@A8-EIP+-*BQ9y0%N5R$K{jhyv$-etZZ=fvrgm84zEXfF(zJgeG$KVKq zycdA}O@M6vYd$uN%)I<3*_aUPf>&7|u1`<`5G8S8a1d_`aGeq0a`15F0vRZU=dkP{ zTp9q8f7QddTyhLE9Y}ynKFO8a=(ZbIgcgC+kkAl{fN6xu^N}WJlLv$+(59l28}lnjVGTI`82C6Ek3PZ)rgC}9 z;~){jQ%o|moiK3=xeJfiTa}Y#A?%;^Rr;~YWh`DgXKW}3Uuz$-==)M>yS(5vqQm*I zCI341BpjhHfXmmhE}y;Kl2BDH05-aJl>K>3+iN7wJHHgv@DM`RONx5js|D~`zQ?E> zTDS(+H}=}kw1A6T$?r?!1O#!I1&eB4C0qN70Z9jf2d`wj@8kakN!sf>R=HX-FeUj%WQ#PlF+J%b4#(7lLER(=c@p6I36*?%E(Z~fYt zAXx$}fRY>A@h+=P;a4-D__j&G zfi;h)X@(gyaErsu8m?bUfUwrl#c>4|fMXLP7fqb*sRmM&XsT&<6|+hj4df4Z2bzs{ zk(ASjh@7V*UW*ENV|UE5%%8ZpR9qP*&rMsLnH$*lfqO5miarK ze$;11ZBAuudH|176fb@p{E#*;Dt7 z3o;Q4VV;Ra^v=Zb7M2zzxX1Z36otm&Gw1OTnGYZIX&MQlXQcefs2 zZG!%xh(|YawKI91{VR#qmWy$(D^3%Ia74Sg4o7q>(_y#W6)eczxn_wLstJ$DoF)MJd`$3$?3CaR5pGg!rx{` zgO`wrm%mtw#~ic zVC(W>QeE#uceV~Q?AyxmCC}%All_5t$mi6ezogAiyyroIOJ2b;sx$wO;$ z69-XU`4-;3X3?wEwx2v9Wr7FNHWA=snwa^@$=X3O_wt+EQ4?2GRwd#?i~9xitLV$G zl(jBHd&7uNucxa$$x@h5^QBzDwQ8;Vn4W3pZ_h4RC|u7NHpJSbKxSwCk#X!-P7Ann zveqFqzO_vl`eNKV3(#&#=ve$*IxfNbYMC1_Dp3I4RH|Q9B8R}5pim@}fb-zgPrkKp zkIC3|Np!@ed#*UJ!a;XJ_Lf2vW1KS6^HZ13y=@%(7@@r6DxG@D1Mn$P;)*>Q`MVp4 z!?nUcgNhN0bNXBYl3v)jBI0#m@Y0(UszRHL4J^h0xR_Wc)_@PXUm? zfkv_PUT4EYvPUFxYT$lIuU*zZu|e!{<^r2gOj(h&I&=aqW1xA6Z6yu{kkb4*GRa=oh*oBzJFN zQiD1fEA5jW3Hq+VQ8Ehok+h;R;$J~9&wo<~D#H=T!wdV3$KrOseQWEtHCP6QA(Q75 ztTw~dSja1H!YNuzCY3mmW|-XzpjnE<)BHKx&=b~@!=G^0zE})y;kyRD1VB~~1rxn~ zl2v1jxbH+uGr+&nU^D2OK51W*LySV#InaO9 zp}(h3cZwv@pV#qW8+QjMO*n~;OXPbBPWLST;3pJP<`?Z%}*Iu*JckHa4piKh%D~BdVdk9^O5S%YL6X#a#^wisCVz@Tp zbU4q%)X17i`^`a0y@kulAt{(XO`W#U&u14>|5yHq>c?^dB$6W_Wir$ZOGF;0u=SM- z9gez3`^$(+*2vv4;(O|ug^OtO;GuQ*Rbu7DG`Zc?>a&!5UHY)y^n{fAKVivY%+9qhdil!Lf@74+Rki4{D;P}bVE}g`wPY8e z#_`x(4%6~I0-oBa57cx#3a)(1Jv~1$^*eRM1=J*$@15~^_Uul%45aZU<s5Av~aOH5IT$X4j_ECT4bz zbQX3YU$iT3Yq?reh)T3E+tlMlNw|xAodpX4riWL%C&7@TS0PD_5v zaC*0p6x$8Mc^n8-wTO(gL{)nNW&&uZv`(zrQwa7XC<}gi$7qJzql_SnMb7;HW!1wCF{R=x#Eaf~xFESf@2lh*12tsdVg;2-|sEO{v)L9%y+)JwD; z4&jY=-h^Dz_EmbNK$`XANqcSJl`BjwNxAs?AH1`ml^0`47-ng$%r@z^R)$xm+ytrh zD1f8f8AE{bf1m0MvqWX+$g7-64xM};9V4As#5c#ICigXZHWyexAbCP3Jo-K~Y?o?r zsBZuAm>D2^bHiZk!@OSV%V4!t?bP2?bRm)^jdYJ*L@KF>(LTnD(0$s^=*QVfRaAk?IX@Dd&}U4`4cxOr#Qdu}Xvg z(PzhI-4Dp4M?#>D$t1h%zd%5qm~FQ4GK7aLbG3znywQ+nGAoYJ)3U1tcef04E} zmjOG{PfGA))iR3_NsMm z80djUrmC8nkKJ!1xsL75^TXX}$d`g7yO}5A@juXjYE@g3EyzieJTkTXn?&bxm zxeg>_G93q4e>%$U(|qR#RfY!-R(x1NjmJ&Zk%JW9-Owp5o&eTb5kP2bGh$S`_@X$F##ev_rO7`aGJM!P&+*8VG=ulSyT-+G{o zOPa9jShGl*pBx$`xXO{a|J`ifoLYe7R9{V4FG(((HpS@TnR{fqv;oFg$$nQsek})lxy?;QJP!^q3_oYsen%xb)$4(9rdR zKiqqCU9*rPJ7&d%`?Ve)cZLLzWh(-4CWN%| zL`@mwgf{K9fYE;=P2p{D<70ctJmIe{*_0Ion7XiwNetfBuZ^rw$(yao^RaS!%e7_I zdc$>LQ8RIj7*~hO=OPOaeZi@_Kz0zoK?O7rp$3%Yaj~6`x0ZRXll!tt&7_mW&Wpwh zt)Et6QXAl3(&87~5_lsQr%8O55WHZJStQRv2r;t-Q%p z+cLjGp>z9_iJG@CZtO<8$;s|3LC#Uom{50daS2ssQjfJS3uMKIm&X z1D6PYt+Y0n`W8F2eQ7-t$g+B&vOtNfnj1bhlN7NWS>X!T3H?f0{%A|1yT|l7=v9B{ z+#cg1i9lo_f|>DNXiojO!w|PfH+6mgTz2{F!oZWppLilh3x>Kay>ng?0d$A zB_l7S^OtB}P%H!#ZbOdUXq&BG4B_}p{^H3MuWh)*^4AJ&zL@;YSnu!2;TXdT(xJI5 zxV8DWROc(TmYFjVS>MW|rEnIQpCP#D4V)L` zZL!yWi5M{%J)C&Wa^WFljqB^82Zu+NRErL&=mP{yj@UKYYMZhzm7g8XUVI}zw2D}& zb6T`sO&>R(9HIPCerz|?;60SZ5E|@>gC#Pm0e-){ZAV&hg;?WzUB~14FY@GpiZfP2 zP)OY#uM?u{$A)8kMcdW=n24D0p-O|mh!f=KDj+eC#S6H%u8u*DOHgqP>dyufFl-)k zYm0qZ??U_N-lyvh)j&>KU-^!%c2`LqDPcTEq~Y4U>dKt&|5zL&l-d>>tC%R}T%_!U zxrVcJ^~(At>2F>z=)8ZLJAKaYV`lTykNm4MPYx2!^ybm(%_tJFaeU`$y0iT2q=xh* zy$^(wFV9W2-JUR5`t5m5&UeewkCj-(N2C$St|jtlR;1XeC_wH0XMH z^_cSTm*UGRyEN~g+t^9NJ{zQ%9n4cA+p}A^WHRGbeiSE12cuo|1xp2jm-Q^f%9U;* za2aX?*b2j1no=zwRZOQP`safm z>&y0cIOz;rkxI;_&Ch$!(I)F9(I^mk)ywh?iGEpj6-$493tdmb!V&cTMwV{H7f^Ch zl}C)>kw^@KcmBfW=5M%q>MgK|l;aF8EHYOP>C4aVT_K9j+6jt~!KSD&^k?JY0h1mMJZzq^ri3{E*r zJx;-oI{3%2qe6Pnn0|HSj9~w=A<(wj)=0=T#&uW6+up;CCnWj0?foLynqjvA@s4Q* zK3SBG^JqxS`g@IdO3PpP0plrO;F6k!&Lz;lYeC+)utZ%IP3oyM%px%g7s}*=Mf3ZP zBsfI|&zZLKFRRc5kYV9klbU!Rv#C2|eRpnf2K#*=`RS8Io)}&J-qoM@(?eB5?$1q$ zu30=wnzNn4O#HA7Zv@eE7Bo6ymb*F+9XZ`r=D)6C20h;LhV0lY%R1(|pm1o(dY)MI z>y|WF&rSo^I1j0&Rmq->t-D_9Spz^*V?D9(?YYakGS>*D)^Ip;$00>)Y5)1g?J!hrW z{jZJXS9!sF)@MZP?lMy6Ky~&r)-hF)b1Q<+Awvh;^kY7m80L!M9ZFA&Hp{W1Fs;d` zlwZD4W^c-KS@JT=QnKPJm(JDKMbJ^6as=($SUNLkWC{SiDlwQ?4iD|Vl6hl%pcKgGo3A3n|7%9Bei*)m4?l)ZrXOu|2w00kj&s8ND= z`@0`gEbA=F!xLZ3a|(d~FgkVWrc(#_Q_K95@vTX3Yk|xaIv3wxIa6U{x%;bt%lTzW zffr0I%_ly}k}Yjhx&ILHxktTpHxav|E#dQAU~sV2N{~^Zc(-U%zChWT=R1iO-a|#t z11hI-C@fJ;@BOqI5((|Hi^;cr*vr0d!`0kfaJR~&WIRa~d(L~hILtGp9L8D+3q^g= z^n!QX!u&SlB8CBT@b%X2LI6jk z>?>QioU0dPT$$i7JIl3AqY#e0K4=Eb?XiF(6r4Yg)VMkxHhE;kW12Dx#9|W^w&6Bx z`Iwgrd9pd6T8VaN<%DcCJ&Sy6*v}5iG7cCS zW))~V48#3OcRUW&eroL6_JT`Ag;(!2KUSJFY(CvN^bX||S*#NjcDI}4c1GkY5hPds zQzFbLxjM)E6SzU88tfFM)Ea3$xMu(b`(bsy8$hi3m8)G>9p4|}=>;|#|KVSfI%8Mx zNWD%BYaW`kC7GzJNnuwKPc%<3b&R(<@XEyKYgD}^|Hn6Wr#I}L;&48A%U)dx2=S2T z##ytvvjWoqOj<(XPz1MVtfsvck;>72Z6v!|9Hq3BtfcYADUYzEcC{4UO%)UK$s*J# zJm3vAkCpZh%wv6=YD3@qC4^!%2(mQ&Cy zX)4PwGJNlO(0+yUpX-<7!H+^OJat4J&j|;L%^&4Qhk>ha3GUs?)AFKgxF?Pjl|UP4 z8j8@P9*2|*4&Cz-P3BvXE(|9QRN|cceU0(ucc1$jeA)Rz3cI~p1~U{LzmO&i?JZ3a znzk}bp6P4hcGAcQ4Ce9|booGwY8DoU>xu0#xTf?9ZZs<9Rd5f-)sL#pAB$%1+`;YXAfF0hc)NpDzZH;E!@LB(ZG<WaLzQ)38r12H@`1UYsC-uT&ga8mP5!$4kU2?XevK}N0# zpcu@hr=D}e1`bl}9ECj4gSfKJBysMU0l>p(LU7?Z3tg#myU#go2bWmusr53{a%Q{VGl22K2E8siDMaP;ft2dlKo{n;jvNzs2&JZ~ z6y7oC0&jumw<)|(j2!C6gJ9`vdg{M^ZxUQkG^9J$PO$G5Tv)`d5;n~bz1g{F2}{hq ze$YPW=eS3l^AAg0ur~mV1#laS`hTJ)LjNYByo31ESTH@x`4zx&xV!_2wPi$*;6)y;)# z!_HoRymm14+v;}*8yq-Zjlp7Nk#juUz&{VYXwohqE%68dAj#_X9dv~_iC=+9?K z*A^SMP|LsPd|(7nQ0A-Qz$hxWT*=@@l6xSItH(#!o3<>UR&(L_^=L+vz-MG1W@ z>l|x{U9KQsb1PPKcEVw++OSpj7O6sFmM?%W7+1-5B0!SyLM~htVg98co$%v_ySj{P zf}2aqMy)mPaYmNm+@9`KmM;Vh+*wnl*h&W)q7kMiN&b~$VrYP)o0duaX3wU;>pja) zaH7(HeA)t-U@@U2%&H%=;sZ@C-EE;v<4wXw0(l+x<*v%HR<3rFJ35zljH#nG-3AiX{uo*ruy^%1+%4FUN8EC7O^wehCA zOCl-5v%9fX;ya2gcyKYDA^6|q0|M<_q!`HWg*G!RrDk@WTd*!?K&wi-th>N=$XFN@ zq4*3(V%z6`g-}|Ryrl-F0*nq7Jyvt&Js`KZw|x3&p?8w$-^a?pR*xXz-=nvB(csHO z^K~I$s=QkmLp{VcKLRO&ec zWy2@I-xe>yGBBqO3=?H1WEr364THM)wKRK0=c@Jb?iBuwo+l^&tool2;c>Sq+JyIF zfU16L+%<0CXAEtD=TMS5k@gG|g36s+ z-wH5NXY}bG;7pdx9ke{UQ1`y^Q7!cciklF2aNPf9 zd`F~xjMTIA+GF}{Z1|6_#b~%WP^r{%s(V3PszcK=8M=`yv_H=Xg*S<)RNlg14}UO`zb zx+eHf`w(p~dZW89X&H&eu%lqZXvyiAm>juzqDg+$yGm@+K$u$U5xnAv_Ge4 zh#aAqxIPX-W#e%pVN6JL!)HpOSMPaz*xXPiyw-Bxy7>!He{1pX8Pv!@X*0&V3s(BV z$QY0h4U(ck$cjej83LVb<%1JKSl$1zNel>OB3f9En1@WH!)s+MD9c!Zb2hMCyAR&M zup1uk5ie9O(*}Y*Zps9Sn}|qnE_fueSBj*rv8&2&dY;^Db+5DDps^ck6qn;3&O#-N zxYd@U8VxJJmRLdM27e`dpFOHcN@a1~*OYz@?Z7>)lchvPy}zcVvyO=G8GvPW2UKU1 zK3qwuh3l`j7sVO~4+FkGLjoT!S8gx75^)jB?*mPg4@tElw*ohPm6kbHfXf8kzlxQjofuR-clmO^cQn1J;KA_dy4kzKFqzTp~TAU*ew43uh@^v3TOXfxZZixVb?)!`D1 zpl@j-dXS^6vbM8^i?p<=g1^(uSF91c2$jSJh!ff*hJMbDnH;pT=JD)rkZ<%zSljd(TjfOl<7gx6sn%03vMT3 z;uNVJCSg9M5dFB=HYt;Rhj>pr1sF-J^+*=yt6^CWwq@CnHJ zwTmAKPpsg98RLO1KGz_+)xs9OK=G+bQqk1|E3j@LM8sw!H(6+YlpeO|kfk=buV|BF zaxa{rS7_*M0Uz2i_GB4(LyPGR&^d71TWeP6aVsqRIT1Caf&Y!(4|e!S&a=bfmKhnh z6wn>`VT%`cnQY$Am~M(uYkKs_OGLK|Y)=zmMYd<3NMM^WeG>pbH_Y5lzh`Quaf)@L zbLK(RNwUC|JP~A-`4-W118j>|_5115r^7>5qY40Chj03<1flj#yEMt5P*U!9yrpVz zZBf&z*`+# z+X}ADveCt%IF$KDYcLRt4}{vI(Em~$ngSDA(0;B^q}uyC#&}ndFb&7sxn5QjV8Bt{ zFG9$1i1Tvo*ol`)DM$MyKRuqFhkB%5b0_pW@4kN-dAPwsEg^~@YDQ}VkB#3M?;oUc zGrxB;SP=Z!?U#3}4CFUQ(gcfoFl`@dO|HsbFh6O#O;D$0Lw|rz#^WK1n9p4@W4U_7 zGr)zet^L?%Y4#z6RZR%tA$1ihJ-l^X^PBP>Xi5 zHfK7Upf6s8OOP(Oh{v^lFB zKBHq*3)-|V@=st-wvll08mpwTuC6YRS9FEuY}p99b0Z1}ar~wqdxDYU@DWH}pKiA@ z_li!Zj;0!G&^`V>t(6z0fbW=xYYbcjMj`UuvRtK?gBoprzD?rp zw{x~co$}T%h4ULi6L}*jh5>z79s7M3>?H&AxG|p$mKaon)gPwc6sgi1&(q%iaP}+^ zB8l>>e&MFfQ;SQw=FI|6ECEt>$?hta`Q-&c9MlCa@xyu@qBypORatXV8tsHe50rVB zJ&CIR*wvPa`Xs$D+j|uC@1+?$lj|YSgzV3!L%I{V+sWC@tj4WK^YRF8QM|-(%p<{< z%Ui=W+&-zP?%$Y|Fs*q8Gm#X&|Lo@(>SlH=_iJdSSNJBJL#TNt zNbOkw?>NWjCGxHe*SPd>bwA>Tjprq`a%e?7Zvshs6+Lt)Fa(US_vj+|LmKG5C@_eM zWCsrvq7jJgQWnRLcdAvsuzIxHj{X4=WoLom7?GE}mCPEfZm#kkDbYzdR!%G(Ct;7q zfj!Nhyc~nJ)5~17A+}B5fZ71JOiyD(BZ)+LjRYh_O}_H6Uxv@^l*x|+R2FMis30br zYRdo#vmx+_Tg5+a8tRdXALy%?x}Y@ zBvYD0;I;cFagqP>0YK_hy{NQuC@CdiJeo-_#T4ZVzy%yDLB1@Q6%P2<=!upQBr%`RPF+#HYdT!oOeEl~ZThuoG^wQL`v^$9!C2y|d?PQ07+ z`P-tK=(Pkgwf4Gdn^<08<*=BTRFZ}18t0|IL9cm`JAwBH5yy+4`#5K-$gC9e;UAGExgftISvqN*=SU5Ic=vpDy0UYqB{b^XTD!qAuBvX{FBtSkk&=K8R(st; zBI~qY#x!#$v_p1HT$D0V%l7+c;kWDBFuR=1P>AEF-BKWRF(*U$eI-LpJ86jagRo1_ zyG#4VXARl!BVVHWyozYo%_SlELnmGWhcR~TImH6PwvtT2Wwsq9+O4@;sKF-rnPBR7 zmqo2z^7b7f)s#}RR71Rfb|UZ3*Kopqm1z*HQOC|!?7oc`C}I_ z#x@YhE9U7s-%xlrg`|rer5YgXUw zFekJt~he~18mBNC=)J5SYB5Pd-@2Cm7euJhwWSi!An_E(c2-&2wlRS$r~Gs0`z zw)t5M%Pd8=+3t~erhat~t4;_OeDd;<`ppO0&aB`*ZvqOsja*Dg1}@NI*@@!pEWcX7 zK%DZ)pPc#capoi13~DV!uINfR`bU>O$u+mLs~#lsZqV1yKztIgzP8JF$wI(lxyHUP%T8-Zo zMB4KLc13twb?<}_$;Fm63bki_yq%C08{rVHd}+E6c*ouq-;PIS#*1)A-BFB8ACDe| z7J-o-vUx;^l!k`h;H2LW?=Ag`>f>S77clJ5 zW}pHq75z9*P`wikmp&iG@t1X(OX3`7?uzavmj(%=zxV?R!Q%E7cRHQF{LjMIQ8bYX zSVmm4{%(Ay|GqB9e4HW6dCN1#u%?e2BwDuMC5~%wCu+KSy%m}L7e9DDso%-v>d*Lx zWee7Ij?|qUpJ{T|iH`ASpER~YNGnMsoj+cc`S%r%uaM!4`dGBg#@JQDu7Q8pFAI76 zFH=9;&t~BK^$Vnh!DyU|D_@C5bbRrH|8H6Xll-4Bt=FrWeoB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/background.md b/docs/src/background.md new file mode 100644 index 0000000..a93f14b --- /dev/null +++ b/docs/src/background.md @@ -0,0 +1,63 @@ +# Background Knowledge + +## Tensors and Tensor Networks +Tensor networks serve as a fundamental tool for modeling and analyzing correlated systems. This section reviews the fundamental concepts of tensor +networks. + +A tensor is a mathematical object that generalizes scalars, vectors, and matrices. It can have multiple dimensions and is used to represent data in various mathematical and physical contexts. It is formally defined as follows: + +*Definition* (Tensor): A tensor $T$ associated to a set of discrete variables $V$ is defined as a function that maps each possible instantiation of the variables in its scope $\mathcal{D}_V = \prod_{v\in V} \mathcal{D}_{v}$ to an element in the set $\mathcal{E}$, given by +```math +T_{V}: \prod_{v \in V} \mathcal{D}_{v} \rightarrow \mathcal{E}. +``` +Within the context of probabilistic modeling, the elements in $\mathcal{E}$ are non-negative real numbers, while in other scenarios, they can be of generic types. The diagrammatic representation of a tensor is given by a node with the variables $V$ as labels on its edges, as shown below: + +```@raw html + +``` + +*Definition* (Tensor Network): A tensor network is a mathematical framework for defining multilinear maps, which can be represented by a triple $\mathcal{N} = (\Lambda, \mathcal{T}, V_0)$, where: +* $\Lambda$ is the set of variables present in the network $\mathcal{N}$. +* $\mathcal{T} = \{ T_{V_k} \}_{k=1}^{K}$ is the set of input tensors, where each tensor $T_{V_k}$ is associated with the labels $V_k$. +* $V_0$ specifies the labels of the output tensor. + +Specifically, each tensor $T_{V_k} \in \mathcal{T}$ is labeled by a set of variables $V_k \subseteq \Lambda$, where the cardinality $|V_k|$ equals the rank of $T_{V_k}$. The multilinear map, or the **contraction**, applied to this triple is defined as +```math +T_{V_0} = \texttt{contract}(\Lambda, \mathcal{T}, V_0) \overset{\mathrm{def}}{=} \sum_{m \in \mathcal{D}_{\Lambda\setminus V_0}} \prod_{T_V \in \mathcal{T}} T_{V|M=m}, +``` +where $M = \Lambda \setminus V_0$. $T_{V|M=m}$ denotes a slicing of the tensor $T_{V}$ with the variables $M$ fixed to the values $m$. The summation runs over all possible configurations of the variables in $M$. + +For instance, matrix multiplication can be described as the contraction of a tensor network given by +```math +(AB)_{\{i, k\}} = \texttt{contract}\left(\{i,j,k\}, \{A_{\{i, j\}}, B_{\{j, k\}}\}, \{i, k\}\right), +``` +where matrices $A$ and $B$ are input tensors containing the variable sets $\{i, j\}, \{j, k\}$, respectively, which are subsets of $\Lambda = \{i, j, k\}$. The output tensor is comprised of variables $\{i, k\}$ and the summation runs over variables $\Lambda \setminus \{i, k\} = \{j\}$. The contraction corresponds to +```math +(A B)_{\{i, k\}} = \sum_j A_{\{i,j\}}B_{\{j, k\}}. +``` + +Diagrammatically, a tensor network can be represented as an *open hypergraph*, where each tensor is mapped to a vertex and each variable is mapped to a hyperedge. Two vertices are connected by the same hyperedge if and only if they share a common variable. The diagrammatic representation of the matrix multiplication is given as follows: + +```@raw html + +``` + +Here, we use different colors to denote different hyperedges. Hyperedges for $i$ and $k$ are left open to denote variables of the output tensor. A slightly more complex example of this is the star contraction: +```math +\texttt{contract}(\{i,j,k,l\}, \{A_{\{i, l\}}, B_{\{j, l\}}, C_{\{k, l\}}\}, \{i,j,k\}) \\ += \sum_{l}A_{\{i,l\}} B_{\{j,l\}} C_{\{k,l\}}. +``` +Note that the variable $l$ is shared by all three tensors, making regular edges, which by definition connect two nodes, insufficient for its representation. This motivates the need for hyperedges, which can connect a single variable to any number of nodes. The hypergraph representation is given as: + +```@raw html + +``` + +## Einsum notation +The einsum notation is a compact way to specify tensor contractions with a string. In this notation, an index (subscripts) is represented by a char, and the tensors are represented by the indices. The input tensors and the output tensor are separated by an arrow `->` and input tensors are separated by comma `,`. For example, the matrix multiplication $\left(\{i,j,k\}, \{A_{\{i, j\}}, B_{\{j, k\}}\}, \{i, k\}\right)$ can be concisely written as `"ij,jk->ik"`. A general contraction can be defined with pseudocode as follows: +``` +Let A, B, C, ... be input tensors, O be the output tensor +for indices in domain_of_unique_indices(einsum_notation) + O[indices in O] += A[indices in A] * B[indices in B] * ... +end +``` \ No newline at end of file diff --git a/docs/src/basic.md b/docs/src/basic.md new file mode 100644 index 0000000..d678b4e --- /dev/null +++ b/docs/src/basic.md @@ -0,0 +1,61 @@ +# Basic Usage + +In the following example, we demonstrate the einsum notation for basic tensor operations. + +## Einsum notation +To specify the operation, the user can either use the [`@ein_str`](@ref)-string literal or the [`EinCode`](@ref) object. +For example, both the following code snippets define the matrix multiplication operation: +```@repl intro +using OMEinsum +code1 = ein"ij,jk -> ik" # the string literal +ixs = [[1, 2], [2, 3]] # the input indices +iy = [1, 3] # the output indices +EinCode(ixs, iy) # the EinCode object (equivalent to the string literal) +``` + +## Examples +We first define the tensors and then demonstrate the einsum notation for various tensor operations. +```@repl tensor +using OMEinsum +s = fill(1) # scalar +w, v = [1, 2], [4, 5]; # vectors +A, B = [1 2; 3 4], [5 6; 7 8]; # matrices +T1, T2 = reshape(1:8, 2, 2, 2), reshape(9:16, 2, 2, 2); # 3D tensor +``` +### Unary examples +```@repl tensor +ein"i->"(w) # sum of the elements of a vector. +ein"ij->i"(A) # sum of the rows of a matrix. +ein"ii->"(A) # sum of the diagonal elements of a matrix, i.e., the trace. +ein"ij->"(A) # sum of the elements of a matrix. +ein"i->ii"(w) # create a diagonal matrix. +ein"i->ij"(w; size_info=Dict('j'=>2)) # repeat a vector to form a matrix. +ein"ijk->ikj"(T1) # permute the dimensions of a tensor. +``` + +### Binary examples +```@repl tensor +ein"ij, jk -> ik"(A, B) # matrix multiplication. +ein"ijb,jkb->ikb"(T1, T2) # batch matrix multiplication. +ein"ij,ij->ij"(A, B) # element-wise multiplication. +ein"ij,ij->"(A, B) # sum of the element-wise multiplication. +ein"ij,->ij"(A, s) # element-wise multiplication by a scalar. +``` + +### Nary examples +```@repl tensor +optein"ai,aj,ak->ijk"(A, A, B) # star contraction. +optein"ia,ajb,bkc,cld,dm->ijklm"(A, T1, T2, T1, A) # tensor train contraction. +``` + +## Application: Trace under cyclic permutation +!!! note "Example: Trace under cyclic permutation" + Consider 3 matrices $A, B, C$ and the cyclic permutation of the trace $\text{Tr}(ABC)$. The trace of a product of matrices is invariant under cyclic permutations, i.e., $\text{Tr}(ABC) = \text{Tr}(CAB) = \text{Tr}(BCA)$. This can be verified using the einsum diagram. + + ![](assets/perm.svg) + + ```@repl tensor + A, B, C = (randn(2, 2) for i=1:3) + optein"ij,jk,ik->"(A, B, C) ≈ optein"jk,ik,ij->"(B, C, A) + optein"ij,jk,ik->"(A, B, C) ≈ optein"ik,ij,jk->"(C, A, B) + ``` \ No newline at end of file diff --git a/docs/src/extending.md b/docs/src/extending.md deleted file mode 100644 index 24a859d..0000000 --- a/docs/src/extending.md +++ /dev/null @@ -1,48 +0,0 @@ -# Extending OMEinsum - -Adding a new subtype of `EinRule` is bothersome - the list of rules -that's considered needs to be fix and thus one has to change the code before -`using` OMEinsum. A limitation due to liberal use of `generated` functions. -If a useful rule is found, we might add it to the package itself though so feel free to reach out. - -Extending `einsum` for certain array-types on the other hands is easy, -since we use the usual dispatch mechanism. -Consider e.g. adding a special operator for index-reductions of a `Diagonal`-operator. - -First, we need to add a method for the `asarray`-function that ensures that we return 0-dimensional arrays for operations. - -```@example 1 -using OMEinsum, LinearAlgebra - -OMEinsum.asarray(a::Number, ::Diagonal) = fill(a,()) -``` - -Now reducing over indices already works but it uses the `sum` function -which does not specialize on `Diagonal`: -```@example 1 -ein"ij -> "(Diagonal([1,2,3])) -``` - -we can do better by overloading the unary rule `einsum(::Sum, ixs, iy, ::Tuple{<:Diagonal}, <:Any)`: -```@example 1 -function OMEinsum.einsum(::OMEinsum.Sum, ixs, iy, xs::Tuple{<:Diagonal}, size_dict::Dict) - length(iy) == 1 && return diag(xs[1]) - return sum(diag(xs[1])) -end -``` - -where we use that the indices `iy` and `ixs` have already been checked in `match_rule`. -We now get our more efficient implementation when we call any of the below: -```@example 1 -ein"ij -> i"(Diagonal([1,2,3])) -``` - -```@example 1 -ein"ij -> j"(Diagonal([1,2,3])) -``` - -```@example 1 -ein"ij -> "(Diagonal([1,2,3])) -``` - -(To make sure the custom implementation is called, you can add a `print`-statement to the method for `Diagonal`) diff --git a/docs/src/implementation.md b/docs/src/implementation.md deleted file mode 100644 index b6015cd..0000000 --- a/docs/src/implementation.md +++ /dev/null @@ -1,107 +0,0 @@ -# Implementations - -## Identity -To test whether a specification `ixs,iy` is the identity, it is checked whether -`ixs` is made up of _one_ tuple of index-labels that is equal to `iy` _and_ -that all index-labels in `iy` are unique - the latter to distinguish identity -from e.g. projection to the diagonal like `ein"ii -> ii"`. - -The identity operation simply returns the first (and only) tensor argument to `einsum`. - -## Permutations - -A specification `ixs,iy` is an index-permutation if `ixs` is a tuple containing -one tuple of index-labels that are all unique and are a permutation of the labels -in `iy`. - -Index-permutation is implemented with `permutedims` and a permutation that's calculated -at runtime. - -## Tr - -A specification `ixs, iy` is a trace if `iy` is empty and `ixs` contains one -2-tuple containing the same index-label twice. - -A trace dispatches to the `LinearAlgebra.tr` although the result is wrapped in -a 0-dimensional array for type stability since all `einsum` return `AbstractArray`s. - -## Sum - -A specification `ixs,iy` is a sum or a reduction over indices if all indices in `iy` -are unique and contained in the only tuple in `ixs` that additionally contains -unique labels (that are reduced over). - -Index-reductions are implemented using `Base.sum` and `Base.dropdims` - the latter -to remove the singleton-dimensions left over after summing over a dimension. - -## Repeat -The inverse rule of `Sum`, e.g. `ij->lijk`. - -## Diag -A unary operation that remove multi-edges from a tensor, e.g. `ijkj->ikj`. - -## Duplicate -The inverse rule of `Diag`, e.g. `ikj->ijkj`. - -## SimpleBinaryRule -The contraction between two tensors with the following restriction -* a tensor can not be simplified by unary rules, e.g. `iij,jk,ik` is not valid, the first index can be simplified to `ij` using the unary rule `iij->ij`. -* no multi-edge - -A complete list of rules are -* ein",->" -* ein",k->k" -* ein"i,->i" -* ein"j,j->" -* ein"i,k->ik" and ein"i,k->ki", -* ein"j,jk->k" and ein"j,kj->k" -* ein"ji,j->i" and ein"ij,j->i" -* ein"ji,jk->ik" and its index permutations (within a tensor) -* ein"l,l->l" -* ein"l,kl->kl" -* ein"il,->il" -* ein"jl,jl->" -* ein"il,kl->ikl" and ein"il,kl->kil", -* ein"jl,jkl->kl" and ein"jl,kjl->kl" -* ein"jil,jl->il" and ein"ijl,jl->il" -* ein"jil,jkl->ikl" and its index permutations (within a tensor, except the batch dimension) - -Here, the batch dimension always appears as the last dimension. - -## Fallback - -The fallback is called for any specification that does not satisfy the criteria -outlined above. - -The dispatch calls `loop_einsum` which is defined in `loop_einsum.jl`. - -`loop_einsum` is based on the `EinArray`-struct. -An `EinArray` is a subtype of `AbstractArray` that represents an intermediate -step in a general einsum-expression _before_ reductions remove indices. -Consider a specification `ixs,iy` - the `EinArray` for that specification is -the array with an index for each (distinct) label in `ixs` and `iy`. -As an example, in `ein"ij,ik,il -> jkl"(a,b,c)`, the distinct labels are `(i,j,k,l)` -and the corresponding `EinArray` `einarr` would be a rank-4 tensor with an index each for -each distinct label. - -If an entry of `einarr` is requested, e.g. `einarr[i₁,j₁,k₁,l₁]`, it's values is lazily -constructed as `einarr[i₁,j₁,k₁,l₁] = a[i₁,j₁]*a[i₁,k₁]*a[i₁,l₁]` upon access - the lazy evaluation avoids constructing the whole array. - -To get to the final result, we reduce over the dimensions that are missing in -the output. By first allocating an array of the correct size, we can fill it -up with the entries of the `EinArray` which are calculated on the fly, -avoiding the allocation of the intermediate result. - -Thus effectively we split an operation like `ein"ij,ik,il -> jkl"(a,b,c)` into -two piece: `einarr = ein"ij,ik,il -> ijkl"(a,b,c)` and `ein"ijkl -> jkl"(einarr)` -but treat the first operation as a lazy one - this way we can use `mapreduce(identity, +)` -over the dimensions we want to remove which is implemented efficiently for both -regular `Array`s and `CuArray`s. - -## Debugging - -Calling `allow_loops(false)` will cause an error to be printed when if the -fallback `loop_einsum` is used. This is an `@error` which does not interrupt execution. - -Alternatively, a log of all methods used can be saved using `@debug` logging macro. -This is switched off by default, but can be printed by setting `ENV["JULIA_DEBUG"] = "all"`. diff --git a/docs/src/index.md b/docs/src/index.md index 431f451..e20cbe8 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,38 +1,16 @@ # OMEinsum.jl -This package mainly exports one function, `einsum`, with three interfaces. -`einsum` implements functionality similar to the `einsum` function in `numpy`, -although some details are different. +This package provides +- The einsum notation, which is similar to the einsum function in `numpy`, although some details are different. +- Highly optimized algorithms to optimize the contraction of tensors. -`einsum` operations are specified by a tuple of tensors `xs = (x1, x2, x3...)` -, a tuple of index-labels for the tensors in `xs`, `ixs = (ix1, ix2, ix3...)`, -and output index-labels `iy` specified as `einsum(EinCode(ixs,iy), xs)`. -Alternatively, operations can be specified using the `@ein`-macro or -the `@ein_str`- string literal (see examples or help). +The source code is available at [OMEinsum.jl](https://github.com/under-Peter/OMEinsum.jl). -Let `l` be the set of all unique labels in the `ixs` without the ones in `iy`. -`einsum` then calculates an output tensor `y` with indices labelled `iy` according -to the following specification: -```math -\forall iy : y[iy] = \sum_l x_1[ix_1] * x_2[ix_2] * x_3[ix_3] \ldots -``` +## Quick start -where the sum over `l` implies the sum over all possible values of the labels in `l`. +You can find a set up guide in the [README](https://github.com/under-Peter/OMEinsum.jl). To get started, open a Julia REPL and type the following code. -As an example, consider the _matrix multiplication_ of two random 2×2 tensors, where we have: -```julia -xs = (rand(2,2), rand(2,2)) -ixs = (('i','j'),('j','k')) -iy = ('i','k') -``` -Now `l = ('j',)` since all unique indices are `('i','j','k')` -but both `'i'` and `'k'` are in `iy`. -The output `y` is then defined by -```math -\forall i,k : y[i,k] = \sum_j x_1[i,j] * x_2[j,k] -``` -which is just the regular definition of matrix multiplication. Alternatively it could've been specified with a custom string-literal as `ein"ij,jk -> ik"(rand(2,2),rand(2,2))`, see [Input (flat)](@ref). - -The structure of an `einsum` evaluation with the string-literal is depicted -in the flowchart below: -![](ome-flowchart.png) +```@repl intro +using OMEinsum +optein"ij,jk,kl,lm->im"(randn(100, 100), randn(100, 100), randn(100, 100), randn(100, 100)) +``` \ No newline at end of file From 3ce4f022ad37d20d366ba4c0aeb459596bf6b004 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Fri, 12 Jul 2024 01:26:51 +0800 Subject: [PATCH 2/3] update docs --- docs/make.jl | 4 +- docs/src/autodiff.md | 22 ++++++++ docs/src/background.md | 4 +- docs/src/basic.md | 20 ++++++- docs/src/contractionorder.md | 42 ++++++++++----- docs/src/cuda.md | 48 +++++++++++++++++ docs/src/ome-flowchart.png | Bin 92509 -> 0 bytes docs/src/parsing.md | 102 ----------------------------------- examples/random_tn.jl | 58 -------------------- src/OMEinsum.jl | 1 + src/slicing.jl | 9 ++++ 11 files changed, 133 insertions(+), 177 deletions(-) create mode 100644 docs/src/autodiff.md create mode 100644 docs/src/cuda.md delete mode 100644 docs/src/ome-flowchart.png delete mode 100644 docs/src/parsing.md delete mode 100644 examples/random_tn.jl diff --git a/docs/make.jl b/docs/make.jl index 2808f69..ba31e72 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,8 +6,10 @@ makedocs(; pages=[ "Home" => "index.md", "Background: Tensor Networks" => "background.md", - "Basic Usage" => "basic.md", + "Basic usage" => "basic.md", "Contraction order optimization" => "contractionorder.md", + "Automatic differentiation" => "autodiff.md", + "CUDA" => "cuda.md", "Manual" => "docstrings.md" ], repo="https://github.com/under-Peter/OMEinsum.jl/blob/{commit}{path}#L{line}", diff --git a/docs/src/autodiff.md b/docs/src/autodiff.md new file mode 100644 index 0000000..53b3473 --- /dev/null +++ b/docs/src/autodiff.md @@ -0,0 +1,22 @@ +# Automatic differentiation + +There are two ways to compute the gradient of an einsum expression. The first one is to use the `OMEinsum` package, which is a custom implementation of the reverse-mode automatic differentiation. The second one is to use the [`Zygote`](https://github.com/FluxML/Zygote.jl) package, which is a source-to-source automatic differentiation tool. + +## Built-in automatic differentiation +The `OMEinsum` package provides a built-in function [`cost_and_gradient`](@ref) to compute the cost and the gradient of an einsum expression. + +```@repl autodiff +using OMEinsum # the 1st way +A, B, C = randn(2, 3), randn(3, 4), randn(4, 2); +y, g = cost_and_gradient(ein"(ij, jk), ki->", (A, B, C)) +``` +This built-in automatic differentiation is designed for tensor contractions and is more efficient than the general-purpose automatic differentiation tools. + +## Using Zygote +The backward rule for the basic einsum operation is ported to the [`ChainRulesCore`](https://github.com/JuliaDiff/ChainRulesCore.jl), which is used by the `Zygote` package. +Zygote is a source-to-source automatic differentiation tool that can be used to compute the gradient of an einsum expression. +It is more general and can be used for any Julia code. +```@repl autodiff +using Zygote # the 2nd way +Zygote.gradient((A, B, C)->ein"(ij, jk), ki->"(A, B, C)[], A, B, C) +``` \ No newline at end of file diff --git a/docs/src/background.md b/docs/src/background.md index a93f14b..597558e 100644 --- a/docs/src/background.md +++ b/docs/src/background.md @@ -60,4 +60,6 @@ Let A, B, C, ... be input tensors, O be the output tensor for indices in domain_of_unique_indices(einsum_notation) O[indices in O] += A[indices in A] * B[indices in B] * ... end -``` \ No newline at end of file +``` + +Please [Einsum examples](@ref) for some examples. \ No newline at end of file diff --git a/docs/src/basic.md b/docs/src/basic.md index d678b4e..8a3059c 100644 --- a/docs/src/basic.md +++ b/docs/src/basic.md @@ -5,7 +5,7 @@ In the following example, we demonstrate the einsum notation for basic tensor op ## Einsum notation To specify the operation, the user can either use the [`@ein_str`](@ref)-string literal or the [`EinCode`](@ref) object. For example, both the following code snippets define the matrix multiplication operation: -```@repl intro +```@repl tensor using OMEinsum code1 = ein"ij,jk -> ik" # the string literal ixs = [[1, 2], [2, 3]] # the input indices @@ -13,7 +13,23 @@ iy = [1, 3] # the output indices EinCode(ixs, iy) # the EinCode object (equivalent to the string literal) ``` -## Examples +The [`@ein_str`](@ref) macro can be used to define the einsum notation directly in the function call. +```@repl tensor +A, B = randn(2, 3), randn(3, 4); +ein"ij,jk -> ik"(A, B) # matrix multiplication +@ein C[i,k] := A[i,j] * B[j,k] # equivalent to the above line +``` +Here, we show that the [`@ein`](@ref) macro combines the einsum notation defintion and the operation in a single line, which is more convenient for simple operations. +Separating the einsum notation and the operation (the first approach) can be useful for reusing the einsum notation for multiple input tensors. + +For more than two input tensors, *the [`@ein_str`](@ref) macro does not optimize the contraction order*. In such cases, the user can use the [`@optein_str`](@ref) string literal to optimize the contraction order. +```@repl tensor +optein"ij,jk,kl,lm->im"(randn(100, 100), randn(100, 100), randn(100, 100), randn(100, 100)) +``` + +Sometimes, manually optimizing the contraction order can be beneficial. Please check [Contraction order optimization](@ref) for more details. + +## Einsum examples We first define the tensors and then demonstrate the einsum notation for various tensor operations. ```@repl tensor using OMEinsum diff --git a/docs/src/contractionorder.md b/docs/src/contractionorder.md index 428fcdb..b035257 100644 --- a/docs/src/contractionorder.md +++ b/docs/src/contractionorder.md @@ -1,33 +1,49 @@ # Contraction order optimization -OMEinsum does not implicitly optimize the contraction order. -Functionalities related to contraction order optimization are mostly defined in [OMEinsumContractionOrders](https://github.com/TensorBFS/OMEinsumContractionOrders.jl) +The [`@ein_str`](@ref) string literal does not optimize the contraction order for more than two input tensors. -Here, we provide an example, advanced uses can be found in [OMEinsumContractionOrders](https://github.com/TensorBFS/OMEinsumContractionOrders.jl) and the [performance tips](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/performancetips/) of [GenericTensorNetworks](https://github.com/QuEraComputing/GenericTensorNetworks.jl). -Let us first consider the following contraction order - -```@example 3 +```@repl order using OMEinsum code = ein"ij,jk,kl,li->" ``` The time and space complexity can be obtained by calling the [`contraction_complexity`](@ref) function. -```@example 3 -size_dict = uniformsize(code, 10) +```@repl order +size_dict = uniformsize(code, 10) # size of the labels are set to 10 -contraction_complexity(code, size_dict) +contraction_complexity(code, size_dict) # time and space complexity ``` The return values are `log2` values of the number of iterations, number of elements of the largest tensor and the number of elementwise read-write operations. -```@example 3 +## Optimizing the contraction order +To optimize the contraction order, we can use the [`optimize_code`](@ref) function. + +```@repl order optcode = optimize_code(code, size_dict, TreeSA()) ``` -The output value is a binary contraction tree with type [`NestedEinsum`](@ref) type. -The time and readwrite complexities are significantly reduced comparing to the direct contraction. +The output value is a binary contraction tree with type [`SlicedEinsum`](@ref) or [`NestedEinsum`](@ref). +The `TreeSA` is a local search algorithm that optimizes the contraction order. More algorithms can be found in the +[OMEinsumContractionOrders](https://github.com/TensorBFS/OMEinsumContractionOrders.jl) and the [performance tips](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/performancetips/) of [GenericTensorNetworks](https://github.com/QuEraComputing/GenericTensorNetworks.jl). -```@example 3 +After optimizing the contraction order, the time and readwrite complexities are significantly reduced. + +```@repl order contraction_complexity(optcode, size_dict) +``` + +## Using `optein` string literal +For convenience, the optimized contraction can be directly contructed by using the [`@optein_str`](@ref) string literal. +```@repl order +optein"ij,jk,kl,li->" # optimized contraction, without knowing the size of the tensors +``` +The drawback of using `@optein_str` is that the contraction order is optimized without knowing the size of the tensors. +Only the tensor ranks are used to optimize the contraction order. + +## Manual optimization +One can also manually specify the contraction order by using the [`@ein_str`](@ref) string literal. +```@repl order +ein"((ij,jk),kl),li->ik" # manually optimized contraction ``` \ No newline at end of file diff --git a/docs/src/cuda.md b/docs/src/cuda.md new file mode 100644 index 0000000..63a3381 --- /dev/null +++ b/docs/src/cuda.md @@ -0,0 +1,48 @@ +# CUDA Acceleration + +By uploading your data to the GPU, you can accelerate the computation of your model. + +```julia repl +julia> using CUDA, OMEinsum + +julia> code = ein"ij,jk,kl,li->" # the einsum notation +ij, jk, kl, li -> + +julia> A, B, C, D = rand(1000, 1000), rand(1000, 300), rand(300, 800), rand(800, 1000); + +julia> size_dict = OMEinsum.get_size_dict(getixsv(code), (A, B, C, D)) # get the size of the labels +Dict{Char, Int64} with 4 entries: + 'j' => 1000 + 'i' => 1000 + 'k' => 300 + 'l' => 800 + +julia> optcode = optimize_code(code, size_dict, TreeSA()) # optimize the contraction order +SlicedEinsum{Char, DynamicNestedEinsum{Char}}(Char[], kl, kl -> +├─ ki, li -> kl +│ ├─ jk, ij -> ki +│ │ ├─ jk +│ │ └─ ij +│ └─ li +└─ kl +) +``` + +The contraction order is optimized. Now, let's benchmark the contraction on the CPU. + +```julia repl +julia> using BenchmarkTools + +julia> @btime optcode($A, $B, $C, $D) # the contraction on CPU + 6.053 ms (308 allocations: 20.16 MiB) +0-dimensional Array{Float64, 0}: +1.4984046443610943e10 +``` + +The contraction on the CPU takes about 6 ms. Now, let's upload the data to the GPU and perform the contraction on the GPU. +```julia repl +julia> @btime CUDA.@sync optcode($cuA, $cuB, $cuC, $cuD) # the contraction on GPU + 243.888 μs (763 allocations: 28.56 KiB) +0-dimensional CuArray{Float64, 0, CUDA.DeviceMemory}: +1.4984046443610939e10 +``` \ No newline at end of file diff --git a/docs/src/ome-flowchart.png b/docs/src/ome-flowchart.png deleted file mode 100644 index 0bceac0d149c89d4f059c4898acae026b6c7f70b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92509 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

up7js=@0^mryQ}7_1 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Đ=^JzOVo=m0b%Qy#r5JcUiYbQ1R8{mSO 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 _0n>&5#RtPsY;Tu5dUh;VL6}f&d>=hglGt92n z><66|d9ETzF(sJq`j_^V=a@6A%TR90Gy~NHFRA z8>d{jCzhYX2n5_;*jnO1&`5Nze`J5juvshn7YiV{LGUMIB|WfDD2$pAXaW$$(kZ`_ z@8R05K@C3o9{DBB^lNC33rjdX`YaZRHr2~DcdM1qv>$50K+PwQ0J{^5V-=?63Kf^r&4G;i`_iU&vCU{CU^OUSZ@-`)fZ+4q%ke z?k<)wXtL{lHX;#kLFLc`jdPJ@cwgzlcIjH^8Iap5_K=?4sXXpHZL=65U#7{srkxmR z1`{9D+i@2Hc?@pCwI&Vm*L% z$H~qgMVZwAe}4*#@dER@fj`XG0`6zu)k+P(ANc38$-&+rFay-pB?03ii~Y)L+s9UM zpuQ*H392M8)9g(SkBYA}uUe#~?)l51w)d<+y?iuqn%v_6rYn*>5-L!l+w8^dv;)M< zH(zuFV?8G2a}oo7%n$&i-JDI^0Id$5z$c_3_>3AkRpz(Vw1z-e0H6F<5*G%5*>^X( zpO2nTDbdjH%+?ctf*zIKNK!uh7qZF1K;%cE%2GXynCnS$Ty> zpgyG3VuESx{0ogVR6&_mA>F@h_4a%oaWQorgM=FsC~u3+HMp`kZYe2qrFVkOq}1aQ za+zN&pQqOv%t=&xr2{J}snCA#XgC`2765?9xR(fJ;~0p(a$1Gxw+B)JX_&2di{Xe~ zM04TWmfCE~&t%lpdLMt7%=joQRQD4lPRduhU-WOZf z|1G)-FB1T28+~4KdpHq}5wGSVH5Oe!jT)6okydWk!S`1m8Ridl7Up49&spUbJfZ#% z36H(lZSYd#PYY#GuePXE=A;X0jyY#FVFl_VD1MuugbC_&l9c@C9={y4=Qz?mRG#QeFQWyMl~q5#++D;>Ye!qQm&28%gvT!E&^2tpc& za5O25w4~y@LsrO_fu;*Rh16H}mz^~M@|;z*jFu2>E$Wriw4irG1a_A@NM&x*;VykyXS#0f#n^r9c7_Q zOa`Eb;pTEk*%?Gb&dX&z)6(R5Jt`W^<8>2(VK5aBszQh%{6OQ`%@la!nym~}Upz{z zrz+kEP>f{DMS}Uc2z2+9CQP2tW~7G`bE){e?m4c&e3wg{k?5;b@zVH8h8_+{HGr1| z{yX^W7Z=NscB_4Or^`V?uaU@rgbs!?zYA=jztEl9LXFj*GMXpkf(2dXKoA9&w#?&d zGaJQ^d(f2`s7EOHQc_lcawTpcYjm{Io6+T+Et@im@pR5Rb>>A;OO()*3x@5C!@!Hz zQNrP>s^>>Q%ww!ky8eP|0hAqXc`bO3X1>7zP}plfp>Y@Q;drncLHmxi`r z!-m!zT?yUeV^O%?gC#O@%PW)fgwmS=TdbYl>r+YW%TnYVL|w&4*+ zcR>-UY7`a-o;HKwrUFYNAwL5bPrF?mR9I(%cSMr*L{Y zQxI27zIkT(_+i;gq^Y|Mh^yVSE)BW_n|4GQ2FQ0?m<9|R&GC^;gyGvK4|7VOSGIw1 zeNMO0j$1Kh zNsw*RL*#wbx$CemtSEgV8}F539~I)6_cSR|i9EaSI@k|UK?-W{o_ARex3vLItneLb z+P5YEXXqvfEMIAhrQbL{olv_VCov;kC_VzU15^1}qHA-EY9+$AFfYExGV2P?m=U4( zA@TXs7DDp6k)E{%WAKP9g9a*{{JQd$+%Wne{8-dV>UF*-gnH+IG7Ilc!6Z{SNoORh z8Oa)o)RfeFov;vt*9tV`9q2@IKwS#bXJB$zPtNww=e?_m4B_+yDR@>p5h}PJlu$rs5ksrx(1|9uRw<=K0)~AIA5=sVx z9#b*lqqM}aLF%*-1EDD==>WCBwRCwNvNN6mQpC+=I@}ZGH z+&b?hGU3c4(h&UpMPy${vYQkDy&pPWOLWrly84Ilx=SccJzI-Jf<-?jMfSR}>%8IK zzJt^aUi*D!lU>C|n<&;Twm&Fng`}TcGh`F1NQJC_Gfoiy6vw&$Q5!EQ;TTya$eXF zPU1_jt`(`J%~{)DUO7t3aeKCDk*tj$s8-d}GS+5eFgB3N&|1tvN`&hH}8Llb3oVJU5F2NrJm>C7_s_6cZA#u1< zUHPm$L&U%PZl^Rugpuk)nXUE$gcfS4kL?oq`pr}&9uqklvqxPxW7s{t?L-~!QJajN}^p-Me!uh!HLRH4N72QUvhk)3& zt3N#`1v{P~KKIa9Z$R-9_$vWx(-W-_bcw1Bmq1j_2CqFBK~>WJ>lhK?)H?rRtMrh8 z2v2k;QLo{L(2+ci#TZ71yoAVg8OX|(Vb#wDhC*BOWP0zyRtWHe%y~ls6xU|D?LY}( zoCD#ko>AcEr)?>mu>+eLf|=?C4rn~F{Q-{$qLo5vR3+^xGVbc} zwengl144EFZzN=R#5)m5ue)>UBq|cPOwj}1mb}nndwB;fQpeD;+J4$blU@DnabU!p zhltF4u@0%B`#Hingk)l)GO7PjM>JQq6qO1RCI(@azi#hDWTrAs-dh~SBPW^h^TT+CZ{tTvj_=XK zcGa8nJ_TelKaeg)d?s4U#CmjTYrIG&CFqabtj)9fl%ptGVlHd^H^>MXp7Tx-<2og+lGT4Ud^ zho#??nZU2+DF(?17QE;hp*sC5b5{p70tV!*wf9;^DZh%b9X+?GT8>I)k}*yxm`Ch06e zkv(`jZX)V{xbSuCS8edrG}-G=06x^oVf0XQudGu>oUGvJEDD-+zjigdc!a zGTxN@9-#=je%c^=wHtXOn({$=!kCaXQocog!cZ#Aq0mR&rw_Dfm&IWm1eCLN(I@EF zfDCfGjn@TC2gY>V#QyqW42^NxgcoOT=c4e5+#Hi>v>@)gPPXw2;S=(PMTxJ<~@o z;PXBW2qho)GjHAYs}|~b>~CJjKUS7Bxpj(@OyGPkb*f|7xGULHy}`cu2PZ#UMl`&7 z4rQe9?Dl$j9Wch00>)T6SNrMx_jKxk%`mtSRQbdo$ z2NUDRyLd9^_9h2?HbJPiGo*OV_ve@tV&f} z+&J8@c?(Jr(5+0;!H5dEN;45-{bMj<9wu3Jz_5;tADxOHVaz%>fiLb+Y}fC0dUCE~ zNT6+K{%TL7QodH{C46PA`M45K5E~+flULT0mLY-2H;f7tN-%ffZ01-H_PlkGU3>_8 z)jjN-8{>V{HMyYc)o8lp_kC|d9WwpMIL0wAf484hA57%$8>~s6o^Pc2*lss@a^Gzi zzfPt8%nEXwTl#5Km`-h2rd++P*N%-S0bS;9J~h$J?}vU&I*!*eM^~ z8&U;|Ef8x9bNkuoD*l(dY*Pwmjr_^#UC{HNLhSBjY5A?xdK*%d0LOk137m(!;aN>p zJjhAhm){ZAczSpGzlJkPPpaoFE!pkw(#rYUB=(y^SsLB9y@W(;(D1=Cb7-wVVh_qN zcKuc2eJF@^=2mI-7o#Ll-b03tklKkMU>9giSy@W=Q3L_MZ~<;`*%c}k^h1H%+n$xZ zzc6Tn(_$OCj&JX$A{now*BC3dskud>+NkSMJ|D?j=^-ea0#Qlv zbyPw(g|}u>xJXbUHN!|uaJiN%IR66c)+ZFhFT%_-R!0OXZ-eP%LSUhxO7^oJaH+cQ zaAT%h*uN1qarHNQm-%Skg2C1Qvu%}+K6OX5qPTA`G(OMLc%q`&B5y;6<$hBnth7!Z z7%w^5D30m@piF7=7CX*CzaPPfYS+99Lqda&#;(afZ%>0A5ZZypC<=9L9Pn)Ryf+vk z4;r24J0~Cg0ZJuI92f)2lJibW zc6-qB{BpMyL#|RTHW0ZD0-QklBUv(>^LT?P#5h-{?V6pT*MF`a)isErJ?{DQTiF{L zN4LQc+q;4d{5&Ezhz}nF%ZAS^(R{dUN6$T(`|M>jO?wZSz);q!#|n&j&p(w6gGksInGhkW{73#BG(ta57Cdtbk4BaKEtwI88_G^)@>mpHo?tl)JT$YB z{-0(-Nykhg0O?qwXa@<~-|vd@@Ld~aLC;1L0a29W8YWBk0BGye>H5FluNXSj9M=e8 zL{oUg23X3W-}bEN??>8(0)$d{B>t~`or#{>ezaW4()oPpMUu@>js^$ucJW+|Zv~+D z9ZBZNQ7g-obvKqT2ZVfE+$__<(19DaD7N}%Wl5pKBqJ=kTE;MXo$^#trBI}y#*R?{ znoVJYNAsjD0+fQ2P>|>j7UjR+h=LzP5`W6@IenMxkK35fjRr}n3;7lZol=}dFf0_A zYKQ^%AG28W)&C;)NuI()_T(Eoa<@vcL?FAF5;L{IhNuZhkY&yvOm+mtN`Yqh`pqA`y z01P}BiEysgoq#7_RTAomI4+8S=U;&45adZEL6;unZs;Y2PWz}C7Nle}_};g|ejw(- z2HAfc$VtF87^AejikINAUv1IAWhnPI%{@J)0>tBR2|k3~GT1wkoZ$ca#sxIATN`yB z4Y0C*kBGOv7KQ0$ISJaDtIqd zdA63I4jpQD)s~^jJDhDtXijgCgi0@mEhw1B7`i4*&f)#tWm153<*;=Fn92a9K|~^S z2dZ+0f7mp^kVAjW@_+JmLUfoU*nTRvS81A|_|VA_PP6E{xJJqc-C75T1WDdt(;OLM zz;68Jebla9Z~a~DlP*a}ll^;+(Y#pXd2eqt(ZHS7N{dMO9C_BasW;C&z z`s$&_z+Hv*__m;>r8kADOk2|CaHPjiV*-awgkuLR@{E_XPZrwiNOZ?ae#HHUnRgkD8 z<4{Jf(TSP#7u%vYCW?{D-b?#u$#5Agwkf(CWs(Aobh23U-byjw*U;Vl<>if6+215D zp*9So`G&O+wZ=x#JDq}TD#*=72LHuQd0X6|cqAD*$VrrJ?xgU^MG4(wQ_GPNAUL|q`x#4Z|*d8}j zD!!vX+pQ0%w6OSYzxu%oTZV}q#RUqNH>ulPWdO8?E+RXS3fMgf06f}w!L^NqM$F#h zxAt?s1gX_*=_?0Y?sC2=dAj|oGPn1gAU;Em-&7^r^&3cS0qsI9FyB;*>>#kToi4za zwjQ9=;6SlW{43w`o54P-xffhB2vcT847(52+trO`cqbo7wl@MFJ|!mCID7DtZHya+fX@_-iX@ zFXjw+HeMr3VC~O)NAyNx1YEl9&jr$Iao2u> zkLeGE-GjcmNyV+;rCyF?aj;CFa*H|?t>xvE3;g?EC_SsMqlPxZva>Up5?PY z%|YP~c`8*QkC^eQMIKQW69-oO!8$emnU6Vt5nsHvUwqP@BvU+x3whWxEB@Itncm0DC95$N&=D!%TnwpPBC29p2uP$hMl&<8~P7lcvK@=>+EkeS{M*7^tJRE$?d< zioclu3CHdQHQYP~X~>%6_SR6}Bepk)pkDY=x+8=GmBl~|mFli5yb@E$>n*!k8P*Fq zPP@%y4vRs58 zUtzJ@8{J{1TgkgUu5Ftmy*-|!P-a9&BItpb$o4`QXhA7yYS&qo@;G%PkCw|M&0Ngi z59V>^7Or{k@{)TePy8s9OKoUz-!H^qv-Y}Jtohwwx4e_Uwoa&0RFF0Gl+UU8Xx1Nj zbtv+^SfWhQ^h*q*dTJ$mh9 zF-n`{7SExpp1@{e0C+cN)+S>guMG-B#M1xL@BLDZr&RVcOU6NseMrz^co2oKwW+A|59 z=QpSln`A;>zKYo*xHAmeR}mpncuY6tZa;K>rNUdW-|W?ABExNZt9tq63}+pVv)M$nV2S4`l3)wvJD$ z@>Q1Rj^R3uRWB2E#|wRU_a+aSSNdWBHJ<;Jo@c}Re&w6f31yEvSAFS@gPB@)VB+D{ za~?QNw^byvsSOsJ^=Il|s7nry~rd$d8=8bn1s7o?n ziEcZkaAb{98d-c+k`V8Y)%0~erZfDNO579AOq8c06FHo5PCx(ln~n~L38+wOt#x2- z1B%QscPAXvM&6adX=g;mP!2bfef5^8JFn~Au^a^|oW59TE5P6uv28kR5Ph}S(pK8F zu`ur)G-%AAX8Z2;y!k#r0&jO)^29hcSYHfpMAZ{U)bmobfF%mnd4Kk?Dn;ZszKO0a zIAm4ru38|akM!otK4Qw^41d5;U5d5@2}5XOB~kGNAs(nm<+Ou?@SI4m#?cB4I~KrF6OHW ze`R+lb+ixw6qB?ArIj*MN@W>HxsC!Bv{iS>RW_5h$e{$P=+0U!SCyXEj)1VHH;e2q zOB&kSe^}D4XA9J2lb$2}UhOY#skC4mT|es{EOOo$B2_AGLRkOhZK~Lrh)}dMSG^wx zk0x|?!HoARmFKt+lKn$YNKPEk(aJnUKqKbRh};@u^R@Xi9OCGy$~g%_0)z^kC(6LO zb?-1OfOUrwFhhMy_<(A^kBs=;P&5bchn9ubk5G)%=_LSc3^#jwLpgT&<>(WCXLSP9 z;&6oute`Xkg0xi}as5I1%f#@{sW0K5BiJx6OF<$#zda_&pn9G`9QRifiA%-@iiQ zWFw6yibjf|eX{hu(n_xR*x1Hz8lk7010ifCdueK=KWaSdWAjYBEv*!d09{v%<93lE z1&NN?AA6h-Jn2tzLO*R38O!uuy9~zCBO^RvSUWg+6Fmqs|2CRNTI96xwlpKU=|1(+ zYrVws4YQwGyQo{!M+pFd@>)8R*F}nCZ^dH_Bu z5I$NF$}zhD&MCw5>50gm*_V2RSd}NLsx9)~f>@y+a$1H*vH_=2+GLGYQn(}FTx|vT zD}@XR^y&f~C{6L%4zgdm?iw^_c3_J9&S9n>ZS$^=j=20-{iBi*M)H5;9muP#1$2SS;1v zG#tw!aJ=vL;6O*)jl6{kO#Zqmf`0ukPghs0_*h>4XhlOtuDe`|?P!iC;Au{!;Zhi( zXVrU6e7<9rV@b-9$G$c33%e^4&~yR66pwN(5fWZgGmJ*sGRrUegW&38q1t#=AoBLs`-t4hMv zUqahHwGLW#{kwK*kvxGj4@6fXjE}RakX6A%l9(vcgcu@F#gq;;UaJ`OetD!_kKeL6 zLP@LRk@%kO&)p;*!1;No7hjNN1>AhIW0)FrT0K;nJQA zP0&PyapbAFm4sg6dX2s)<9|u6t{zCP3?f4CM*cjIT>a@TF^|25vIY(Blnk=0w2>Fl zu5rIk{O#n(mmRo0+8Z`r=%9bTmju|Ro0U^(rL*1&>5t`Y>1TbZyu!Mze}>f_OqW#* z0$f)|L24N|@TmgsfuD}o^a195;TcXLfViUqB%g{rAlzMgt?mw}e8&b?dZSyn&1hso za0$l?i8UsQF}8(DKG&&z{|5EtD6<0a+oiFhud<_0aLdpRL z{j=j0q-&_Jvuv;<=$h-0r74FPJ@PEIej5^=e=vGLe3@xyB7{^X6GbO;Pngm}RYE%0 zd5LL#K9sf}tM=dQbQTs-J+a-n-|mm+SbrHNR)o_*>6Ocbb&auk}37 zCU`vetDbdt3O017c+;@!Jqnue9(Eu{8N~sB)p=81Z?_st>g-9CZEYY0oyD<|<*5Cw_ea88M zc38tvZ+DUS$4A?R;g*1N1p>;s(3mS7hF$Jabph$#gS^F+v-xu2MTK@P=tLP?RtkNW zZpg={a!Q*CK%nZ=Nuf(XqSxYJRl{Jq^9J{@JscU%~NZg<4Ipsff(jW6^_Jh z-RfAcuX-qb**(*Sqb_3?%w1Tklh2xkzn313vMC|;QEa=>Tyt9UG2Ye^2i!A-R1Es= z!P|JoO}FFtbSa|1B!vmI%vkPNl!wU2Z1tREV}mvtQDdzG;fAmh!Z6A$XYP{c&nr}J zemdSgNp@0rxam}woXu+oM;`x^OKtmY2FY~rI+0Gf#QA<$QQ z7eGWin(!d?76F0nWXdT2)YIl2c8|;G@%~CEGWt6oveOG60w3CAX;iT}Z}Q+IdsJtH zy-O(&)_uMkCq)1lcA4$%_d8l05ck&wf z8V?9#tW6iXlLrB-bhN>@!QTR8J-%Z(Jy!P1*zTR#*geaQ{}h?ZWAuOhtLO;bk!%d{cS@9-zH$^qj<=jl9XKbDX`G7Ik+eTrJyK! zG&&N0!~IJg?KHUQQLip+zZMFQ=n;^m7j|BZ7&(vVF{iUM>wq=rnhk zE#GYHeK4U>zzLD6I5Bm%>d~*3cp?{`eQxt(CQat-ek9~;Q`lxq(Gj1y2D>ge^&OzdvTR5#4l-WG7T86`e@NvI1x~s&Aaa+w zFst6bB8Yuy+)m_IxUVNELYKXZVE35N|IG^jZus zAMLH3r`=R#;2IJFl}SKphZt${#NlY&D%+qsCH;5C4ehs|ED!R&lfttcOY=*xCq(kD zr}3%w{2|x`1fgS#iy?5AudhN*iyD`^5?L6yBOjh0=FIY%t&Q@6A}1YDx5FC}rM+pG z?e|t6I~aF@S_IU^K74lil*5^Lnk?#H{B>^D;21K$;W1Ru`*%n+Fhgo*-{Ah#aw083 zAit6mBsXTrN8KW}(+D-L!>Z$Y4lW5xi+!1dUo`GKj?CU!SB7aoT~XtO^LcOW?4n zBo~}4bE)^(ac>KY7E?-ql&`k2LeV~?*EC@Y(0U0n=DS`++IHf+$U6pNY??*O)gz#o zOWfk#TAN1sq9dy&E6=Ndg*2|GgsQQ3(w$cyc^fEwKII^VAdDa3$oK_>)ASt(IhoH5 z8w@1Zy4u*>l8<~@^L$MK$aZG}&ja?EoOdP}L~tg^7L>QO?txfqsb+JC8g99bVzStw z^n}tEZyc$Kt4RXt!@4^@63a!j!-7(O3cP&o#^5o(6Lf*5UlyZ}=BmqA2U2oN?O0;v-m=2Ft7!lu#pCnFrZ7VtaE~k+g zJchEQ+LtoN73dFF^m0XzgLkJH_(XpSc&!d?e0 zhBa;6Hc&YG?DCYW^Lbw;L%2O4AQ6UwB%|o;hsg>|3aw{m2rst2j4FJPVIen1`+Krs zGCf#LCb)O->@-NABR2cs5*pCzGq>iyU147B&kAWnYkvc>Xc!xQ5z`1czMOEIB^U)MQ864(Mo~03Cf~6U0G(~79WjvR!=#*&G~sh> zL&;@~Q@_>0=EDh|`26^FE9F+P7JH7H_u-akzKRk1>ES{{ zxxJB0zA844k{@LcIFwnenmpFW8^Ajl$__~$y zdsgNSH(A*0-(ywb2Q8ctpRdCKL0T4bO+yphPz$Bx1AAc1xI!Q`>SWBWK@}I5Njw&~ zoT?@!H$$)UpbyUZCj-!G>#^)CGXu&j@-wYI)~e4meIQcomgbX=UVkR-S;@OvJtD-G zpo#q)r!%JJl2Vf38$xQ~o1Yr(F$J~q44YmU>+xCb84TW6&bh8K>An9%wFlJH+Wl$S zUSW2f)8m-fAZ$8Qt|wO`Pt$pM&}OvyJ!=f}o4%{(kFr#OArhf(^l=;v%=GuZ^&n00 zd4bm9bZ@o8Q;-@&Y6?ipDDrk)zLF2WH0zsiTS`lj#73Y1#z&iV#Rky(Sq zCLujbv<*rY41n9-!d3R}H%wPTmq%m7iuFb5*1qWG(Kbemm4;J#UFF!tLsJ zV~dEaZ^+3XwhZa}gA}#kuBJ)fb8l9?g9d5aPj49WL8c(7E;j4~xL9%yj(l{=k>dIH zLIk(myoRU=rmVr1uBVN-H`FTg^km*|lI@0oE$Qu_8z1MWzJe+UiPZ^hh9C`2Mt=z; zinJc12d=T6p1)ueHEiGATz*b701_w2XOrmPd;^teWD+O6wnGmbm#n6}egUC@$8|j> z9I~$|_Mqb54z3iQDr+}5eUkND^D6RI2=^9N)f=rHYm3lkJwIN*mLNQ|$%9@w+8rj! zwKuw~rfEW>p+AC)+>zw{Dd~Jx(vT}>a+7_$y6+xg*nO_t4PLX-U>?L)0IB$@n{EuR zMSq}0ei-%L{u-AROr}MMDS69vDTB?K&r6`%59yoAY^B8hUtNi?h|P6GubV9R@s>%s!O%4U1p|~AmaWZH(X$w z@bcw!2ASYM^9hjYDn0k|UaYwD?h7M5_gG5Ew&jfB;WOY_krETrm%mr*%Z@(`@z)YL zMDeOIraYhL6cr(Nx87D3J4Hhy8p=hy0Bwabd>D$2t1{CXWC2n%jf3}EgRafkc{D{h zVba{#vcuhztk}juc_C)UH;0NO4f|f~UY(2$lhvPaF3*imw8pjPmQcc$eSWlgryUhJ z)Yqidfqbm283IbdRk`+T`LQym4x^86@@Kw%Hg;1=@D0A?pA<4a1$5L&KH!q4>rZoMny=RB7=q$%w=tpEo_3z z+*18371UxVKjwb+v#ayX#FSyhj)T%=;n#kERsfXllH5+ zRi=0?K!+mO%kWH+M0=X^0X$fQzk>6=*P6D0HfW8{7UAF%IREv@#*F+jk_u zP47h2RAL#44+qhG)=zgFk5JoSM}@5G_}E&=>^ab0m1EThH+u&>N}Erwh0r3R-v%1$ zPGQRG4$}UaBqD2xNTcRQkrsySLTH`hXk0W%93%lXGkB46MAG_Cy40U|QCGF78^J^B z*zx3Gv)C=b;Ty9yLe6=vR(TpBO{Pq9w_$L1%80dvInOX1+!g=Z#Z)aBMn=3YjgWy~ z2uq1}mG*(JvU9K9j~`5N3W>JOBLRUv)C^buHcm-Wb`;o$7@wHlOG*dO(eEs$aN9dTY#;8kO{7!uT1 z?{UGE5~4jS%R+`W0#5=RD6ITdI4t?JZ$hk}A zUxTH zQWc`?HgIzz#+OSLI_fmAb-Pon_fgIIVb^R#mBq|w-8xBw^{=;!Prk0RJRCB-H2>K| zXF5=1?6X08H8NuBxoX{KQi`zWTUyE@<2DT}{3Qy%lA#AzbdePLOVkAuSTPgNvApZ6 zP8UaADA)~rVm~}nmK8tO8)M`Vu&$Qy+|$e2nlJ1BZg)1|@fPv1gor`#gGJ@=I{EOmBG%COUwAZlQcV3P} zE(792R~;U+KlQ?xqec>i<;KAbC!d~RRYX;;5oDG3q?e)=vZxP~+K-%#J z14H*Qnw!q@72`&oN-ir$=ZfXlVvf&<8daF=SS(i}bD7`2IQ*HVNGOWQZVu!|E~e#X zLQ0UoY`n`w7kIxpJ^Lp6w8k~ZV|sea}^zoa;SIqu=@v&y1b}!%r|hC z>bUASL$U=kzM{U}&YhZzntF|}`*Qj%3m|q+n}tlN=x5qrYpLB-l=arF$}Uz) zR5KPB!@54oL)#Rg4s(lnKQYsV_ilo}(?fKj&#@cXt)SJ@GV%J@VU}r33UF z2v!DzxU-{99VXsN zHW0owKdkc6@v%j3S_UbZi{J9_xu5M%a|L?(lw=L38EM|rGf&>3ylYN{#$KPrjDa>) z-r~r6^L$M!#!#xqNy|guu1&6GpWSWj9sC_r%poVV(;8jgwoDJgd76TawUep{xPG-rlk`DXo8F#5k|%BR|apo z9c)~;8Ew6>-Ig@4wm!q!R{FFp+4=nJ+R?8YR=#Ht_^IfqN-76T%WmQU@tZf!qf2+5 zbT5G*chaLlKN2rkcZw)m_5pA`*LvN~^gfzfhtp`N&kQi?<-?HhGdjtT8nRMW1c$yC zy2knNEyt51=?7Pw@*eX9>w5r0oUjvSOD+1b$ww0y^OU=;0n39wn8}Mbun=ruj$-OL zw4p}7^3~(@rPdmk_Y^H)z61`gkY&tm3RVKbRePjt$S+ zW`YM7K^m`SO5%cxE4Lezzcmk{?BG*jPE3#@9AhgjH&%R2J;`P?&`a=`v5e021pjB9 zdlW7lA;DwTNw?N|=@XlG0xu>M$>nlqC0bN2>Iw+-R<=)X$9>#b?&?qVk|d%Ld*`hf zTP?N)H$w?lWSmfL_4Ith4FYWMF4 zl6Z4<+<)J`5W?B&U{q&RrbY7VrAmNoXzNU*2Fu*!W~y@EH0PDu!zDSL*SUM^_^fi} z*C%$iU%)gzsL&5@VZlQwpPOq3U_qp)ji>uj0B3>6m*)yz#ZMCU)wj0WZeZ7?%I^Vg zvLJmr2>MxJ)ipgtsI{eo2I9PnsRZPmFrUL50w_c_Rx^_GE%Y+2w z*2c6HrMQm>Age}#Xu(q}RuCN;tdPI9Je*CybcKN6-Q{})o&Y`A`4K_yY_st2z5N#( zC<3>O)4W|Av~-%uXxUc+X;f)2tCmuOVerFt@i`0Gtd3c8AuYa5KHR5mZcK#eH$Xjm>+8G`ysQiB5hoSvZ z0>wj27^+bVr}7BI-GcMBKmazR{-ivTUHum2j|w(#wM^U};%V4cN*h*q2wVfF@=Gug zRq*y8g)Mz-Wc08=X(ti>&syJ9*`6f%H)Uphr+7rxd}shEuIU2yko<{nOh>)ve(T@? zAQlCkm&5?tY~Hi&UxS(MPBZ6;^$>X1Z=)S$O|Y-?JvhGDUI3{ytoEB*rpux}BJ7W< zy18op1NQWG4$XW40&&TYY`m8GnRI&&={x(H`o?S3$@NYANOYn8gYaAH6iYWY5xzEP+81VCY3N^iSX zS~EztvxTXO00ef??|wB7(AWef($|?cAK)sg9hpyB$lNwI=>MSGKm+^KDz2c-lLmyh zVvhFLmBEDYv_72hj}TZ)5p-bKoOr1t|K`s1U5laM8a^x8pleLrt^7=P&L@HuwEVB#Xr+&v7dW=h z0=x*F=&qzb>pUi=aT)b})5G&iL{e-L@mUcJ8s-d2LtVfjQA>oV^am3tb~WZwBYX<}!>wH(( z<~8`lr_TG@1rRA;mLQJ@S&g%8;THXM?!4Bcyfvn-zwCht4qPUn5s3$}$a(ctyYU*P zINtU;{hIH|^rh!y zZ2i$J>bVkrSRBXAbR+3fc%z_VG2^3OU5c|FJ87(@9n6`2k!UP|{PehSy|SqsDzDwhJpo4LH4g7%iS?F>jB}W1vDd0K8KRfa!;+_vNV% zL=aNv+W6zv3wigx&Wtz!`H5)72tZ2KhODyEgkE2 zPjY5p`+c1m~alJ}#3pXggsiB^?cc8gUo!(0QNpHLu) zyU|koWYE3!($Q(>^?-(kSb>s9kJLU%UuJ$54LX_`Emup98Q{u+3v^#G8$xTb4~Q^> z&)csinkt7=T^@bo5&4xqTnHlN?gdqRfU){E6xhJ7&=$sN_)+M4cA5Ryp7f0yRJigM zhAfXL>(k5x7ca^+=;SD%8)eh}Mq_b+|4`sZLeP;yIGBtpFg6nx{0`1M(2cKDz>Id% zBSEqx#$a(=7%X|rkA5Lg=_Z7JAQcPKOV_`>1gD+~cN+xGMF}AK`YV6-zP=h* z(vd>AhRkoJ3_*?-7{0Y97c&vb3IUC9VOqli*_@cqSO;_V=QBWuOv0d`wX2w1F+jlZ zqyVh}0>(SgAtom{Xf2=-qBekHlQ@j->K#E{~`}F_HC(U5Bj8Y5tF0<>Je?8dL z;1v1Ubo6bwST**8sl`f?kVdhagS=;U?qi6Q3^iVvCT2o2hR@2b|MLwX7F01-rM~yz z?c&I2MKrHGi7pWY4RyZNh(yg~STaxLg3(wbhW;~zKmF*%d8>YpD~>1dXZfv-LgD_? zQYa&&hU^U$39!92Jn1m=gjoPkSHpN=Qw0x3Umr?AQ~cydRbd~Vb>H#u3p9cxUq-^y zs&gsv>5R>@xxh^_N}!Lzg47-l%@WC!`50WsS1K%3`$~~ISFeLd%NHPMKP|+r6f_Yl z5Ros60P_F{CyM!~yT}JLlnUElUZ+=#RjP(QUt7#^-_F%|!w`tT?T-V1T7F1PI?5lj z4)AdPSv(s!@E<#@fblSNL%@78l4<6)78723I-~`1Im9wu!WuKp;rRcojVTrc&0Qxn z{`Wko0bGI%OVbWOAemQ28Kp(b)T_|N{&_d--*=P3f1GqP%J$CWGLH(`(ac{VY7;~I zZLl;VujXewWS+vDA*0yX|4hIlw8htUJmW+&U*&Ye{>ZYA0VoiA;UnQM^K-9(C8i{Z z3qjvqhz z^qTWg9K?~b;vf#p8nei6!2h4y850t)47d)?3zoW#=YD_dM<otANOZNrVhJdDYQqWwoJ%Agr+NE13L z;NY~1<5k!x`;S#sReRi96>CHW8fUT;VD`T!&c)Ifcmxfj{8g;?)^_|OIe-N<+xPINbNDkb&VM7pJ$RX(Z3%^miN*HK;Z-=G+jEXm}RAp_vgss48ls0B_L+! zZ8w5Q`M;Da)B0n`hyR+$4AgB^Dd{T&&g6}~5}SSHLztsv&EaCbldxPh7`)miiJc5X z@~U|8+VK4`dQ=zdRT{rKgpxtWyfhPn#=Q&a(v`0-SF8s4(h%c7R1RYE;ymV}_ zuN+(?@vdxvTg{s{Z!~fqQje_z88CTbVq#}N5gJ=3xp`lrYvp^^bn;#GFV0KwYNdumg_kK(oZj1Ra#ky14D za%Vc_=Jyz7U#9``K$}$;h)d^zR0Ce8Uk`wj^mfgoTm1Fwz_gkewl-Znjtxn$<|s0z z$(g5;!KPhzj+*B{rQbSNWs>!ed6&A*?1>D^jya9s>5 z5RtSyzM*|Ko#V3H8_4k_!gsN#v>RC9)2y4zeps8}7V%n}A&(Q>P1a}-&t76p{37l+G@u2= zA7umazsHwa_9yo%Eq~%6TM_@2SUN;{Nt!0TijwZUS9ks=cnFTl%_YIF#@vVY+A(_? zkYqEln%Wt6zPDEYk*ii>tbHzXmQG^?MSBc3SEw}J27M6w`s|yBb>I}_zO+h18GsQxl96p;g(4_#iBf`tqnk0Q z-jQiHQSc4NSh7{2t9Y~F82A#S-_}2*&y4CfHVhNrX?cRpegdm2RbZNR1; zGeRGyp=`nT*Dysb`i*%AdV-McCmzfhoCSmIZ#4u!#Mcq;^`;h-2dsmFR|O|hJ}Lr5Pjr(Sl3vk& zwfsznEI&t;C(JFD*x_$<2IPaQdH#a&>K|kJO}EGWWlN57&SvDg9Ku@e<2Uiu@%)%} z@duHD4y9e(#Xw)#VKmdU1Wben(+%4#%oRsGFp%{{32F#@uI9*-v+2d(<9YXDSSPfK zzJo=F8TreGf%gpmx!&uu8P0>=%Y?9FI;D zri#G_JL=o>v{>*{!51o;X@9k}{I<$gcd_86`w_3!X7j3q*tFFQK6mqJeKvKNr~TC# z`AYD7BQsx9b4lUkITn0&_>wlF_(BN`=_P?M0r4=p>ApfwScDv+j@UTp1YBGG`-fIb6Cm=OcC4`*a9OzPGe9EDkth##4M@^ly*pBBKRajc?f}X`T+_5bB zqpeoDh;03OTg#;mekx0o4%fH0^S9UngTF<@|LFb&Ej3??gcy)gCmMYi!@)UUZ!HYQ zS9YiX6K6ZbOq9L{O%+W2;@gQIOnw_AZv-x4{7>>Z;{3HKU@)YjZZUO>ul~q*Rd*O5 z_QJ^7nK$cUvQ8EDCNxi%TXE7bcGEc4=aCB%3tqH*NVk``eW~F|g~F;_phz>m^MP}pz}o)AXfpbo}B7M#y1R)R_s3b zD5Hp%{At&-wuroOT7dq&>fzQrjC4!>ZVDEI7##s39$&!XPxH(o(O%rthKo^N)j}MY zgK%Nwefdq+j_Jrc_iZ&mcpJ)7m%F|xcCsNglh;b?b8zo^qQ3=ZYH76#WZ#H-v;(uu zi1?5)-w~6!Hdb}TLKG(LB_SLpJz<1uN(ldu#BCaUa1MCTFNE~6Y`@)^1#*-T9;GL74Rqli(k6qGlqf)6t>?18lVawe^`?kvHmzMz4(e3#}Sb^e4r@ACzbBVkT_2D zs=iE%r7xj`l?^-nio8B2ZZk1SX3TqrZXo%sBY}^N&w51Vj>OdcB_Pgj0VM97H)muN zqHcv=uUV}UE7Yk_Xl$kh@tZ1P&D{Hm#xx>srCoY7Y^-r06xau%PcpWKpS%tif%;|| zsBsg>c^@cHXXk4c^n>Idv!8fg|8N18R!SOx>Nj^^@srwI({HgeG;5CmEJX#^q+#2u zED-zMHG?O53PCKZUKt)G6?FeiMP}EF0+;vMGzCDVGzWPqq?DAFlohK@5#l&Pl0eT| zyuWt+6WdYy*X_Hmzuy7Pk+=DiXO2@Kl)IQ2E|$S(_5GkgfoVnc5Id6bC7{v21JSUn z*bH$XnYOQu*7pI>j!p-6y@41u?bff!O>Z5p_bo z!aNc#4xmce{%?jzldMQUgnmEsygh=x(zXDQm&BU#NWh=S3{ZMx4`~Af1Fyc3#Fa1N zHSd-1dW?hka!!bxb&{TUplxXDbcZ$eCixIpmVlI<2WueR;8ZSLxEzqD9&>e3l9Q8b zc%F>MJB3Yy>|pa%u<@*aa0`1MmA7XB4rg?{zHE?cW4;iY@+vp!mh*?ljzxf_tSEA0 z1CUbtz^u?%#e<>?5_LUg&w3sL&LV|+7ba{7<~C#!3K#X{2EZ*a3@PqiUfNK2*Mho~ zN9!d1La{#kLxIDUWz9r_%Op3`0O>C9^L3HXcg7A?;nP5(Tn6h55OkM@4SdN4I<+`3 z1f2vf#yh-Jc!q*KKf2cS8+4mcrR=;ZT4b8<;DMvFs_tyu2-G5LKo-T^mV!-d_Dby^8 zRayWHZPmz|^3wg@z!ne;P3C@?9c@EeMBW^{$kB*l+2?wFV3#U`47P*me|?pj!qM&YA3fH!V4w&4My<$#v20(}j`Ck>njIDl)2R~cB4 zDoy8;*{{SOxcgy}P(SY$7pt0@R|_A$w6Rmk!Vg{R^LHbXY6+obK=1W6AE0`z4ckvK zG`+x+&3u!Thrd{6K?#KZCV#x3-S!wZ3QR_m8x#Mz?MSInG=?0g<2(B$)Hv${4RY=? zd(!YorHw8KY`=|&rg(qnQ7H;jf?;!Xhz}jkM+?8m&Je3sThfK16>61zW-*sdk(kco z>dhI-6j`6m&lEB*UuH4`7NEmYL~btgroh9gg-iGpDYl9!A|Kb{MYV_9e?M8;x-@?I z7bC**n8E}9r5TQtzS~faGA-1s%5IYU7!h`z=L>(fyKVviCi*}jsLu*>Als!6xFVl} zozEl>0LgO^OR8J}~yLH}pDMTe#F+N$>Tp|CzDm(bPq8?JkA|0w0gv_*1O0#8wu zXy4-<1)kF75h z1}O|$yLHf0{#l_8+;;OvQ4aIOx8#%J8N^Np4@8y3hptL}i{HZ|u#}KrXr-u)6c#TbJC$n}PRpqn0+k3jd&*^~abQvCyWLkk!Pqi_3!(sWI!1 ze4n_=$t2$qM()U1+n)i9(mx#IGCv^9&Ks6ihNSMa@;0*pC(GCktZ|#2n z!J=Ipp0ckLC3gu4pGdo>2#SVYJk$CWUjrYh(I~IQ_hy@Dp-_)yi-^;p!8Qtd7;tu- z7!0=A*NA&bR(HmHUU~(0%Z=9#)L0DUf=UVRrOo;5>DZ6YJcZxeQkw$sXLCJXVXr6c z9{c~&143l!L!-$rvh-~P6Llh=H%ab@Nq3=Aj5)_IgobVlsrpc z&!j6BX+D~s=Do%6!qK#A*^?1kIDPP=Or!K6HRbobYrEEclI5*$<^e#@@QHU-_rpuU z45|VUom?c-SmXSA18+FV*AazC4T<1-UOo&s!n>#E{_+(*X<8o0uFPYQ+0nM_rLO-H znpr~5o)NV&to{pr-FzZ}Z}6R~-I03}7VG2O2&)1R?Qy@-wfuL87dMmN7Q+w;UlYlf zuYl5FPL;I)?ITALUoorXHM?>JE+lb;9SX}rU zJP(IJG;7F-3s4w__EP7IhPQ~^&s#uJ&X1kaqq6|8c53--SoavC`NDgn?$uk*%H~fN zB|@5?;1TtICAh(yTwC@UicV<{wz>%-G9bN48Zqc?80w?gko9@7TH3vLXfrobyqXua2*>oWp zTkhmLd1smQ?Kq&VO}PH^ZNgAq=1-rO!cP{)=5dP@_PWe}62JyAk;Cjs-hzv-^~{4T z&=Mx|hu-Q=X4^dr(CT5_>92ophmAN=QqaJG&0un0QzaeGsSTN{d<~zV$RdQ!ue!hV zaTaUr4L8nUWuDT<_~wj&4uJttQb{9N{`}oB-fuVSvPOWyVXe#P6gXCv*+0b#&Y{SQwFkkMU?rET`G7sslvtvSR7_+URZtkHNR;pba=^RiCoxCM5RSYQR%VA~h%jmDON#k}C3*i7+(K;= zJ>xKVczRoT&*EIl6}a)W&gshUX^jj;Kv@5EaV{A?Ciysbuk<2BLu&&2{j*-N1<;A) zC%tp5&M{wm?Y4q6fLLT`jM7elfh%v$rNtisi{xMIkxN zQc4j~$e25R8_1^r1>g548>w{VbfM&W;d9r$zbO)AXQ_k4j3rQ2C%s6wO8BJ6-Vcj6 z&(45#`@1f#u3h>sVy^!lt&{Y-4)~^%LD!aKot=|{P3|Yg%DSw`f}r9n%O()jL0Et8 zOL_HYJiIQ(gM`KYc+%HmQQM$zZeQhR%qXnc|9v}~{Za>6M=VQJE4fZPFDm_2QfM(HAVc+< z6CHd9Yfj+QUVs#Z#fq8xCdJaen}1@q!1cnUxidrlVQW<5;vdL>g=t{ITS$URH|ozc zDq}^0=)dkTZiSuQcia3SPE@+i*^3GVOr(F*8|NYrFA39kTjNXA?D0K+B6)?~oCIS; zOksoUU#d`S{P! zJ^uS~7+A8G1tN7h87rz218my#{Dmb|Kwn=z1hC{HX}pORX1{on{}U?z(+Gw`-FUMM zyg_5E>|)6?fvpT0`P161x0;x3nDQ5CO$QwUjbK_sel5fd(cYblA-W7Y1RBA#<|l9V zC)@kkUl;*{3`*ww|Mf`{ULZmtg{M<*dWHSEc*^ptfV(?WTNPH(S=Nt7g`W||u<7eH zPq0`52t&24$(jr^U5gdx)_(zzbgUHA^yu0ci)Z!&XX`Z`g@l_yMHIlU36UBi=!{g^ zNdv*!R9RE~i>FG$K>Z9Kd)x8axEeki1?;g3Yy|FTIKb=JULU2SlrVGT5B+CiL3O7* z_3U>7TMIdU>e;}AaDmNl!KA7-YjUYYh zwb(&)PxcA}BNXkoL)D0kSkACzo=OA1uq3+l&x)J6jJQQakmU}7-lH~Sxw5s-cLwU* zHS+Hh11abK4d{89tQQ+??GwXqv$!03qulN*$>z0!NbD&M5Fe42iBV~+z^r#U+<#V7 z?-g`gcT)Nb5JfM)=bx+dmK%KV0T`h_0Hrj<82`uF*|{|c!7$I}4$6vhCmE_Z57ldwR(hwkxw^Q%GA zL1vGW11=!*{2Lr)x~hYCU{Bqm1_K!-Og_&25Ng-70Z1=9zwl^#?QScBxa67`D!qYB z#v532^L`A1o%ghleU>zk2p(G2*$i^+*;l=sMMv=I+K?l`$5kL)>$@v$qk;n4j}Yts zcsu<-AnRPiTg6F%3G>pLf}tbMIeSW;Y=0Efn8JfeN(CLz;sdh>1-ux9eGvAj1RRke z0cD;NfNiMkBu3|6!k2);$QpT6?&bV=3*;p*z@sGi8^!=!#>XHbsAq<~?+EWpL0VAl z!3sr%5Sn1EJ+UJ~SQ;e7&oUgdGJ&KA2`eff17jLgAow^+P!a6^;DcG3f)|#5*za=% zo!o$HcmmiN!we9(?*}vsfH!#EWvTxah=ME_zN!tF0dSW&NMPfA)=j05EL?H#d*);C zyEKU@VDJA!1EM7w9}bvIX!v!8M*H5hd;Aj4yDBDhb5@794ZiJTJ`w`!#F!?Vk_%fY zpn^eTyOR?EXNRe<7of3+Tl@u;w&Rw6&{&PUMNo<=keqT+fR_L?X9%`5uGXXk&<4kx zx|4(W=BiT4cZ1B+a}=h9!OJx;M)2P_{Uf_ltZq>A@E08bMaz0cz@Xm)H%bKQTkP+b z8j*(m8O8<7Qx+IRwcz!oooo1ybpH(9U!c|xD@7UuY&NPQp_pL@#}quc6KaKHh(KDX zzKxsmyW;=}sG$Q{YY43_kjB4Mmv zJ7z;0%(-+7IJK4M@T!S3s9`l1Qi25r)H#cz>yhMO3HE^Bdt^ryg5Zwn?rVnUP~iJS zzcj=8b4mDF^US>0C9Ln#@-*V5*;%VCgP49J`=o z$*K*zaff5i3XePgzh0#)5vR3`x4oKn>}i9j6x{IDM`XYf3=Bk~JRdIpTeON`slW z>$aja5Ol2s3pP?e+L7Y*D=d8$&_V4F@=n(pRVcM{EiTbOERVXF3%K-OtI@1U`b~kq zyZ@`#VwokU9RV zM39fCjEOEDZ6Ubm`ESp%@->|VopXS&0yEG@(5T+vR!9}Q3~FCuZr#(RZISqk-l@83 zH-qki{}>TsjYs35@bx3xWb0>Tuv_%&@%wUBnT%aP;qx&}+C?x$&;8FKB|s}=*7A|D z5p3sE5Br^%=qGpxg(Y&A*Ui`x)COM-^CmVk{6K}i5;c&+WAo&G#1yRKEzifbis#hX zk)|8m)}=L=erpXYR-R$QO}7J$_okp}@hxzE?RB>xwl<_@zBDQIINZ>@RJ>1w)IJL} zu`i?%tq3-s-kC}_B_j<4KmqhJa&iMi;wKVvVN~e?6K?*XmgYU678I6c;N`1*Zv(*5 z>Yx}@F2KE6<5#|4d{K>ylltrz&aq{}%kmOK`SUmkR&j=2C=YAezPGI`fyQqznWpRV zhPA{*kOIHys!1QVsjB;L7)acH3S8R>i#u?H^I0KdRuc`t)pR2V^BHH>H(U+@qz_o7 z>`(mv{4V`1Zv4dNjIE|)5XoD>TpR=y8w~)APrW>3MZ{+jnQA%MF2kf~ma+OH>aD!+ z4h)|;6MW;x|IyxCMpgYqU88^)gmjm52vQ;)(k0!9bcYB^hk#PjttcRkfHX*VD-BXg z2nf>Mao5rR^Wph^?}z)2*P%n;aL#Y%+H0@1=A7J=WAC>b#2^1a2jYc2oNWg`A_IfO2axDfX#*M=5RwhP3kw9En;kh#W>WG|nD2JWO%(gf%QHu0Hoz|v_>}?~(_OtXdZ@qEZSDb3 z5-as4h-SRlo)b@N*@oaN%ADbiZ7e!7iT*k~Zz zBgh?~f*S3yM$RL72;Vbo-k%uG~5E^Km-fHn|HBa6)EPKSad_B8vfme|7lP4wa(uxD2;?cXg&B ze-zb+?ANzNlfK^Z{ESSps)ac&#QgCHd9Xl-1KE&b%o7pMeR7^m90mNWl1P0(ULXyr z8=@g$c8W>U=sM>m1e?N8Ziop8r2?_cB#ImYuDsghvBwDY_|j6pNQj^hO1;rE*L+~v zRW;i3KC6hKdrMJiK4@yZbc>w$wyntZYy{QLWeFpuo4yJ4`A*lJKY)s7Z&5uHl4Y$i zsCSQXUhJk>{{&UWA+640H!(?!3*sEilmu#5=F=w6cg&>0BOdHYc z+>n}k?D}=Wl;1S!VCHk71L#7e1f3zZLOvHANaje??=*1>5Mjmi4j-R-q;fdjPD$yNFfTOIaHs z-i~0aYB7X;ie&h$IWW__2wk?CB;4I8P`e@!_Yz4ma*(TDKo*m<8J&oY`D1YITLFFR zJ6wx4>tNq7=1iYiko@v)1-`Ax^~F!~kgptpqWAd{clsjSwvlCu7K1YL(C)ey?Df{K zbDdH^SH9cK9lj2^%4k==8jLEjy;YXZxjwqYtHoXA1$#ggEZN1%9$ z5!c&XJ3>_kdbYWWN~t~=@()qGKBq5Y>WIk5?(+PSBj(6A)-``-hV;1h#U~{(!-*1` z5yr=;eMz6p4L^Sk6RGw|<^J6|(q3=$|%yrPwKfp#=v)~)hE1BK-m9y@mwKQ=6A+TOw!YdqSJ#l4FC^( zR!(hQCL9o!9w>=uCfNi#2yA?{rm{XKg}w8BC`8A^pJhwp7Gk?c+0=TC+NJ$=(DG!_vMIE z)H@FHNExOb+=FEn2_2O&F~KXpI_iL#LkO!lj6hz+e)d;K0<+7iz>7sWk>Cy2{q=P&Vts7gp^!kSf^TG+mm>m@U6B*_!vWu2?;ZT?{U>ga|g8 z42NaUl#P@95r>lOWpCUW=S+^yg1BSvAQ_*fOIr|g{4yU%E0c@OaA)9cADhG z8QbyF1!cIf2uMp2;Pv@zw;a8gYjy!f_PY(Iwzlul^o0PX&1;J6h3iyPqg+>) zz~7bwiH49sy84Yr5Z~*NATm6$$F|rs=)o0!8ugsmW11pzc;`DeK(;f+3UtNqJu{m9&2AEu3o&k-R6_4d3G?VXt zM!v8JdpGzs(#spZaBq0}Gp+r~vhVI19;V|D_lF&CK4+C%k#|nYp4sW*KV8`T*;RFx z^GHD9?8qo{vi$0+RYXBqu1cDQ?gSokgSVxNUO9o|)7SFyf z_3l)2U0x&fcy#mUqlPpLaXy^ewQ$i3LH-qoG9!%Sj-H@XIt5yjUQ14>QBk#K?(?^3 zmWiF|!)StX-;%cTmvw6tH&TRl9c+)@mA&F$j*J>!u=x(0Mem8qE&K3Pd#QUy+TZ}j zD?Yj6x?_3=PlfWidE}8X96`mFzghHjMp~Uh?VF-###?ZuW>A9DH6L#jGMRQi{CZ)! zvJ^;nv^7gCkb+qSM=iePk2*J%W`0>BkEv9X*lF{X-xugLQDu)9>~Pzvo1>2efQ%%L z@j`|o8$q>@BJlkE@yycKS$wtB*1)7tx`SFbj+MDL@9swdaa#>DM3gFC{Lv%hHW!1M z@^Ee|WrdO4y+h$o(ms9f9Wzseid7>idP3+lk2XbcaoggU9M#soivhv=5wpiGPO@+f zLBpQ%H^U@c+`8-ET>s$3F%IVRVR<$`Lzfb4V1Y$f9j6T{v|8$|Hx*?9a=o7K0}Woq>T!&ZufKhcn10chHhh-f zXt=aW!pNE7D_x)&O+izfBN=q$rTVZ8aIk>3;?^2%CfCNfaf6AHe!;FI6<+LmHbcwIl zvyHW;wjQ0~X6=LBIG_^WG!k$<*Jkbe>WiaIe9yBDEtE?V%rF8y7yBpJP z5w_zqaxc$!xEK`T{c7E2r3IYniH*Az&$+Eq73*Bba)dq9J3Sp7<3O>u1jO3KPj|YK zQ3MYNZexm_&^NU?P&~NzMDTv4-O+3kwa&r!f-j-@nmzJ;@0)&YFITU+6fMlPkn?h$ zua{HON}L^xTbMpbxHm04Rq=_e;ZXmPV9=hOPL+V&pDz`;DPCzu?4Y74r$)ml zmBJUF;WCj>p_UHJhJ^L>r4cYTQ2s|A|MyxLir=+v^Cbn^N@jKH z0psp??tmdM?}^@~(2Y0razOjpc)`LThZA>AuW$mLOz6-7m$X3BhSFvISP;yv;(pg1 zw>;~ir5Aga_nlJq?5wKa34N(Y`sy%k3rZ8Gz#fV*$DeVuR?KJJPjNKTQ%JmgMacH{ zyEuCTFubcpC*Bic&9TF0e6dfXW02c_q*#={h&y4{4PO2s%!tc%mNoAE+! z=(r3^!rd-w`8Y52N{-%HhFu)MLjLwL35Mr{P^};sq9f-FDU~oh)z>8Ze~whWc3Lih zdX_hRd7m}+BZ(Vu+u-a8>A*7}Avk%Ug2tpG8U~UT%>99kbh4KUT~V?lUuHWClb2)J zCfR^?RMK|*=}n(=CsFeHZPVBIOc|dXrpNQld$h1>qA1kPR||$w6iA7_JpC-rQIB(9 zsaK-~u=0EkwpUZ6m>y1#-Vo5h)#7G6kIlC#DNh9hq^_6&k3Hp~(*vy^+Qejnas3}` zn0GNY!l*deo_JR3@@SS@K0V#6yLwSs9F;r2x1`9BQELEf*4)E-ibj=QCri?%-?lSI zBk{D0>b1`)1j?#k4OFU9ozd$?7XrnKdL+0I`+M(4mA zQg#d7(l0-MvgN)5WHrH}vb*_OU!`B&BzB2*9{gz3j;?n@&X6P>8Gjjvo5Y!?#Nz9Q zX~O43)^32T4Po1C&wXh(MUA{GNZkL`jFU{Xp1Vui7^dC)0fBlpOxE=dF}V{ zb#-V~R|V(|kZcoT3h4J@Jn=?u0|uI5|7&+}t|&xmp$0HcNSnAGRR8R(us!ReEk^TR zRahvxluAs_SRqLc$bN+BTz;_7YmA7%1@$sMy@rj1FT{uRWJJjD{CbdZhe5%28L|iY zuO~VKF^Uxo>yI%hMGc~!{`91$-bykub;fKu{uQDd-g@FwkM7a&Ml9q@*ZdlPSM-;n z#X&ItXP!~1YH&cz2)C(Nm4+Na!V;6)6^1)iaS{W}c#7T?e8v2~SuEKP3t~NNxg~=f zZMJ3vt2&qti=X(@6kA_{6cNURdET#27VH%Aiw68R#;O$zjJpdG1x_c^CEreal1#X> zlBy7;RhM;9VNP~F{plL|LBv5!wr_KNayj(8ZQLkI{!_`ziyo%OD+xO4BYw!z6t#Z} zvpJ@K9V|>C;f(5e>8E^H| zu~k{8)zGT(EFYnBx8*gFgLh*^<-=z`!W*GJWT-%V9iIwGoM0MNNzbPK1CWc%csZto z;O)vx8@Rt(R7|=Q!W%fL6f^i1CUQI>5{YTsHCuX*Vq@V$Plb($5MESnzsFaKMkacC ze_g3x2E|_vo%??m>M_|*UlV9L%rZ2pTpP8?ov!?tc%3s15kU8Wilph6L65N!q#3D$uWg^rJwZBV`W0Q(uW?H@7Ql0!>MtHANPQa+gS4!7E6Y%dsNQ%J z=#`qXKItuks}4WedT+wnXyK&xn>V#`F)<9xw6wpaZXi-jAN>>{y`Z(LZ4VWCf037Y zfV^b;OS+rf*0NgbVw6EIkEcH0`jy$|lpdINc_263)QWhpFqDL>yi+bSyv`XvcE3bX z@A?ma6A0>BkLKZ(p1S`2<^Yd-*b!!x^{Yb%5ZDKzn87H2>mx}1)kkooqii;pI85sR zTSO~w0Y1IEzw_@$PrW`X37Fm0lj!>Q6v()*#5@`{MEy%=|48fl{vt_^LPAJJ=6hsJ zEf?PPAV`w@FRUgSA;3*t)_&)7Mi^D;QR2n=!Qlh|^1&!X3JiG*k(ud#xYz*i~{6)K}A~zJoD#mw9T}RK#0TYk`3R0@YhF*E{ zap#)AhI3bs8{c9e^--(g-{yY&-$gEXcRw<9MfWWy^n(4&^FFC8^(+To*i#V5!8^ob z6h|brkb*2JU^U$LB=q6dM63o)UmnQD`L)1mur9ggZBJ#qlId4XiO$dJ7fjoU3b83| zZKQ#Rl@0&pZvH>W?-_^?U{lqL!`(SlIqgyo-NwDCJxX-SzFOpeuI^6_&dd-U;3Yo;usqiwqc3xSNL9}Rk%AbD5Q8|Q3|LJmHA1x;BNhAFb&-^A>O}@UEVLQX zgA1>)8*{JSEE)m->d%;t#x&3Hl*i$EP1`|gNcSZK(viURcx>Ri_gnI=sxjACQObME zZ_Ep2Z{>Wy9LilknwQMdvSJzgf8t0OFaGCxo%tHg2%)^Dcm)c&dZ$2P^`rCoiBBWSJM+3ZkBFkq)>udmx0-;Y(^JN*Gakof`Y23n zeZ#2u@e$KblU{jmEovJ%AC)Q?i9hR;K~7UPFK?ekgIMQL=|&@qM&$72#klq1y7SIq zLW=;KeJIito1TP&OLhKuBXa!-woDs%SAlb_kvxIw#3rMjf@o3)U>WY zb27o{kEUTcSUa+0OM?Kt@b`nw*B^wA=s)W{PfcWxI8kp7JUbo`!@eF*DWY$5++AaB zoELH8b(E?)UR1Yoej?PWt>fCYrbeE$1D^rzc@$~W%;AFma&jT6D zlw_Vs35c*VMIP?lJc?(@MmS+l#{@lgi7KC7&^>ANj*4Z%PVb3R91_|x$8)j9ZIh4l zrHk|wao>*b|4^fJ?qBJB;zet_dvQek$?NFJFUL?khL7Fdv6_{(%E&J;ji#u=rtBh{ zc^qmJ5Z5+HAAC7}2L8PppeoydE%}}ahpbd}g-!V@Lk|W*mo;tGia%JGB9%#E+cntz zxUrRXS6Lqf;xt+UYyvky&^5O!DoyS8H+h@WeQwiNPMcR4TlV2!EMjk_t{&`6%tv(VBkon`D176EeoJ?7R8H+y^>K*OJi$e*|?}&N>F2VtK+&TsXB6cTyyB@|c4M^aMEQ;2#Vi2b? zULJuUo`(0q)Oed2BOBZ2W7Bl$R=t7Vgz?ZFwR}y+$6_fPLuP3gBs6SWN;*7m zIFhoGnTLnQXSat4nTSr7h&bjA^0harZ9yk1D?=|=QrxtM-rc|5@xm^K_N&c8XFduR z$Y;vJ0={fI?7t@3OM9^pwU0+F)pCnDT~UMDFI}OWnuJzb85tLcUsyO$!MI85y!k9szXv~4r~`89=@U!n0hZ}!i{nnJf~>+H)|&Kfd?011cf}sywj*5z1iA^!EEAr z^z$U1IZ#9+hbK1ZcALf4O!-|rZU_AZ%|O77NoUJMbnK4l3@P}DUY+YRxVo)dvxc-2 zaEQuIhP$@5Eq8za%%xssKaYvlRkjcCvdT2d{owW9 z#ZfS`$=eTXR2RFxo0l=1iLo^9o#B(2Z^i4avPfD%ju4&7@tWK5`chIsj^2}CEW7xS zt(k_{t~K?7@jC9Kdw4#l-uL(%84GsipVV*2NBQ`h2Xn|pkllNJZ>SDK(rClIN%TR; zad?$|je+m!r?@qSv!gT}qfTB2+syWzx-G_TVk1yVLw7WB|1*61U{Z3C2xJ6@?Sh-Q zG|Co*^~!S+G(V}2&MIEp^+Ip+GyYbkz>HabTZ9}-8|Csf4Xp&W7{%|Yy$ahgv`Qu{ zTxzygj0`SGb-uHN_v0HvjSSDFUP9Lzw#pEi z*ECO`og9qEi#SULZ$_6}6@Ln0RtQ87)6`_+;VG7qVNZO%e7O=;I@{}G5Pz32<50X- z7IUPGIEK3-@V&V=VMuefVw8fncW)}I6x!Z$T6#6D;6XQCN48N@eD`d#|FqU3Q7g{D zFCwyYs_PjPv{;HU_w>EfX+wZ!338(Bp8H?VYU-45f^d>?63Kam??JBle6?*9m4en2 z4b95pdtpUVoMMvU$BcrItlFe-bhul+loLH!EYU~l1E4nLO2gmDvec$ zZK*}jU}6yWe?BCUAo*1u#6jWyErjy&_pnu}-aUt@cx^RbR`kGh!uUSBSFMA>RfUu3 zsOM;HOsTp>iNS)G`1s8{{E}fDsSCX1s(UMe8!S&0)v?1I4!K#*? zq30j*v`okS6;yF&bg5#sW~Z&0!`^lH4wKq_|uCuZ1d*1ikiVPEYqR$hi5n zNS8_q@0!%n>46F>SCoa&k*|l?5m8VG3Gv8nqo}lt#GZdj! z-`c$2_Vj2x_czH_w&D7u_niNU?Kkqh=CK04r4+Z-d=8z>4zF(u4Mx5m>JFqZryL9l zS;zDuuE*s3A;yUuMp8F0<>Z^W>QqURl_q|ivS9WteVw9|Yfj^AzmvW?)@Bg5|Aw&Z zIvQq37LBRWT>w$Wgi&G5oQGoA7~TJEur1&P&wNEtWyBN5Z!p zq~?BL&`N=5V|;tN-CfcSoJSLqw@gCvRuwrMH1(=F4aL_f+t+9?za|;&dr2KVjq;qo zc`H*bb2Yzk*hTggx zxb1iBZc&FU0jGl?Qgfg|lKeHPQYhL_%w#1sAsmJ< zo!iOuTIJS2w?gNg&*vx4^OaU~Ydh}DS*0lnxT26&g^)>vfUlFvXku@;_4AAsw3Esp zVPq?S;gvSbTJh{hr_dICUKYx&w=r~Uc_BEwKgEuI=%beGzR@yCC*V)pM1d669W4Q==cY znuL-!Nq%QX<-{{C`4(wWfA6uc+SP2Kp8UzlGOKMGRaxxW;m<7Y#GRWBE^EWwzTP4U z>Fdz1Z27mae{x|67RP$NZ=rW7WEo%ZM3M8Gd=V@mNcmp2nWq zy#WLDTBoLGtcv&8f{!Q@D$n6M>9PRXM$PoAE5*MDez?0-r4tpMsL)Ig)28SvpP6C~ zE!$K!g9!<;2fOF>G&C4P&*{^szt%{F)`%wkj=2}rkaWCGD(WKEh2sE{2$CC0AP6fb zo>(I$wC(ZmHPw)`_fQ*g>U%z~{G-6&0WHyoD0t}WUBsETW5P$V$qz(ewxqu&d$M4D zp8uvzA=Ml%kNeUuM%;5HS_G>b>$Om6eGr4oR)daz-gK{EeN@5DrjGV$=uwUfRXT@B z$m?Wo3!=Pm$90AdE^dC?u5t0Na?KB=2#45?eih7AtjdRd`65DE%AvYWjY^Xm-qu_C zk^ooFdq{leY1i37rVK-#NOlN!9dXF`?h9xssAal&4&_+B80av?^*_OjPwWA z&|g1`za8SA5hrnoZ9X5Mni5|m?U8~a}D?LZ@neO$^9GbT`J}h~K(?K)Csx7?Kd$=*V$Lg{cx|7}BK)K&>cEE4i z%U?cHSFEcHQN`-ozD}c^WsRewvofK3Lh5$pU(Y^27Bkk9;a=x7!`kmkY{I5MMsI5_ zHCLklcQe`*s!f{A>ikj{heP~PV8I6stuQB;UA^UqyM3?MH%h6KLYdVhftgIL7%M7*0 zS_Gduw=)RSf3A|C-f6!Gq0XeV-+K14p{bG1He_j$O60N{Z(!DIc+bnRZe)*YYutFi zzE@PvFf@tOSJ?+UFkM4r!1ujOGp31ka%tgPR5?FXlt+Hgjs5)f4JZTCJDMjAw(;k( zNX|tqvE}_x)tQP+yQ z74xm~E&7KjAFdrxT_XtcJd6519gV~!O)eP77=whSE93Y4qeY&QO-Sn?L1E!&4=O*4 z;N;o55Lz_S^23HMq`>r<%gh5_`eyl|Amwy<_@qSKISOl1TMe=dPM+(mtS;Qh%5Rhp zMbDH`=n-Avdiek2uAFj`vmzmpM9E8uYyKb9t^eDV|9AF{-&vNm6H!3rx!zOjI?B6|#F8NjU zW+4sSCezKO>7yn5&g}T{z)Zm37Yy*Wf@SM34rr<*Q{Nx(gd=_`*Nlz$U|hUg00U@4 zx@O@5+wkvB{K#2>`GDLR9bV3LPrjf>#-sM1qkCvV;w@?sRrU`2L|!4kKCl?jVDn`7 zHfLxjf`0BjQXq}&4a5(l{feM%E(a7FRrlaSrfY+Oz$(BC$IyXp8VM9+M))-2kA;!{ z8p4f25R{m1DX9!EuMnt|ry*K`;|-tjY9M!AjTiqT=QqonB_4<|p!R=+_?AboF$UEe zzFO=?{16#$FafMeQEKMTD(J2C6?}-p8X1|)-`}1KhJgsag@*bTKF!a+Oz>YrzQTm+2PNMY2!w`e2>1EM!jL@N z#{I~NDVkO$JNd}3mGeDi^KUTU&=hVZ_;zIFSO#w!zKW)M^>?Hm>cHb`JtJMG6X8P~ zo=CPKCejb}90vvhhsOUA4!`UATPbO2d3*c9`ok$Zss~vNm`sn}Qk!*#$2c~g$S5SS zr-UY+5dCWt9w+oT-NRn*c{INDa8{`Ok7_juNl6P}RABdCQ6!PTi6r5Yz{AI18j`(} z0HwvK0+g;%|C%BTO%e2r;GGUY$_N6wH}=Pv{u9MUV&hj4cf@8GZbe)Pd+sx523BoT zNBojR<~Lyxu7B+3eHG;AHack3MRIRnHl&H^ z@7#7P!?Pyk(;RMI_urSfO?nR#-K`w|?;;t6p?@{iu>OG%b(s8tdBq^QW6ABmo%1h* zLHUL*(wKzm%QVMf+igt~jQ($RV!@kSw(%S)M37&qNy=b2Y)O#G{hd2%TA1D&^f=Tg zpQI7b!7R=$Y+u}+>-5pSC^Lu$jSNHy#eeI%1|vq6;vp!omEVeX{1OQa!8gr8TeHkzn)jgEZOgF6_oCM22CBFs+)-nIFQuC2B7M*6a2EvO zVt^G#0PbCINO-(cOW%zu9Af5j(Tb!)sF_L z(VK%3+R}fgQB zU(HUdNQN?WjJyW**(df$rgiZDFbF@RxtdV&w-$yX#%&*#C-_ShUoN3MnHvIVKv@z# z(D?fGYdNS*Uz)T^OMs|`f~JE|GDo-BZ|nft}cpim-T4E0c%g(6%?6 zbh%4B`Nc7hvX@%5KQaL#ji;!a8;tC6ns(QcGH^j@BVyP3#Kv$1K%i~5M@I4_;A{>F26g5 zE_i=+Ofgh~f~hS7+aHRZdOwQ4G6(kR0G|vQQmAvmyd!Fm7CET?Z(Pz~4+wBRqVrp! zjuh0ZcP}l70R2Iz>cgn9wu@7JoT z(lj}<3ZMpgKt?do(6m^v#u7#!ym`;7yU*n3^(p2-q&aQoXrZ2lHdH%zgb|N7y;?^` zyqiB7Z0fa?r>;pfHvq;UF96&`1uW(?ba8~in&qh2$P|%3p%~YNvqnuJo|&dV`*SR) zDqdHSoy12p{n;&8+QIx&`A?~YTpytYK#~0?MjF(Z3cvC#-GC&dvfiuH@ups=v)5uO zbt5psalfy$efmL!4jJzj!cMmQ8Mps420CJ>vI8VKQzktmie186?2mt#cx39TcMfwW zzEuP2{X<&l^0f2g3F?1i{u{>JGLn3D=@n8ULCj}cDRe&28dXzMGhd=cf!&e-sz`OT z!9XSfO#N82%|(dg%Wnoo`QR|kp)iflG4;it;SP%d0P`$DNquF64^O)w3J`WC0i2+Y zto`=g>b{_VJEHj#-nOwtH~skd;%FA5OszCNd>GhzqUdbxXOYQBo}uWf^FFO+QT^z* z{xHPjfKm>Y??baqhfA6WRLPW#}Z<>sCECv~o9?MPwI(Wp;u84>v& z&)>X`thWlg=NUWB;RnP<ZA5s9Fuk@3$y}UA0)Zz$sw6#f;Dr7 zUG1_o-{^Ce1z!^BH|PAbh};UWJu=&mJ+V>%c%gYvlK||4s*318w1hzwAVAg_Au{0N`oHCHD9%Y0r&zDU?mrk|rF!^p6Od zG;RPXq5OMK2@9;7_kx|9mh(YjKNO&~ZN_J3hYl=y zWm)H2FRwJ3S|>uo!|9p-y_XzehSD`&aH0hhUHwscsh;DyHS@&s+uQV4lNDU=Z_RB# zrwE8d*hxh=j>>!RcoqK|@@OJxb!5~dToO>Y$0XyCYdHG+WhNF>1}*bbjXg%1t}Yy1 zIJOJ*%2B2mD0YVPwO9oJ4)$=ZvX(nM3UF?Z9|&1~BO&E9_8Vg?5&7E~{}*ubKe|cZ zxTuW6(Xb!Os=yBb->9|i58W7Q8f@=w=#vC&01w5d22Lp{QnMR@UEle4@LNT}qg|1J zolmSX`K{lwFS!Sx2nkvM4olzx;F~2;&MZYpB3QhhD6vas&^3%@N_CgGJQ;Xd8#yE1 z`2Z3h^#$q+Pgg*;BR_l{%yF%6Qgk#m*bfcdvg&GnkB!Rl#ldt*+ce6I0$|+LF80}K zI5I!po)35|5gyQvxjrcs#CP~Bf`qH}K{1#YzW&L|DB*q{*UJaBKfy(Dc|Y}rt<7A=6rqJ zIm8Y|C;@o96akolFxj%-6kd?KF)Ub8EaVH{6OzpQ+o%vkqe`FmttWfk;Kt(kUO6W^ z3p8~eQYAQ~-luS}Jy1!4(Lp-_C zt8dK!4x=SFEAsu@g0U4refFE(x2$BEQ5=7AI3cFGtl}ZPSzuvKA76jI`&ADwNM2sv z)?bN%$2=Ov6dstj*S`1G**tu2Ew#Fsp}qp+rP9=s`X&m^an9?uB3d z>~3$Ds$4&V9a6B8szyzM5U=a5muc^xRd?3Mm88$AmeqliyO7ojWFue11D$Tmj0C~@ z1A}tQ2xZB@s=o%*49u=z=a~P7HNZG5;55r027<5}Zslv!Z)z&Vk-!BolE(N+7gXKH zAS`UKf#2>c$;N6{^F!nW)n{|8Ac^{f{+>z5Sr(0GL_oHkR6k_H@DsKJth2p#(PA|L zHklWz5@5qZdd3zL5svco3YP0P7k0b<9BTrwGmlIb-j~Qe-JWYfN5!MxHs}f<=P&8P z!4=M=p3DTm$f|(^+r_VEmh@B9XH(3&rm5f#1alT@eu_ni%r>-7n63C~Q6Emype-GY z8|h4Tb_WH?!7@xero zTHub02IjClUcfjMM`pGRvCFjMn4%9oVr$4Sq&#vCpy6)BWsvqi?s)#+Rp|^aY87cJ z6(!an|9lspn1PM$QOS8Ss}B1;`y<|6a5>{&o-f?FOGC@UqY0?j%+!ThW&lFPh{2HC zvXFY+$jr=SU}Tg*fb5nB(sYVn=}MX7T7Ylu46sZFOs7VgvS_DQ@*uYwkK{ruZPpd3 ziYRRxsm+!yGg9hk}s3+cYvilj>dkBSNg9z615^Dsw%n9`V4CG7KdX z7~&ThDhB6D33vBW1u^|sjSSw-%C0y6Zqa4R(4jRI8K6v9s)C5GfY)JRfFHS0bb8-^I~{SoKRk>g`VL9*s{}ww<-JN)qb9%=kV1{= z@IWnDCXjdr_B?;D8f6n~9QieO{>+ykD|+eCUBw$@K9DV2kM{@w3BU~E1WvLsE$G7_oi zl$^&pnx2WN0R7o@D(>%alBL$5pRoTsR_)>GZ|_aKs#E)c{{t>A0^Y|Z1)2O?I93x} zo&*MsvKc+Vi^>cLZ#NeUl8~v4_+iIGtz00l75x>1lH#b zyR?kV>gesMRcWMvCfF{{fM1Tv+lE!z^XBi(>!BHpGMSJH@d#k;SpbFod_$~mt*8!F z@hklL5*5#r565*WKrdT9$4?gGWhO>*j&=ud&AR0?g9iT=>fd+|ej*MqbB4~%`~cOR zx+x4aG&R!2K1V~vbz{1Bbbf7LW29cw#{s&$?rsmLsMliDfKcGOg11}$d1r*+ z=RB^VtBw$Ou@c>@+)2fA1QjrPq`;}#-rkPNhot01OiavFT3YH1wDD0?#xLgqI(+@o z?BDp^!h)`}%*%fEEOp(`2U?h@hs?D}aBq+Y<>qYQ%Ecoh%F#*-=$p82)!z;7k~v(f z%3faiMs125&%IiuhO_tm&BtFR?;!g1Oc+|zh3&tN>}RITsFa*_NX5v==t&X-dTF7N zk%>^6*A1xse!8b@&bV02T@DZUwQs5YMBGCw!XKF(7XWAPeyFsl$$f+kFn$1^RuEb) zf{n7=pAttS8PpBV&6O;*|^t%E4(h5HsIk1YZRt^Ylk855oaz=R8(b8 zIG)tTTUr5_Irp{cSiaU+%Vc_b`s&azSL#i#EQ}Z(wjRl2QnAkG!kg1yR6-vfO+LQ z`k5h(K}cyoUPKv%H9YyQA_cKD%jCc?g(01|+TEgOVCVsMfiXO0-)+YqJ@yo3_7Q}q zUr=yE7=Gzj+J2h03hx3!b{W~ERn!>eL z)4KY7>_VTd$8`m}QWejq&v501ff-oSw8Xe2K>KYw?>|GrL%)4xJC`ZX{AOn#3I51S LD@zqg7zg}6b1C6q diff --git a/docs/src/parsing.md b/docs/src/parsing.md deleted file mode 100644 index 7105e33..0000000 --- a/docs/src/parsing.md +++ /dev/null @@ -1,102 +0,0 @@ -# Input (flat) - -An einsum specification should be given via the `ein_str` string-literal -or with the `@ein`-macro as e.g. -```@example 2 -using OMEinsum -a, b = randn(2, 2), randn(2, 2) - -c = ein"ij,jk -> ik"(a,b) -@ein c[i,k] := a[i,j] * b[j,k] -``` -where both specifications encode the same operation - a matrix multiplication. -The `ein_str`-literal is parsed directly into an `EinCode` struct that holds -the indices of the input `ixs = (('i','j'),('j','k'))` and output `iy = ('i','k')` -as type parameters, making them accessible at compile time. - -The string-literal form gets turned into -```@example 2 -c = EinCode((('i','j'),('j','k')),('i','k'))(a,b) -``` -Calling an `EinCode`-object gets lowered to -```@example 2 -c = einsum(EinCode((('i','j'),('j','k')),('i','k')), (a,b), Dict('i'=>2, 'j'=>2, 'k'=>2)) -``` -The third argument `size_dict` is a dictionary to specify the dimensions of degree of freedoms, which could also allow to provide dimensions for index-labels that only appear in the output. - -In the next step, a singleton-subtype of the abstract type `EinRule` is chosen which is later used for dispatch. -Subtypes of `EinRule` specify the kind of operation and are created in such a way that they allow useful dispatch. -They are defined in `EinRule.jl`. - -The possible types are: -- `Identity` - operation is the identity on _one_ tensor, e.g. `ein"ijk -> ijk"` -- `Permutedims` - operation is a permutation of the indices of _one_ tensor, e.g. `ein"ijk -> jki"` -- `Tr` - operation is a trace of _one_ matrix, e.g. `ein"ii ->"` -- `Sum` - operation is a reduction over one or more indices of _one_ tensor, e.g. `ein"ijkl -> il"` -- `SimpleBinaryRule` - operation is a pairwise contraction that can not be reduce by unary operations, e.g. `ein"ijl,jkl-> ikl"` -- `DefaultRule` - default if none of the above match, e.g. `ein"ij,ik,il -> jkl"` - -Since `ixs` and `iy` are saved as type-parameters, the operation-matching can happen at compile time. -The operation is chosen using `match_rule(ixs,iy)` by testing all subtypes of `EinRule` in the sequence above (top to bottom) and picking the first match. - -This enables us to chose fast BLAS functions for a matrix multiplication which is also a legal tensor-contraction. - -We proceed by calling `einsum(<:EinRule, <:EinCode, xs, size_dict)` which -dispatches on the `EinRule` and the type of `xs` - the latter enables us to dispatch to e.g. cuda-specific routines for certain operations (as done in the `cueinsum.jl` file). - -In the case of the matrix-multiplication above, `einsum` calls `*` which can dispatch -to efficient routines for most `Array`-types including `CuArray`. - -# Input (Nested) - -Whether with the `ein_str` string-literal or the `@ein` macro, nested expressions are mapped to a nested struct. -Consider the example -```@example 2 -c = ein"(ij,jk),kl -> il"(a,b,c) -@ein c[i,l] := (a[i,j] * b[j,k]) * c[k,l] -``` -which is a simply a product of three matrices evaluated as -two matrix products in sequence. - -This is equivalent to -```@example 2 -c = ein"ik,kl -> il"(ein"ij,jk -> ik"(a,b),c) -@ein ab[i,k] := a[i,j] * b[j,k] -@ein c[i,l] := ab[i,k] * c[k,l] -``` -and is expressed as a nested structure `NestedEinsum` -which contains the `EinCode`s for the intermediate calculations -as well as some logic to assign the correct input and output tensors -to the correct `EinCode`. - -`NestedEinsum` has the following definition: -```@example 2 -struct NestedEinsum - args - eins -end -``` -`args` holds the arguments to that `EinCode` which can either be a integer to label a tensor or a `NestedEinsum` itself. -The labeling works such that the `i`th input is represented by the number `i`. - -Upon application to tensors, a `NestedEinsum` evaluates its arguments. -If the argument is an integer `i`, the `i`th provided tensor is chosen, -otherwise the `NestedEinsum` is evaluated. - -To make it more concrete, consider the `NestedEinsum` for the expression above, where for easier reading the type signatures were removed and the `EinCode`-structs were replaced by `ein`-string literals. -```@example 2 -ein"(ij,jk),kl -> il" -``` -Evaluating this expression with three arguments leads to the inner `NestedEinsum` to be evaluated first with the first and second argument and the specification `ein"ij,jk -> ik"`. Then the result of that is given -as the first argument to `ein"ik,kl -> il"` with the third argument as the second input. - -To improve understanding, you might replace the integers with `getindex` operations in your head -```julia -ein"(ij,jk),kl -> il"(xs...) -⇒ NestedEinsum{...}((NestedEinsum{...}((xs[1], xs[2]), ein"ij,jk -> ik"), xs[3]), ein"ik,kl -> il") -``` -and finally turn it into -```julia -ein"(ij,jk),kl -> il"(xs...) -⇒ ein"ik,kl -> il"(ein"ij,jk -> ik"(xs[1], xs[2]), xs[3]) -``` \ No newline at end of file diff --git a/examples/random_tn.jl b/examples/random_tn.jl deleted file mode 100644 index 48b5b3f..0000000 --- a/examples/random_tn.jl +++ /dev/null @@ -1,58 +0,0 @@ -using OMEinsum -using StatsBase, Random - -function test() - for i=1:50 - ranka = rand(1:8) - rankb = rand(1:8) - ta = [1:ranka...] - rankab = rand(1:min(ranka, rankb)) - tb = sample(ta, rankab; replace=false) - tout = setdiff(ta, tb) - for k=1:rankb-rankab - push!(tb, ranka+k) - push!(tout, ranka+k) - end - shuffle!(tb) - shuffle!(tout) - A = randn(fill(2, ranka)...) - B = randn(fill(2, rankb)...) - OMEinsum.batched_contract(Val((ta...,)), A, Val((tb...,)), B, Val((tout...,))) - end -end - -@time test() - -function batched_contract2(iAs, A::AbstractArray, iBs, B::AbstractArray, iOuts) - pA, iAps, iAbs, iAss, pB, iBps, iBbs, iBss, pOut = OMEinsum.analyse_batched_dim(iAs, iBs, iOuts) - sAb, sAs, sAp, sBs, sBb, sBp, sAB = OMEinsum.analyse_batched_size(iAs, iAps, iAbs, iAss, size(A), iBs, iBps, iBbs, iBss, size(B)) - - A, B = OMEinsum.align_eltypes(A, B) - Apr = reshape(OMEinsum.tensorpermute(A, pA), sAb, sAs, sAp) - Bpr = reshape(OMEinsum.tensorpermute(B, pB), sBs, sBb, sBp) - AB = OMEinsum._batched_gemm('N','N', Apr, Bpr) - AB = OMEinsum.tensorpermute(reshape(AB, sAB...), (pOut...,)) -end - -function test2() - for i=1:10 - ranka = rand(1:8) - rankb = rand(1:8) - ta = [1:ranka...] - rankab = rand(1:min(ranka, rankb)) - tb = sample(ta, rankab; replace=false) - tout = setdiff(ta, tb) - for k=1:rankb-rankab - push!(tb, ranka+k) - push!(tout, ranka+k) - end - shuffle!(tb) - shuffle!(tout) - A = randn(fill(2, ranka)...) - B = randn(fill(2, rankb)...) - batched_contract2(ta, A, tb, B, tout) - end -end - - -@time test2() \ No newline at end of file diff --git a/src/OMEinsum.jl b/src/OMEinsum.jl index ff90099..e617382 100644 --- a/src/OMEinsum.jl +++ b/src/OMEinsum.jl @@ -13,6 +13,7 @@ export getiyv, getixsv, uniquelabels, labeltype export flop export loop_einsum, loop_einsum!, allow_loops export asarray, asscalar +export cost_and_gradient # re-export the functions in OMEinsumContractionOrders export CodeOptimizer, CodeSimplifier, diff --git a/src/slicing.jl b/src/slicing.jl index 18beb57..7c7570f 100644 --- a/src/slicing.jl +++ b/src/slicing.jl @@ -1,3 +1,12 @@ +""" + SlicedEinsum{LT, Ein} <: AbstractEinsum + +A tensor network with slicing. `LT` is the label type and `Ein` is the tensor network. + +### Fields +- `slicing::Vector{LT}`: A vector of labels to slice. +- `eins::Ein`: The tensor network. +""" struct SlicedEinsum{LT, Ein} <: AbstractEinsum slicing::Vector{LT} eins::Ein From d45de45177382f35af4c5942e6af3541b3ed086c Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Fri, 12 Jul 2024 01:48:11 +0800 Subject: [PATCH 3/3] update README --- README.md | 127 ++------------------------------------- docs/make.jl | 1 + docs/src/applications.md | 55 +++++++++++++++++ docs/src/basic.md | 14 +---- docs/src/cuda.md | 6 +- 5 files changed, 66 insertions(+), 137 deletions(-) create mode 100644 docs/src/applications.md diff --git a/README.md b/README.md index aff2941..e2df687 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Einstein summation can be implemented in no more than 20 lines of Julia code, th *Note: why the test coverage is not 100%* - GPU-code coverage is not evaluated although we test the GPU code properly on gitlab. Ignoring the GPU-code, the actual coverage is at about _97%_. -*Warning: since v0.4, OMEinsum does not optimize the contraction order anymore. One has to use nested einsum to specify the contraction order manually, e.g. `ein"(ijk,jkl),klm->im"(x, y, z)`.* +*Warning: since v0.4, OMEinsum does not optimize the contraction order anymore. One has to use nested einsum to specify the contraction order manually, e.g. `ein"(ijk,jkl),klm->im"(x, y, z)`.* Please check out the [documentation](https://under-Peter.github.io/OMEinsum.jl/dev/contractionorder/) for more details. ## Install @@ -89,32 +89,7 @@ which is closer to the standard way of writing einsum-operations in physics julia> @ein c[i,j] := a[i,k] * b[k,j]; ``` -#### A table for reference -| code | meaning | -| ---------------- | --------------- | -| `ein"ij,jk->ik"` | matrix matrix multiplication | -| `ein"ijl,jkl->ikl"` | batched - matrix matrix multiplication | -| `ein"ij,j->i"` | matrix vector multiplication | -| `ein"ij,ik,il->jkl"` | star contraction | -| `ein"ii->"` | trace | -| `ein"ij->i"` | sum | -| `ein"ii->i"` | take the diagonal part of a matrix | -| `ein"ijkl->ilkj"` | permute the dimensions of a tensor | -| `ein"i->ii"` | construct a diagonal matrix | -| `ein"->ii"` | broadcast a scalar to the diagonal part of a matrix | -| `ein"ij,ij->ij"` | element wise product | -| `ein"ij,kl->ijkl"` | outer product | - - -Many of these are handled by special kernels -([listed in the docs](https://under-peter.github.io/OMEinsum.jl/stable/implementation/)), -but there is also a fallback which handles other cases -(more like what [Einsum.jl](https://github.com/ahwillia/Einsum.jl) does, plus a GPU version). - -It is sometimes helpful to specify the order of operations, by inserting brackets, -either because you know this will be more efficient, -or to help the computer see what kernels can be used. -For example: +It is sometimes helpful to specify the order of operations, by inserting brackets, either because you know this will be more efficient, or to help the computer see what kernels can be used. For example: ```julia julia> @ein Z[o,s] := x[i,s] * (W[o,i,j] * y[j,s]); # macro style @@ -140,107 +115,13 @@ julia> Zl = ein"is, oij, js -> os"(x, W, y); └ @ OMEinsum ~/.julia/dev/OMEinsum/src/loop_einsum.jl:26 ``` -To see more examples using the GPU and autodiff, check out our asciinema-demo here: -[![asciicast](https://asciinema.org/a/wE4CtIzWUC3R0GkVV28rVBRFb.svg)](https://asciinema.org/a/wE4CtIzWUC3R0GkVV28rVBRFb) - -## Application - -For an application in tensor network algorithms, check out the [TensorNetworkAD](https://github.com/under-Peter/TensorNetworkAD.jl) -package, where `OMEinsum` is used to evaluate tensor-contractions, permutations and summations. - -#### Toy Application: solving a 3-coloring problem on the Petersen graph -Let us focus on graphs -with vertices with three edges each. A question one might ask is: -How many different ways are there to colour the edges of the graph with -three different colours such that no vertex has a duplicate colour on its edges? - -The counting problem can be transformed into a contraction of rank-3 tensors -representing the edges. Consider the tensor `s` defined as -```julia -julia> s = map(x->Int(length(unique(x.I)) == 3), CartesianIndices((3,3,3))) -``` - -Then we can simply contract `s` tensors to get the number of 3 colourings satisfying the above condition! -E.g. for two vertices, we get 6 distinct colourings: -```julia -julia> ein"ijk,ijk->"(s,s)[] -6 -``` - -Using that method, it's easy to find that e.g. the peterson graph allows no 3 colouring, since -```julia -julia> code = ein"afl,bhn,cjf,dlh,enj,ago,big,cki,dmk,eom->" -afl, bhn, cjf, dlh, enj, ago, big, cki, dmk, eom - -julia> code(fill(s, 10)...)[] -0 -``` - -The peterson graph consists of 10 vertices and 15 edges and looks like a pentagram -embedded in a pentagon as depicted here: - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Petersen_graph.svg/252px-Petersen_graph.svg.png) - -`OMEinsum` does not optimie the contraction order by default, so the above contraction can be time consuming. To speed up the contraction, we can use `optimize_code` to optimize the contraction order: -```julia -julia> optcode = optimize_code(code, uniformsize(code, 3), TreeSA()) -SlicedEinsum{Char, DynamicNestedEinsum{Char}}(Char[], ago, goa -> -├─ ago -└─ gcojl, cjal -> goa - ├─ bgck, bojlk -> gcojl - │ ├─ big, cki -> bgck - │ │ ├─ big - │ │ └─ cki - │ └─ bhomj, lhmk -> bojlk - │ ├─ bhn, omnj -> bhomj - │ │ ├─ bhn - │ │ └─ eom, enj -> omnj - │ │ ⋮ - │ │ - │ └─ dlh, dmk -> lhmk - │ ├─ dlh - │ └─ dmk - └─ cjf, afl -> cjal - ├─ cjf - └─ afl -) - -julia> contraction_complexity(optcode, uniformsize(optcode, 3)) -Time complexity: 2^12.737881076857779 -Space complexity: 2^7.92481250360578 -Read-write complexity: 2^11.247334178028728 - -julia> optcode(fill(s, 10)...)[] -0 -``` -We can see the time complexity of the optimized code is much smaller than the original one. To know more about the contraction order optimization, please check the julia package [`OMEinsumContractionOrders.jl`](https://github.com/TensorBFS/OMEinsumContractionOrders.jl). - -Confronted with the above result, we can ask whether the peterson graph allows a relaxed variation of 3 colouring, having one vertex that might accept duplicate colours. The answer to that can be found using the gradient w.r.t a vertex: -```julia -julia> using Zygote: gradient - -julia> gradient(x->optcode(x,s,s,s,s,s,s,s,s,s)[], s)[1] |> sum -0 -``` -This tells us that even if we allow duplicates on one vertex, there are no 3-colourings for the peterson graph. - ## Comparison with other packages Similar packages include: - [TensorOperations.jl](https://github.com/Jutho/TensorOperations.jl) and [TensorKit.jl](https://github.com/Jutho/TensorKit.jl) - [ITensors.jl](https://github.com/ITensor/ITensors.jl) -Comparing with the above packages, `OMEinsum` is optimized over large scale tensor network (or einsum, sum-product network) contraction. Its main advantages are: -- `OMEinsum` has better support to very high dimensional tensor networks and their contraction order. -- `OMEinsum` allows an index to appear multiple times. -- `OMEinsum` has well tested generic element type support. - -However, `OMEinsum` also has some disadvantages: -- `OMEinsum` does not support good quantum numbers. -- `OMEinsum` has less optimization on small scale problems. +Comparing with the above packages, `OMEinsum` is optimized over large scale tensor network (or einsum, sum-product network) contraction. ## Contribute -Suggestions and Comments in the _Issues_ are welcome. - -## License -MIT License +Suggestions and Comments in the [_Issues_](https://github.com/under-Peter/OMEinsum.jl/issues) are welcome. \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index ba31e72..7769e8c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -10,6 +10,7 @@ makedocs(; "Contraction order optimization" => "contractionorder.md", "Automatic differentiation" => "autodiff.md", "CUDA" => "cuda.md", + "Applications" => "applications.md", "Manual" => "docstrings.md" ], repo="https://github.com/under-Peter/OMEinsum.jl/blob/{commit}{path}#L{line}", diff --git a/docs/src/applications.md b/docs/src/applications.md new file mode 100644 index 0000000..c8a0f59 --- /dev/null +++ b/docs/src/applications.md @@ -0,0 +1,55 @@ +# Application + +## List of packages using OMEinsum +- [GenericTensorNetworks](https://github.com/QuEraComputing/GenericTensorNetworks.jl), solving combinational optimization problems by generic tensor networks. +- [TensorInference](https://github.com/TensorBFS/TensorInference.jl), probabilistic inference using contraction of tensor networks +- [YaoToEinsum](https://github.com/QuantumBFS/Yao.jl), the tensor network simulation backend for quantum circuits. +- [TensorNetworkAD2](https://github.com/YidaiZhang/TensorNetworkAD2.jl), using differential programming tensor networks to solve quantum many-body problems. +- [TensorQEC](https://github.com/nzy1997/TensorQEC.jl), tensor networks for quantum error correction. + +## Example: Solving a 3-coloring problem on the Petersen graph +Let us focus on graphs +with vertices with three edges each. A question one might ask is: +How many different ways are there to colour the edges of the graph with +three different colours such that no vertex has a duplicate colour on its edges? + +The counting problem can be transformed into a contraction of rank-3 tensors +representing the edges. Consider the tensor `s` defined as +```@repl coloring +using OMEinsum +s = map(x->Int(length(unique(x.I)) == 3), CartesianIndices((3,3,3))) +``` + +Then we can simply contract `s` tensors to get the number of 3 colourings satisfying the above condition! +E.g. for two vertices, we get 6 distinct colourings: +```@repl coloring +ein"ijk,ijk->"(s,s)[] +``` + +Using that method, it's easy to find that e.g. the peterson graph allows no 3 colouring, since +```@repl coloring +code = ein"afl,bhn,cjf,dlh,enj,ago,big,cki,dmk,eom->" +afl, bhn, cjf, dlh, enj, ago, big, cki, dmk, eom +code(fill(s, 10)...)[] +``` + +The peterson graph consists of 10 vertices and 15 edges and looks like a pentagram +embedded in a pentagon as depicted here: + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Petersen_graph.svg/252px-Petersen_graph.svg.png) + +`OMEinsum` does not optimie the contraction order by default, so the above contraction can be time consuming. To speed up the contraction, we can use `optimize_code` to optimize the contraction order: +```@repl coloring +optcode = optimize_code(code, uniformsize(code, 3), TreeSA()) +contraction_complexity(optcode, uniformsize(optcode, 3)) +optcode(fill(s, 10)...)[] +``` +We can see the time complexity of the optimized code is much smaller than the original one. To know more about the contraction order optimization, please check the Julia package [`OMEinsumContractionOrders.jl`](https://github.com/TensorBFS/OMEinsumContractionOrders.jl). + +Confronted with the above result, we can ask whether the peterson graph allows a relaxed variation of 3 colouring, having one vertex that might accept duplicate colours. The answer to that can be found using the gradient w.r.t a vertex: +```@repl coloring +using Zygote: gradient +gradient(x->optcode(x,s,s,s,s,s,s,s,s,s)[], s)[1] |> sum +``` +This tells us that even if we allow duplicates on one vertex, there are no 3-colourings for the peterson graph. + diff --git a/docs/src/basic.md b/docs/src/basic.md index 8a3059c..91bd7af 100644 --- a/docs/src/basic.md +++ b/docs/src/basic.md @@ -62,16 +62,4 @@ ein"ij,->ij"(A, s) # element-wise multiplication by a scalar. ```@repl tensor optein"ai,aj,ak->ijk"(A, A, B) # star contraction. optein"ia,ajb,bkc,cld,dm->ijklm"(A, T1, T2, T1, A) # tensor train contraction. -``` - -## Application: Trace under cyclic permutation -!!! note "Example: Trace under cyclic permutation" - Consider 3 matrices $A, B, C$ and the cyclic permutation of the trace $\text{Tr}(ABC)$. The trace of a product of matrices is invariant under cyclic permutations, i.e., $\text{Tr}(ABC) = \text{Tr}(CAB) = \text{Tr}(BCA)$. This can be verified using the einsum diagram. - - ![](assets/perm.svg) - - ```@repl tensor - A, B, C = (randn(2, 2) for i=1:3) - optein"ij,jk,ik->"(A, B, C) ≈ optein"jk,ik,ij->"(B, C, A) - optein"ij,jk,ik->"(A, B, C) ≈ optein"ik,ij,jk->"(C, A, B) - ``` \ No newline at end of file +``` \ No newline at end of file diff --git a/docs/src/cuda.md b/docs/src/cuda.md index 63a3381..ca264d8 100644 --- a/docs/src/cuda.md +++ b/docs/src/cuda.md @@ -45,4 +45,8 @@ julia> @btime CUDA.@sync optcode($cuA, $cuB, $cuC, $cuD) # the contraction on G 243.888 μs (763 allocations: 28.56 KiB) 0-dimensional CuArray{Float64, 0, CUDA.DeviceMemory}: 1.4984046443610939e10 -``` \ No newline at end of file +``` + +To learn more about using GPU and autodiff, please check out the following asciinema video. +[![asciicast](https://asciinema.org/a/wE4CtIzWUC3R0GkVV28rVBRFb.svg)](https://asciinema.org/a/wE4CtIzWUC3R0GkVV28rVBRFb) +