From cf4279e0c5d59d92a03732544c73dd3f0be01b5b Mon Sep 17 00:00:00 2001 From: trbromley Date: Fri, 19 Feb 2021 13:30:05 -0500 Subject: [PATCH 01/30] Add basic template --- pennylane/templates/subroutines/qpe.py | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 pennylane/templates/subroutines/qpe.py diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py new file mode 100644 index 00000000000..30d655fae29 --- /dev/null +++ b/pennylane/templates/subroutines/qpe.py @@ -0,0 +1,38 @@ +# Copyright 2018-2021 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Contains the ``QuantumPhaseEstimation`` template. +""" +from numpy.linalg import matrix_power + +import pennylane as qml +from pennylane.templates.decorator import template +from pennylane.wires import Wires + + +@template +def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): + + target_wires = Wires(target_wires) + estimation_wires = Wires(estimation_wires) + + if len(Wires.shared_wires([target_wires, estimation_wires])) != 0: + raise qml.QuantumFunctionError("The target wires and estimation wires must be different") + + for i, wire in enumerate(estimation_wires): + qml.Hadamard(wire) + u = matrix_power(unitary, 2 ** i) + qml.ControlledQubitUnitary(u, control_wires=wire, target_wires=target_wires) + + qml.QFT(estimation_wires).inv() From 929abdfb9ee9016390ff7ee1c5600e0a63d27562 Mon Sep 17 00:00:00 2001 From: trbromley Date: Fri, 19 Feb 2021 13:31:59 -0500 Subject: [PATCH 02/30] Include template --- pennylane/templates/subroutines/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane/templates/subroutines/__init__.py b/pennylane/templates/subroutines/__init__.py index b6c4e113adf..e21104c5156 100644 --- a/pennylane/templates/subroutines/__init__.py +++ b/pennylane/templates/subroutines/__init__.py @@ -23,3 +23,4 @@ from .uccsd import UCCSD from .approx_time_evolution import ApproxTimeEvolution from .permute import Permute +from .qpe import QuantumPhaseEstimation From 00102f159528c2954b4b5d6fa1b94d86fdc58509 Mon Sep 17 00:00:00 2001 From: trbromley Date: Fri, 19 Feb 2021 17:57:14 -0500 Subject: [PATCH 03/30] Add to docstrings --- doc/_static/templates/subroutines/qpe.pdf | Bin 0 -> 65569 bytes doc/_static/templates/subroutines/qpe.svg | 372 ++++++++++++++++++++++ doc/_static/templates/subroutines/qpe.tex | 25 ++ doc/introduction/templates.rst | 5 + pennylane/templates/subroutines/qpe.py | 27 ++ 5 files changed, 429 insertions(+) create mode 100644 doc/_static/templates/subroutines/qpe.pdf create mode 100644 doc/_static/templates/subroutines/qpe.svg create mode 100644 doc/_static/templates/subroutines/qpe.tex diff --git a/doc/_static/templates/subroutines/qpe.pdf b/doc/_static/templates/subroutines/qpe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c39e16bae7c50312f14d5193b4bbc17adb37f273 GIT binary patch literal 65569 zcma&NQ;aZ7(5N}KZQHhO+qP|+@7T6&+qP}nGy9#*{+mtqT%1lisk-R9>L-=1r%4q= z#Aq4mSfNPgmq*s2mGFfiL3xe#$BkL)4akNjXDkkv%BN zCWs9D@r8SvC`@OnT9g7i#2`Ayo;@~(nds%bzOy5qVDh*bJ%pYh0G0y6L7EePc(3Wx z?)mwAbQfN>)x&stx^@&Fp4WyCf9GZo&y4`(FMyFzC@k|&QuJZ1`OCemSW@wO(7$(R z&wn^PUdjgzp;%V%nozPTI2}QEOn>CA>#f+auYB8`YtKX(kV~5u$`jCll%p;EbIfch zJ9Xg{wMJ&O&=L%MVsY4LkMfyddwzFf9|l=Bgq$fX6fdM~0k!mml~g#6?U)-{kr9Sd?6FjP4sxIG>0aB-lZ?X^ zT4u`nk>bVoQLZ2U=u`i)ID@OUXm-aJ38MwVOf7UVLr4mhxi{s-h1{eh5^$%=tx|NVyc%|k0Mc&*(p z_3}P=l=&*H(ISRrfVQS8#uGF(Aed|yj@)JEfabp)Qp@cVy4yO`k_xu?f!k}_rqbG6 zuG(6UQ?||KV+su|Z)5o`NE}bgCQ2L|K*2iL_3z#KC z_6Cv@hRroH$j~aMkRxW&Sj2`7hSSCH zh&NML7@t02aMYTEr4%)7JT?hA;|ORT2)SbH9@5qo46#q8)JL!|t#Vq~_Z{pAfrK`4 z61|&7&O78Jnv<(5kgJ+AR^7u_v+PkScl(qs<7=1e1q+-4l@IeR90*Di^@$Aq4*_b#PR7@Z87jT252v> zGnb$03}%#9t5SDA(kU<9fz_@xY-^Bep*&(m37Y`_m8v%4;ehzX#W;59gQOVpl(O-M zL#bD)(pJ9h37)?qEc7}-_iV{>)jbewq1uX1Jsh2zYw8LikQ>BW7YEmj4<`}NC-{Oc zYN6ICqu9d78r{>(^DErIV^2y=siDfGZBcDyom7vyvH4t1WIs2tF$lHT!{h>{|Du2xR8NIX%s;7wsxYsQ)6g%aB??Y#Ljw71Nz7 zHZ2t0v!kVLAnN)mS|%9Jh#->=Yz-}ooq~2d1*fleKX$}GP|R7J(lWjuAFo_qE?%F% z_bK+yAHaPuPdSvSoyq^h#s8xJ#Z)Gy{~uf#2^d*eIR6K=Oa$yq9E|^y{fFZJ2?;ou z*ctv$864{lu9Bp^M7LNRp@IlPLg8>u^1SPf3L$F+0VpIXgmgjB6TIlH*!iqiOsOi6 zT;C(+)3w@jrAvL6n_+G?ckO9b$8JLt594uSo503^N&++meF!WC zfYQ>kA}9cWKrs#u0`;%HA@D%Me0|RgiH#To3s{_p&V$?;mQA@FZZgsO0@qS6A1Q zpbmqNL~{=eIeb5EoGZZj5CcOq_B7gkl}P~HFzBngr4NY>Ks_+dQ`rE3Ww>j2zF~lM zC^HU}utBYEE`g1qMgPk!0I(}<03B4=J9704c>wtR+5v!oPyS!X*VLCf0moq*GYFJu zXFdUhJjWoO0l0e@po?nrdp({89sr2p7c_+9C_&v1p&ddy^YAIwJ+~`_fT$ikKu7I; z-6w+r3r^_Bz2W|BpVjdn>gi{C3Sw)N1UfnfP&DC3N*)ppY_MKl7x|z5jH?jA4&tuA zw3|an%}yPYO41C0O%1sN3u8B9P2kO7_o_^&>80Iy>G zp4dG7iz{sJE(Hmcfx9l)G`bylmtTU1F@YTe0NM}8>D5mk>|d&c06_pPP88^R|MdYx zqJN=&m7$ye4Ht%2HpB-agX=V4RvFB}{)Nj0^ zAm9by{V6I6z&#WMFd#wxKMa9quY<2Uj(CFmzQ=d{-b)B>l701h{SQ6-A5oyV zKC%$x`#S@!aqG)L0GvOD9UKan5WT;E-@cFEt&=~oCw;}=Jej|{7?oTO?!Q*&Z^(E4 zYXtQ6rZfEr>r1`?z4$=3M=uP7KUmhVAI`2#2JLs`w7=F$W5Tr~g82HrQWkoN2zZL; zGQ2p&K<|DV{DB6AaDL0DvfcZ&e$FApdT|Mu?=@8C8&Htnv>UI)v@y~V!8Kt92u zx~HF+qAQ)hRR28~hIDWksYg#F$P^g2YDhcYibQjVGhN(NqIF4LM#O#G**22FSBiKo z+7WCMQ#tEirH^e`r3RPlc|`}_iQK%+H@yne+9wpQLsK=)HuF|bK2KK{W1fMp^oIcw zPvlwXBa_fCB++xcY;hSyl$_zl)>mFIn`1uzWfxy52lFyYHN+JN%N5JJYO2}gLQ@p> z&sS0WEt@5HJygE@FXFT4siyoBi>C;boM-S%rJFL6huajCXkXx;rsN$N`$8a=Z6I}b zP2q;*$;6)+DIs?1STp_I-wfsB))cuD+af92Hq$NT&i)J^rJ|;@`o=cXfx(1z%1eVB z3v}4eQ`bq6$jlN&3DL9D8qv*JlW@i(*4GIV9OIbI#eFOLv#CA?PRo!`3op5N_gI== zpTdknyVnBt^k8vrz0XFQlPr5)ZS9yWT?)G?eAS6$>dEcqjO?slH$i%D&73B)cn+b_ zSkUQVC0wlmrqHIt0oq@(uQ|KSp<0EWoWs;ap_4YZwO*Uw9hG3*=n$*)3o^C*SBwh@aokxznqS44hJ0blUa!CLAS49eTwc2xr%On_)r~ zg4aP~_QTERvYk9>ifj*;+hWCmXPj_hPQB zLBJHoWlEl=7a_Xc;4=WbC|fp}na!Z<9~ZF4Tz-Bf`2B937gJC-Wd*#bMzWjMqtYg9 zcq&f`$cd$6N6tOi`db4_2J{!z&Q0;!1HPN;LFOJauxEtJPnl~sBqi*JBf92XC=+-6{vy5chVjmI={GPC1P zH>%-uG-xRnhtoW}f}PawxCEQQ@^-U$WkLNtKpuZF1bpMc60i}u6Ka@lY=P~tty+j- zeja(-wz-9@U7~rro03fWNu+%|^Bo?pJ-Yk^#n=M8yh`A*zbf!MYVLCRT1f@>9VJf4yth_eHyy_v9*D5=3Sz6&QVh ze;AWU=DJjrGSayK$4GRiR!j2Hpjv0O=U|$&gwT3SM~&Z|r>LY+bpJtD^&7S_?V*=v zbhYaD;97*55LFP_Yjski-cAlY!`axoAK41+x0Vv8MmyoYG>VjKI|xdSW&(ufnt76~ ze|-G(1`la_5W`Qh7GPVek&u8h@$dbB5Q`T-bzoFv?ZW1Io__iJMHG^m$TH)Yg`j+{ zy_-W`LGqv_=TBLgoTo9V;y!@o=m^FxUsTp`z-o#(-n8vC!bW=*dZWeX?mxZ1!$p$9>4|Xv!5+ zb3Ka-ofwA*m05yAw=}88J?dbtz7`pJ)m2(Ya65WQ`ub^6aLb?vk4ApyZf+X6Dj+%~IW5bjjeGnO-#R(UJtQgbZ#(M5 zAp84(dY9ZE)VLRol)WJ5MF3ZNqBqOL;`KFtkeMXfvVr(89ZOIb@!YB$=?@t#E>*mA z_Z%FH>Sr5DttgH%32;w;z*LW}$7A$7PoIZjzP{@H42O&#&6$Z234>&W`_iNXrl46; zTf^wh06KG_UQ50qsglD8I=vM5d>^(a`VwEVv+c|^_L`t+4yJF=wNz=NKPhm1Gn`JdO6Q_@@k`<-q7@b)CEGiBn8hB9^ z4W_+R(<*C9%qmvFIr}dy(-P6!(-LaADKx{bm{(lvCL|k1KiE*1yz? zT7>$8@gFBhU>SK@oR3nwO0d!K-RsxI9f@KEzA1uyp9R@ymRYo&+=U-IsA^O5hj5bR zJ>FjP}tVtoTd`TWwqt_J9X(=G>m}<^DLdLC$ z?!DrAam)?F)a}mOApye zma+wI5p%~b6!Z84Oz2Sm9npsRU1<0kn2Zwx+11RC@SRscXy=-cxH3{%U(#3_oAP(@ z=QLe2?*#N_-cuZKBOaFM9K34UcOmys8me=hsV?pLbrPEY9Hf0i3Kamy++Ad2@=I|X zeoNU*M(@f^?Nn6NBi>J8eITZ52Oy6TnG^tlu5`c6ZSu2C>P3r8S_&%a73Cf@8OeCz zu=U@D5-af80+3cSfI$6y)pL}jqe9pqmRUF}D0%J`=3{LqB??emev|3a zi)RHSjXUlq6tSCmHaUgyVLM$3Pe`i*Qz`)5ra$7g~kCzL^iwLN>UjzK# zFh0pgaT|$)$`aHG4T_`9HPy1ty%JYTuifmetQ(aE7l(h1XWt;Hm7Lu!mHuyhOU3LM zt#OWu2v7AVgHf6zDRcK@`YcBB-oD+49SCK?giX+QXnJ(_+SyQD#(V1xS0cRH;`cd( z_+j*xB6N*7rF-T%sw%Yo7x}r*bVbyS-hBdy#qKs*!FjSi2i{#%tDdEM@;>=UPxMp! zYsTM7i6J5OS_VY$N7)ZpXiG`R1xH2T%!>FzH3iR@)8Fha>>Hg81bep!o?b%TgB4HL z!x=~ZOntt&1A3F)X5tCP;aB4DH?5ki&8-NWvFF>c@JkduU2=p^wA>p9%a7x7tMN%A6s$+<3o#}< zwF&uo?yt-W<|thQ9sOTYM>PL3WJvX?p0^YVTXSo`-Jh5z^RyXxlz79SYhN_)^I(XV zG%tOTI}a-Ujv3$5J=^`xN}97T#^NTeUj?YGH#+Ip&5(zvY3WYL;XUr)W#WXHaS*Y} z`Fk(&!BqZ%--nJFRNNfeCiSy&^6@YVi+Ixb3;tU;j-H%&~C}%h2p5V@^)>+u%|GtbqE@G>3p1glj!-AGmYA;-m z!nvouqCnuK>bAKGGvRRQDIJYWl$~eIz)vzpvDQL9q8O2G(0pMMt$My6^3f=TD`Da{3T*Ya|r2n8--xM+b}{j^+wFw0FsFMWTryvN!Z_OC=la$ zQIfh}o=5a{R`|g3D94&-%NFM`?IevK39|1WG67FqeIl1_g?fxT0$lv{I2B} zYkyo3N01a%zt&Hem)v2Hj?17H539r3{hw_Y8q6G6qlR&FU%2xp;5CCHG7L=9ZsFyK8@ix;TZv>kaIQb<-UeRA1}t(7ApYs$+51xnss$YXz3C$`@*z1i=NU7b0ogc$FxD>pdI<`jpd zn62PJ)*+QV6%&dxx&2fT*`~mQXcpy@-(J{|lp{D=lZ#2LajQDPvF6bDs_Jr~3@p<1 z*l4n+);7W`$-37V&!aLLT72COG_#c_ujZ#;$yAoCTbeBxV z#|`REcH_r|vznj~nlfcYpS)!XLAD%Qd(*LcDV$-6%FhN{W<`Oe;!Y%|kYPr=zP$d; zbtt53$CQ~&f{M?|iLyCC@ZSCqO8&H4h`9NL1e}G>OKtAY!S=rC*IC>7EV2NB^U|Pp zwV~wXgeaw2xZ{sc;uWZdDJ75{yQH{ER^i);pjbX@-t|he94x=BXT!D2ZN#dbnoxSYdVTkxpz&>r|Hp zkVXI}Eyhc8%Hn|k>y)D~dCEe`T=oGr;RL74@#ZUO*$Csal2In#GfW`@J5TXCkF^R> zHk9(_G$ry9TA_$w`*+_q;ckfsx7_bDs|;^L)weBA+!MM2g^XPRRtgjH<%6+hv(_`$ zvH$6qB18%)on4(3oJD@4s64+YjKC`US}|``BmPMhco@W8;-sSP!>Y3D9&sDWd68H~ z${F7ruKJv%BpkFh$AzvJagG$qNhL!cJrOnz=C7+thK?O3of z0ePxx zZ(*94(+-#+b<7m$j54~KffKuEs2C!YPQDqu`c^YwXzBY`!nMkTD{bY8#8C(4BR!`t z`TZHzvJ&1NRV5mT|2-crMn0qI=44G?GBV3^B;VDIUd5$5Unk|u@ysAj$mK=IWUSN$ z84>+U0YIZ!W%|x?{VBYnD7puCR?>bX{f>oU?YWti(;}N4t#`uIXW{_E*|cd=l=>z( z)@(m8jtro}D_}O3Th;ZBQAv#Umc!IHe_{9teOhOFPUSrKRmmf|%gjoiGS7=JH24$R zOxoIZ>YgGwk1QL$-hBbYkLa3qlHap(WttqiI_oG$BbTjStveK%;t~qD>}&~5as%aG zp~8CR=*I#T&AP@KSF)pvdW8I1@Cxzn5%o#@I&u=(=XRr@H>0d7R+X&*t#m)hV}I2= zhlRTZ0^NeR#r9-RcwV9A*5-pVQq0|N3&;@`7@f5{1d5=%{jDWwy);Iam|I)v2w>`s z{>hs4#-xaN$br@FG(i$KdN#uz+k66ocY^p=IPb660Z>B0HP6{(doS$P_y-G9=K{a0 zE}2q@O-I*UJadW$dv0-a@!YWPJMUlc04aW1vk@EyFE#&8x0q!YmF1Gr;7{)m`$mkw zjqtHB_%eh?aE-V93s{{WUAPS3+CAoj#Y3AP;DJN<>Prq9zAN7WxqbBu-U+Ten3L8Y zh2+B0mG%1myXTVzgPb`DFFk$Hu5_D*sXr&9aX(Hs zjabc zkBrBhFuj*k+yvxYXV-h|)%x@)!?~C_!!1bmt|W*okXs0i z2rma8Yeb<0H6A4E6QkoHcVx54QJ75$+|gAni;GYo_jWlfmOgS>NA}5y{&$bEgu2n( z8hxro_4%YD^1kyIcf9=d3tYyxqP4T$q07}!88s@2tX6nkg3f0cj-6@UaE9=`&&uLp zfjZ|K7+h746E%)(5MMq%nci zOAl}R2HB@fQF`;IQl~Q(^_h_hF69!c^r z(kH5+emCzH4V1pG)69r==8u9TSn$D1N4uh8NlEM#2fC71RVvY7+iF!kf5|8%vcuN5 z-fGIU+o3k=L=-1))|DCD6?k^Wyqi2x$*HMD6MxUZ9+XB??IBYqV^a0>^_K;+tG@!q zb&6+N$zF9XNPa|8IHyZnJcC2_G|v6i9xQhC#Et{Bw|({&m00k4`%9*E=X!M^dY3gWKo*pg!L~eTyCqH{`t*`tf7;^+wE}=c& z!KJUq>j#;8PhL3%6-`DCBZ@lLArOe;O;h%ytdxIDzkEMx_bbQ-DF@Iku3aDH!c0y3 zrOskv(5d3Kr^8`S>6S+zb14?VQWq3yxNB?C%l2)KOp{@nGQ-qDQl{Krid-Ye^iyzK zTae8{T@Y><8INGQXwus?VOnTS9Hn@~mw3nBK-Hm9Hp4{mZgmU`jqVvvhpI|po_MgNsDIhwaSjyZpID4lv@uJ)*zbjtWqSH=8V4DhvQV!s^= ziA}LdgihhgjW*+zvRFYqJY`3U;PJtn6#J-bOu5lY*L|}~nxX&v_G_fMw=ypA%BYhH zOPZCX9+nvuji&_agdWOnsCXkjeB5+(_2+Xt>DdO;Y|fYtt`XH^b`9a%Fl8K^1OzY{ zO8BDfEnl}WX2}m4w53l@xcOG;^E$QYWw~Z&k9toE` zyZGSMBgG^H7mYV^e&|judy~$)mU=tcc}0T*xc|=3C>N3X*mFdN#oYcgbk2ltDmr*m6Mo7Nx-uaW zs9J!iNFk*_=%a(Oa#(gJMB~tUR4sB%O5j7ZlUVWnf&42Y^DQ1z=Tl#NXs(01?%j0t z%3cP$7)R)?Xv1g}B>5mhEQtUb5-YM@r9#{kp zd4ii33CQlrYe%gEdW^;&Ln>0|Y`8R*!|Q&BLWXd}d6{(DB=0fc)M1LHYxU1Bz)g&% zchU|85EFS^x^QUF$h+oG4i5T6!s8+C8j+UFANkGpkq<7zyvqHET{0MO2wmqkdh5NW zD4Q4(;E=0itv%Wi@*V`q5eP0U2){iq!UoR=Nv-d}MX?ig*2GY~R_*fFaoT}?@%bjw z++{H1J{2;mjMR8~kDe_|J-N3eHPR5-)W&3w9m18y9*M)Tuj1R6mpjMYMhf-K`#_w{ zZXRYOc8BKHCAwJJ0{&OqN;f?qPtAKNnM05<#p4{4T=3;J1K%-&LUeMg0SL}%?t(Iv z>Tl#+aP*0dOpii>9Rx6?Yv0lffPOmI>gH zQmT7yGbNWW=B;x0lt~uJloq^zvq8j@wqy1f(qxurBDrEh6B@{H!uVNxpJ(gTCN`^i zqeZSc;%`ez@IG7>^tzWGtKf()0LvgV*##*|d;pX$PYJCXYoVtR#tAKX5c8Ggc`$;?b-s zbGE&=l^v44Mz}O2eD0GTXMm^`WDMUDrC`l*b$a#N4>a!Xe_?yPL99O}ZG-B0WsSNl zQW%zkq$s(?;6`_CMODpR&7pB(>>BrOahjn2&dx;x(1}t_8k9x(G#SfAkHTD$JUXxo zKZ)S=KB;O14of>@sylSdDpG@dx-{r@1DBvngj5C<&3R%6(kx-|2Gl?%l}SdVCG=`A6J2ifQ^BL?SHcWuf)K{$;tMAEHSu%swCgN((P0r zB?e2Z&F}2MCNePq$MnN6vOp~6AR!UK1~n59Q0)-lCNAPa!35poA7wxN<#?}ky3c6s z`FP)%-?`tp^UsY97MqU~!-s7Nsq8a=!1L290Ogn0)X>2I0D*c23IGD3p%GIIVm_|P z_8S2?z6A^#BK<+l~0%%B=G(fU|o&tkF z7J5ElxF8RN2FgKg@2vv3ILKwXe-F_54F|yY;bGx+-xA;>9fEr~E(F*-7$FWJT{-fN zz$}1pJ1$Dl{f{`L8>KkNplVS3+}2hW`tjiaw7dJigMBa$VZ=B9;0W;H9cUo1Z!C;_ zV5h+EjF_|lP=jNLm-i#~kS*eF!CM4?$pe^{;C>zj%v=VBVcY;N9E0*&(0SL;{@;L> zUx0Q%|2we$xv9T9C;ujY)Sy8>^5E<1eY#qLbb6FifckJQVSr95t!@Z>5Ox3%;6I?C zY~KBHpMU5OmoSZ@fPU_9K;`3Czyjrfe{pAqXK=2f9`{}XIsUQZZ&fgtsVRmAqV3Vp zAYu0e?<;vo%eY42oo@QQ{8_F+13iYn{;=K@FgAbI5cOr$d5kcZr;v*3pU{FG5Wh#x z0R#Yp0*s1+j06COU;*#zoR2?L_QzLHAGpVVCt|V)=XX%{4!LO?$M?)v#@f&BacFs#A>)`f8L8G`;)#5)LI{cV;XcMA9bpb4V9zXA5^_WJg! z6`p~H3}<`)^A~pM^8&l0;sWv3@*@9ml@$WM0KP#*0eOH11yFQDhXD)A)B63@7Jvo+ z+yKAjE4ile;P%0PFVI|N|1Q_B=mFRNqJn|%=Zv@LK3-iAJ^;P_G zpZty9>#P3ill`0@!j$fz|(oWeWX9s9^(z zd3AoftKb3(K?>rX1`sjB_aV?LoX6u|7682j2E61$aF6jPe;l#@lCqjpz!ZYN1^j-t z<~IiP|3wu%o1TSy`g!Dge2{}Y3Pi#_c*pkHKuF2`T?=EHfrI}o<^DQUt+@o@x8LDi!88pjg_VSA7$-MOCdo##>!qM)r z=mrWFF85%|#`C3KBlps*7i|3tWeKRMb!J=1deO^>Di?eA&VkRfnsjQWxEPjw?ZYC- zwEc=<3+YpCI`MUtgwc&|ikY3C@XDurIY=ZJ>B_VzanH98?2hi`ea#3{A0K@ff&l4g zG{MhFM6hd_5CWWV)vH+3TgCO)Ug>i3-oK49jdL-{nXNebyvRjGF4JC{BD6{6cE=$Bf@X;Oex< zd!FX6OXuWG_ONZ_=mGpjTD z_bESg4kacYDS$5%b9$o1hn1L0emBNnYn}`@lBdqFXbgHg;mh<@%cE2j<+xdeRmJU_`0Z9NC&%D3<0;ZfFr6)R0{UWi+q9kV z@BOp740y4cka+srCXGq&rj6?1l)*8C))%jj&SBhGS!8$XzTs{F9k|i5M&uH|`P8bu=XA!3}oTBQwUl|GbMAND!I5 zy{)as$WOzud8<}bI1i77(q7Sjr`K$Zy;ZkS)lV=~XA6ThvSbz4mtH^`Q}l!6L@^y| z>fjAquLc0C3zvWCkQ;$1E|2EDw}E37eJKNiS?IzM30afh$tb1x;C3~xOUi3}mf?ho zwt*;&tp-`j&D6UeJL{cpA=w)RK$x4Fnbdv7+KSe*gVsi-%OV$%3s=(UTRczj{jgIv zhf9lYWN=!C+zc6KgK2m6M12l5{1?IZ4Bp`X_3-@UaMja_b1X$jp#YF;yZbP~#07q`C) z4%)0&rdG#;6-W_xa(%i+bs;08Xu;b`)VbO@e9d~WEvf!eX*Fh;{93_(2blC3tNC>-PFHH5PBf&tdo&Hym(7Cz9 zYp^$>sgcM^Q~D~(>zBn%d(%}YY$={4ecnYW%-vPrHI?Q14On3gtLAe(MW(bE{#|Nz zcl0ydDCC(R=}D08eb^B4+5o%AKz$mAEgSRP0z9xqo}Lx%uIG_Irt?ASjo#w7?OsWJdAFKt3-5{x>L7rJn$s_@C2Uo z8J8G{+zE4DpV=)lFM??9p3SOvj!t}iO*4&`OrPr=ge`4e$4LigN3*1#JTe+Xzmhbr zfb>HXa~ngZax$skvg$VF_&Dzp;)t014FOZ zhzsJ!?Y*ONzw2hd7h%g7P_JhJMuTm;a zHdFdu4~+@#76DzxHBn#vlY?T}me*Ab@%garmy;OL(o($NEkgQ2c$``&T&L*P$78sV z+91XI8SBLJ+^}AepA-9uMUflz%39yxuINm}L!$LOtS%g3@R&SrsswgDXr}BA5SjR@ zUyU=_@DR7+h%`dm&_hles~%?7oW)!(3HBK8!Yq=x9c7!Eltaq435sz9oLXpQfzyz* zR4S;^6S-zLT&&zOTZPGf3%+zR_3Zo=Gq$w_M&F--HH9A6jY(p+F*A=s1BkDpUXfq6 z2^YOU|F=NSq{I&$#>bJF5VvifDqq#&Va0tqn0ss z!cX2@c91q(RnhB@?&Oi4a;dPK$Zac%5-hdCl)Q8^7Hp?n>zOcAFG2ik2xSPQHT2C# z?Q=qVNx!0taKcFvQ|8GW6N}aOtkIYX7upi_e%1<0o$!*(!n88?)d33*_YP;9x6>h! zk?1-CNi)Hn8`Cu~g#G7z9{IcAy6H-%C)+r1)!Wi-*0b>~JOu@(ZNsFRRhr-)(7FUH z4;cWBr|}tl1d0`2SU47y@4{Hips{SE2?y;|JMpJvjO(B5DYyU%dalQ@JeQIZ6#I(# z0UDwSHY!>nD)=qJqW3qy^Im0GXbU+MCOj5qUR_UDGwQ-TYEj z(i<+;^J|DRFE)o^Q|gwY*MBz3m`nLPSt*APz(&SGR86W+ov#(oAi;b*g%A5VIu(S8 z`*B6<@y=}Lpw;Z)c*o+fv4T*Uqkai^y&q`6VtmCSN5XaW^O;x9%oo`)oc@jbF)NV@ zf8(3kJ>;y;{A4sH3cH@et(>A15)2A+IX$_MhN6wJP*X%B3`({Qr0l$wtjiTu|}gQ0VAxa0O8uj zX+LTJ?#>U6u7V2;}7bN|U*EX|`lNhw2fS16)5@hYq=yAM8trf^~c zneebBU&p?lI(%*q=8;p0e)z#S@CCcQg06F-#PREcVGIl?qzVX4#pg#dt<|t~a_#4E zK`PULuMBjeSPx>D>aK=du@5!vOMB>8<+fMwwa}~&x=Pe0>n#jw7K)R&q$Y{^O`Nr; z3w4!_3_GS~+DC?k&m&2>a%D<5DfgS1U^jKo0!u*UU~l%Tsaxz>8f{RIaaJ=$m3X9K zI|R+MrrI%-kEA9u`mG~`t7B-yB}--);>*Ix)vAv4st^XGPqj0!);ADcxiET;P!#=8 zI@Q=?`V}h)+YoR~z?-$mcn*F-MZv7pd+%2h38w~)?AK|BCq`(kGt#-6?pv{g+0~g4 z38pK8EK>1R?c`~Cx{wCp+<7&X)m||*+llT-Mir^d^WX3>SH<}P97eUrjw`Xh%dRK7 z&WZ$2iHY2)qE!aP#duz{BYQz`hW_iDh-HQ3${r%L20kWc*Q}{KbH<;Y!*HN+J2}m{-jsif z=1g|^oetJHykr;2)*)}l*herJIR0Z&KDm;S`aZwJ3Svy1Hzn4W`^zCe+pmV}YrW+I z`TkxUC(toZW80d~Cdy=LdM01pvL@pq@XZRXa>~}z)kBi+m21{0T%E3I4$Ykf@6oo0 z@2pFTE0~D&o>9LYr%k>Cdec3!`iOMWft4M^RK(c1GghmTe1vv>Zf~tSs+YZqjhS;u zQjp7+8#;MnhvLoIJN&KordbMf_HSWQUKr97eEqX!pg7>-3e>zB^Rd(>h!JdN+enT{ z-q%IY%OYe75P#}aCm?oqrn%;5y%0Eo-Sj`PbsW;mh+*~IwE21oh3uj6NOFITcXC+5 zwK~ou8b(+a?}kUDqauX8M2qUN7-^(a)~PCF-@)q3qHy3ddV*Cw<< zK4gB1zoXF-=D~=HV!a2`qJ>T$eSfFY7XfhV7tz9;!0)=7u(6HjXMk!8zw`s?KpY~d zTcf>5e<969=x>|1`$Jz+e#*032xM(uRbO5veZrfcNYGA-+c`hS^E+{dTML9@_|^_Y z1nAXC$fwP*A@5mYMqoGOg-R4yiWA@+@-sc>^(y(~g?C$V`ksL+bx96l=bWD2a>y04 z<9&J6gCQ>?o|}8u0M99HoD<00%q>4fr17Y?rmHuNF92NDO>(?}0NZbJqXyd@@+qZO ziUEKho{P5RCZ=uee(mqK^k5)lVmIt-oRBT&5DTtJfz`@?ZeOPlP!cCj@jv)2#~}NS;#< zNm_zF)==2bPy>9q`G2b#BQXJH?u{4Ctwgg#7lL2#)2tgJ9oOL#EO&fygS}}r%Joto z$D&8$?Y>fExBV)rlCXB2X6w<}I2j*$5StO8FH1V=C|X8(pDg;A>26Ayc$F8HklJ=- zyAqht1YXB|E(I4_nj)tz_%hi{Vjvwj*gKA{8d3SP#4J19`Dr-ygjC z!?DCUk=5eW-^`9%m0rb5N?PKJt00NE4*#lI}?GE>O7FIE^!qEaXOr z^f4u}%IW)bK*LNDnL_E4Eijudl2nA`YbMxFCrT>S4u(?a{a`u;jI*G=uINpZ8e4Y5 z)@V0p+vhfV4uRjd3nK&Yp87dJQ#CPcyl$wrx02993bL_9>qndE^0siCUTemmo zkTF|15bj%_7%5}FDj%L;vgNU?1w1Z|0%p{bdjX!DkA$tW-#D)s^e?Q2@phfPrKcl8 zZWq$@72rR+>I5lTMypxhsf(#gUG8*;l$uh=c#i}j+r2zSiP4r(8uU9esCvYZ?8!i$ zqWYP9oriD;XD`zSq7%bc|P28*9Oo#}p`5I2m@% z>e4Cpjh*0OHOS*INq3Yw$}kvEUW-28o5HLK>3sy_u1~tgz?}x-X`S{gGg63JiEe7? zNC)O#sj&v_c>3*_*R4hrd?#;0clx`W7+b0hq+PUQbi!IPBWAt%JHE|4Y(54Vv1f%0 z&6EuM{&VVl8~jX~KB0|fj`T7mpuFXG^Ew)u4x0sJ&kd+z24gA?UCItW=2L!lG~@kI zZQgi*qC4NN|I4!DO~lJ;97}hdOSIYHA@d1)RCuSVg8MNSc+QGtr#w}8ocHWUwHVtV z)_3I8g}y&OsQ|k;KlK%^T*4oQU*?~&t8}03>FA*z*RJ2?r(vohS#qCVm2gj9R9+lr z*4$tc>6lg2^Ki=)o}d>Z3b46L!|(|p@je>_q*WzW4c;PJF@pDQX}6Rk$?E9zZ4D2^ zm)ad;C7TAAYlfT0wZTi{%dp&xd)ji6VUU)&b+Qgdp}uYpuy&V!#F9%#eds*&_%x8I zI7ZcP7FggdJ8uP4NH}Inn-ero?azBbpPo~5vI+7BBMJ9-xGeau*+o&PWnr{BOJ;Qk@3Y1 z@D8{wA5QgEjRip0U(l?Oz4t>$WU7=R9jSbwMIR{-@hi0b2b|;(*sAKhvx}&fC%Zzy zEL_!boG~@OjJD@>L^S5cmAu*DB8hhoR<@|J3UZgD)VhwgQ^h;wxp4+B?B>gRJ)xWM z?E4@VjYbL7NF_0FqNLndMnA`?8vg8e%uXf)>0VoX2nF5Un2T_iMVLGd0zTFZ!`vsg z^`S{(yZkhK@IXB*^}u~6K)LMzYo$*z82?hPim0`-iw_z^^e>{I`E z=!QB(@~on;%3PSJk`x>@Q<#`;cW-G}!|N>@LqREiNW3_|`Ad&plmSva4R46Pwb5BJ z1IVoKAv>JyvAAkEQez9TXEM#(0G9S^dA=d{bt0LnTlSG{=vqSb)P_2+`hpl^Cg=%R za(RaZsQY{We*6)HrF1Sjmqi(6%O;Yg-E2#Z(L+kIhE)Q9HI!GNlVj^}N87Ra4 za_joc6M3Q4MpmF( z3{+HnHX#Fj=mukj1;8hwD*>I{?ou@MeegLe_3)>D5g7Y&m9{lj^3LL-9$8suCj5r! z!D`Mc%^2F2AGjZQPcp;m zSF`&+YzG`8ylzP_;f5~LB`!2U9~2m0ZGBMEumipnQ;ng4i)4Hh)Tjm^hc=XRu_|e6 z8SJ^q`3w!0ZJ|DZLd4K;^t365m{3#Wh zd&}O!^gvDj2^>tr|BJDA;L(MPx@^m~Z9iq#DciPfp0aJ*wt337ZQHi1`b{VI-rVF% zx_`so$=ca-tT83d9Mbd4zFD#*TI@kFs(~uS7^hXWZ?|b8ChV?-7veM5 zX}T_y$zPLj^&PlAmO3upTmB3kVY8~i;+^i7t#KfJnBs!H$=EN9>*!}FT$8sMk48qE z@DVSf$yC+?I6dofAe`;~eo%aqoIbM{s}|`JMoZFv_%ctGnL2}w`(}b3G#(9veJI|) zt?(vp*rzd-FXemnI3;E)U3U%}&9uR&mMmzJ^nt%NQNVT){gWqeN@3cy!_KkGo;Qz( zseGR`*Q={~o}`n0P4bJgdDl=)!EPx)0epUY`rtwxomw`k>*l5T$o^AmY`(iHM5s?1 zTNgUDedlLu%)0p>qCEEhDavDGVg7%@J7yv#Mi$2ZaUq$BiG`Wze}{ShXDLKXE4V_| zB?f)8*Ixz{Dy^;UZQUqge=9Xrn`YBP>X<3M07*Q6wVU z8-zxX@_G<7VuO4DP7T`7_$0WAF{}^QiGCaqgtQn?m_HEVW8MuAw0J)3*a9A$0#n!q z2)@4DKUOy&3qe{zf$~+q5Cf!^5TP8f^)((I9*t>yT}@(o_QL2XAVj1kjC^Qk@Qyan z8X!M3I0ZI0upd=y01lnNCdSc6nhvZH{4=8)Fo+%)0+BS)+Vk)rybZWBa2FoJoRR`W zITvuhA2#6Ev=8pBlLH7rE!HpWbMrG!faor7<|H*0Nu1KD9uvw2v>t*B2-vD|qFOshaX^24%i@kmkiSJPi3%uHTtw}d@%@zTsyTlfCtgm{8bE2$wJLSz&g5u zP>KK9JQ59lASounWxpde)!e^MX*U6GU$;sNHP-MRw8kRxyf z8YLt<^zyj-yk)#N$?si!3#$WJ!vR5h18k zcmf9be}>SXMw>wlJg}#K&-BzL7k-W}9DE9n@@V!ZPrhCgm<^=Emk9wQ=)&ze2L4eptfBP^O8UlWS^@Rj~;M+ZbZR8jZLp8n!19AIK9uVJ9wx0>_ zhCx3N-yG9N^X_^tTAiK#dbET5n4C#F{e=8>+4~E~=aX+7;0-BJ4b@Tr&)x9BmGM$HyVcW&ZSJeZG6{L5!c14PUQ>8=5?nBme6q?6TeasgD4;$^9udf_yv7yBHU15|c@yUNxPV^oXBqZVFPL$4-Wyk*?rpn2jd`rR zq|(L(Pup5wsXWjW@F&YOh+K+bgJaChnQ0f#q9~IJYK|%H9OQZ$P3!2%9-77SE7OcH z6};n%IURpu)jIihbHu{5I;V?*0r)w&XDUhS<-e852!_-%)^rYPuch1*{U)rcvqTj4}N)|@m# zCf>SeNY}RLp8K}8d<{y{HYI(N_fCj3Ega$#I74x#kS&X`6evAA%`Q29jjjq!|e**L&@_f;k>Xc=lf0o>2&DOmvYFBZDHA1BgXZfqI7Y%_9o#}$r zzeF<$19o*?JZH^g?>n38m^!Tn_=dsfn=Q};Rz;FKEnSd}KcaLBT3F?q{tz&8JMHZ! zR!McK@J)m^$(t>KmM*)m>G>6qnO@8y%i}_yVN;2O(Qk$4nf+V_4J{*DEu}UzoQp#} z%!DOs0S%|yib$wLYtOckC9oZF6EPFC&h@^&3XPdyGc26m_{dJM)W{RTL}0G9&)SnR z8-N7A->}`laCVktc8eRlNX@wx<)f&S8=~#UmAk~YLtp%j^^f;E0liV}2LM#k(^E;K zY7;*sa}~&N?vJ$XOa^x)(>M7%svG0t20R_d?HmlHm8_`R&Hjvx=P z_|~Po?}u}6W_&2kLkkhHG|7!kTA`RPT=*PpK7f*hX~I3~mclkiY+tirP)R3=LA}Jszy}x^VmM>DylCj{*(YQY;yU*QyH6XhNje7~s zVb7!msFGHcE_F4KH&?a)z4zvolb_)AHK#GHs)(FkjSqU&#_OaOwkeYR~*ZAqu>J{c{dcu8Q!A?=^(`Y&JL%@i>96PHVA_nS{K% zli|ZFa5FBaA#Kpqb0z0yQKp)Oi#>n(ho?Oh#%AKlygI>yu-c` zF?U~V%#VXg6^$$tiwKqsh2DRi*YO`Z^uC>^Fj`|?<_>9!cYjcS2r19cI+&LAn;+El zB8js0J8mv%e4WBo$W*mm@U=yl&KE&eKja)UlMYMZEt0X>dnj~IYP5_fDP-m+UbTK} z`#{)fxN0Bv;*nY*ghpR2IBH4mkXHN$5?-GVz%HVcJZY_(#EPmfWUGfGF`VIp{!(-= zjF4UvN#EU}!QDpGU#QKU=~%6eX2jm}2vQKR`LL7G=fDdq|2=3GQ#%IOKA%dz?p15E z?jbpKEiR&1)<^Z)4(KWe;_hqONF-w?1tC&TuqhmR(yyp&Wrn9ksrbrnZ}}`_iI^w% z{iAV0>z%Dn4mz+MSMy`FGmVB(?hR2ENROYj8i%qnXotYu&#kSU6LQ_Ocw;>QY{9Up zHAlN3IpOmAo#Tn#8MGjCF7}Uwz~xUd6b!4Es3hgxT#;LP9`hMc$rEV<;cb zSEYAyohtvs^uy5r| za(e_j9ZP2El8olx&rWU27e6{p2J5VnaucZ>yN8~mq6*4ALm|Vk(fbACzVqz&RS=0u zP_5#}R1@0fQy`pH{v;z7WTIJ3nyl8X~dmg%M!+`0DUJS zbe94j45O9pDBL_obe$-4czb)F8b6yieH1AAXvFK6cD&xz0CODg0AP?Dbx6cA_ZiKp zYVNb#PZ%?S_QyEIuL6;bupKWJw^Ez;s!%Sc+Obc8VY=tSKK5`=+{3XME6AvR7*mO^ zy&^~2OEk@_Wu+Wn*8k=CM(-0K4%nXy=kS;^Y#F#6@!TJA?rN9taU-U2p18W@)!>kf zg0QU7nS2N)G>~_NAIQKZ>R&#Lf5zj_UH@!^sP}M;j;eiKdhV#!AIOj?WA{D$&V7?E zNcwz#RX;y6{7bD4+bvp6p9n%|3DqYHp>(W-=f*pS0=VZ`75!pFeW@fgBT1<=XeteH zb9#fqQ9EL342fiVbK@jKDxO>x;K>>o)p=CAIyjY7HsjQw=2M_~r4gWPUt z5)tVzU_MGojnJyRs>fb?ei|Us1&9r#+wh5WcbgldP_E^blC|V`CPr0VYv~&3?aeW6 zsP2K%cCVXp4Oa=Lk#}ngE)RVT0|R#*BWH)WWdv#egrA8m z*NxhR6Sq9qBg_UIb-HD1)f_0(RiM~?)7scJQe^{frbn)bvs}I(6d{I_*QqzzL#GLB ziJB{Vn^6u@TP@?HIu-ah@Xw;zT2(vw&4@-ZomKe+VYmILj1LY==j8w&n-lbVqY`tB z@qx4s6OONZ_gf4%DP%ceoU6+{@=uN$%uV)iVq9Te1!f4_5)$E{l7>#$!igO(Wr<4< z!070*;L?4p5g)Y7SS9I;IX_R6{nl#khOcPV?LJRa+7L7=kbe+BV~$!_#7GuVw0va- zFYhf1s8c6@RZOhW*XCnukZ*pQ2jB6NcQ+~3$*_)Yw8R)w0l- zG?;UjMVc`}I6JI(@V@rU;;X(p%(dnK|6?mvC2{{8e|bzzhQ2GbMLA=QfFB|y70J91 zHiitW4DiHby%5eBRa@z>8#4do+MR9d-Vhl+zLGjj5yf(?qh}j zyMupeAg=_P^sLd_s-ED*cr3q&BY7KHfS6&}%Qd`ZzM&Am_rkD2f6DKCIhc8>be}YJ z!c|C4=SS3XuTd-{CfvTinJUVL^t!<8>xYpEou=e_36zlisha99m63cSH|*QFibb4- z72MF_>ZU{6WcEYPGxj02oy0A`#~Rh=MyPpPAZMW&YlJ|!2^5zp{lGDMFg!RjE$=~k zalYUt!GR}fOf8N7NJI#WU6Ee-pdIO>s( zR~863HJc?^w8#DVz%5=k4VK_D8S+g~?^Q?bQzS`>7c05!7#sOCehN%b`z!(pBX(V>qO-DsuXwZ8MLSsG@?PG`F8@#`S%{hL6hTpX=IzKOM*aBl{L zq;HJ_rZre)y!uY)1wZ3thlPMEMGp`Km5by6`?n929`u!v$8y0-J#>nKsEML4xLo8H zNvOp~(A*HK^Ew27&yNp;p?*n(;d6xPR=3wI-{UFSiEsz3)2_-z}4_=^L#RUe7nZJ*`Gs^D)M%oFeJ9tW3 zGC3yg7kJyZ)c!#ZTG>TsIwg^kG}6MvdH7f}rI(fpR9gN)IGZ-Ha+N$%-u0eweNg%% zH^(7_C&&+y$Cshgiz!=n^M8DIJ-u8z{V<95FM%j3LX+V52yX_rl&1S=@~5zDFlEgX zspfAqPbO8^@s+m9A|>c!sjzwx=7bK~AiCPq?fM&r@jS|qOKr4``Wo?{^d^tTC$k~* z3+;&1dANy1i2add&7u`}Bu#*Xv9M`oP?35&*vADTU6U{YWj>|co?y%tmY zLWstk$f0e+nx&mBjcOa2y|#X&hZBY4kaU%fard`N>QqnrG{i2)=`?Runnr%a8nR`< zrLq3fd32ENn-8_T8H43>V}%kjFzT|0Pgy9pb_7?w4s_`RPE1zWD&N^;Lh}zM(yTtB zF;V{qCLUYf9Llp>^Vc>PF9q!f{>WOjACP4~=z3bCuSyQRq#4jH zO0P$PKNLfSSs?Q#wi3Xr`|zX6Q&Gx^e_QFPVfF>)k?h-JBfm@n7eZ>64LA@49f2%r zyqT@r_=4E%8MoSu9A5&R%IO)d2-WSyKcDsL$u{f0#`|#9?65hXC8YK%k+Hesi5Qh_@HX2- zaJv^hr{W<@x`CBL`WhmK6{(K8lSMIfIhZ)F_Yb&o16LMahhzx-1M{(L1t6tWId%BTly01qx` zlB;6lL2p$5nF2n=(T=Cov0{wlISLQ_RYRer9Q`79wu`Jc;8+%n$rp2MP-r6NBi zStLRo`&%~YKnFfcv6KKR|$YPSE-mM?k7ksm<}BC6g7f`-Z~}ssDw=Gk!$r8Cj-{7yrBMBuJ*P_(W&NrPJHf?91p8aiWtoZV zowf|&loTY>pwVsA*sO3{LZNKumw2)q?L?9@X#49OrIcAAP*VrV27Oa;_TjR9P%XI; z-OXT)4}};a;qD0P6t5NBH?2~0J%Xv0-Q^o{B5;9Nj2`WhpzULBSN(b`Hrwt8+NBz0 z7F!0%R!o`SY4e7P5<9TlYYV(x-^oRWwoKk)8z8k);^)#r?&9lRJ?R#8WRJwK?lREPeQ5Y5g(%S@gNpcU zfTDnUovjSTIgGd8M_l*{g(EL5+DfS}+K(LkYrq)a?tWNU+<4d&Tp^(j2+$X~)irfq2IPstOXxiNfx05OXRWmovqCl9;vE0dv&Y+u_l2DWJ@4~v&Eh2n1W#8>sf)xx(!?@W zsx80OI?(g8e0T*mD$8i!Nq7ss1Y4*-W8-T||9;YVH9KG%S6z4fH>wP{TV0x}or`Rz zm@kED*zt-YFb>FIMXA;XZxgV2w-lNsLk)yrUfhn^I)FX@QIOQ{bXuQWBv;u^K-Cxm zdpw-BGOQt671gIAx1_pJM zzB&XIHi3iKqpy8Km0iY^`(QvR$hA4Ac74u3Y`2&!R_}{rJPI)^uSSMqnHmkgHv|$m zKP=wxU;*T8??^(Sv(3R)Yp!;VIMi#Af;UOHUyDx5n%jl+8d#%7i>Ui2?}u%a(mt(Z zy!|(++czPwa=kh~LLuIdU#MnREcZo^U?DWprv9{`yGlCb3{B-&6*#?w#}7?+S2bJd zNVqG=uxM3~7gJGkQ~u-8Awh6&8-5VQ33XljEAvt!b=AQmilpK!r^b^IP1WJX1W^1K zD9l|AiS=9gM#jwwP5p|mL{@sWI}WR#aq|&m4$dzzWs)uhY&=^nkuI;GOVSYp)MxG8 zHrLOSV=rwx@me;sdu{Y?sI|(_Mm~Eg#;0Oi?JNKl^2ATryW!qcsLZJ zfTxeX$EK{Q7kiu;`NVhEPRc{e>J>w%`f~c*rG5U?KQ54urBpJB)sGN1le$J)YDcVE3_p^tf%s%b0FNBO=71g7snpDN_BVEQR#2x_B(?Y z3PmxxNT<{pIzTB#=-*sQLi?N=`w%`|DMdG5lv{Cg;>$jhJ>GNbI^44L_v%wRoydd4 zEvP`n(uP(`3Ie55aO00iO=)=NxMhtG)U5E3IdOq%6@F1$j0vT;Cnve-w3%|vVaZ&- z4|lT!7gxRe19G_bX(&9K*uLgY&UGc|WQweLNJn+n5Sd!nz4)nK($Hd%iokk*k#c|e zh|DEsux7}9@arO=un^N-dJi(^T!=*WVX^F+3fV-s(fYYj5%b;sXc+hb9QIYd zz7K4!Lpe%azfIfvFkO}ejyt5O2+T{!N^L1DR zBxCC?Op{-Q;GZjY9-ML;d$M!OuDdn@=Ny9Q!hWd)Me8)O2;3e8vd&~`5;R_<-4m8g zNd`KC;it=KYLsnkM z%Wg=TeV=nN+WsQ7czY-kwRJI1dtV{^Qb5$0V@$=dg$hHamOV}umI+e?=m#D}x^_VG zUa9EfwEqIU;4uOeMQqD(ve?5i9kSfB-^lwgX21fEV#E%&>+13w&UC3Wn5%T8Wf>;P zS6015ks_7Zzd-<F-*=-|-Dj2MqZ5<=)D~#jnKgPCBV6`*G?Jgdg zec$Uq(>8AM+Fl9{T)++gyvmPL&okZo{V66>e#ZY?s_?v?y-JLy{u&9nA83;WTe0Tf?6h7)c}dLIfGaCs z+rd=Q#P@!v&;cL)rIPx|SxlO_G7GgSCG76vlaR=5 zBaRRR4Vr%X0Bia+E0q#Chf{RaU?)(;*98gmEaHB7x+GT?_(I7CswD%t{kYDcIS zjSlmF+Y(c^4hp{vPeOdUpPf&znUy&8=UiODG)B08R#}O_XJBQv%Z+xk@6&&m28@d={696o1!?5|o%~8VrxeapaY6u)| za`p5}eGahRW<@8BRZ@G!Muh9GiQ#3>SoXT8J)%sU9sJefqvzt4-=;!hR87p!vurok zk*Qz9D{-YcU#~R`)Tjn=z{%ry@VLDJBgY_b=vNi))x&Czyzoe7N0!X;Tsa3%HMBgv?KhB|C?1ty zO)qZWuA)1agaJJ(Pwn5^j?Z$pr^ayPsm!Q~-J!%xmM2U2&QaDEcOia!Xa&)fR~3VQ zoV#^vo{HYC7E2H8q#%V1rV7aT0z_*p3aT)8I^iYZiCxdtfE=Fnt?N>0*0q8$N1dF0b&p(NbA1M zuF!DS;BExQNZ?kirl84Al#81b{GL@yl*uAGkK7w*s>uJ97JM95jIVt-Z8KiIec~jV zbgOuD+jl$02+uycV-u`~w4BZ**x%?w&3IkhD0^HtD3>F|23yc+vwyfR)kbbdgdX?y zigTuVm&<(UW~}OaO!G!zcEaN5!7Go|*0M!WI#;!Ey$+|S6M#-a(U9aP8Y$E}apNnC zBrjGSEc&Lbk}9!D4`x}MXoR43=S&w%a%v}6er|(D_3#67pY#m8l`udM&b8v&?hgfL zDd^9MVTIjbFd_+E4XI3H8*-39+$Ox1hPl^%^oWV%uDdh~p-p>Rp8}g1O63!V?Nk?e zE_@MJJ{-P@U+Jb8n1trjv#7*;zvvVTa7EtO+5PzSz>7btqpM~wSM1(a_ZUyRF0u!2 z24A05+c~Jb8j?QjzZUJ}#PcPF=thc;8=-ssIA?iQVA9lD8GmreLaE=KM{`LP7_ul=V$ zq$Q6C2>83piIn6B-b2Sr*1&c@0~+@=k$jas@eQcZe8_JC9}pI+k{Kdl?i>7lakWP4 ztcp0a%U_ur&sDHJkVqtSeF<))NC=>rhaLMnViBwOJmg;xHZLZFkG|Z>%Bo}thGyw5j7sM> zGFR~CAE(^X$C)0Ylc@%A#P;g^ESg%^$ZxeX5S>cnWgNWPE5-YDA&Ix?YJObcPCNV! zS;44tl%}y`>_+;A!FV$x_#+r9f?-!-rN|%91>q@$t?<&HM^40B1_SP!X^YFJN=MF>52P^si9D-DYyDF$kLDgG~ zSr#0-_Rsjv8X;->G21!Z?+_QV-L7uD9BG-_F2CMd&Dtyz#ne>3FxAQVp=VCDsWV8k}9llG@nBh{)a}esV^qX`X7Z@u8&MIf(kb7-6_Z z(ATY_KY!g}KQ4qYdTpR&q_Mz{Y(fJ`)D6y6&k{s^koolkn6)EIQX zP~p@Sm3%G@wd%%W|BO2?2$d+iVRHphwZZwM5^S4R9mWNG##zE?;N#=+k#e{vkKp2r zh#}n?aL-!!CMLhf%ujcJk5Q%-I12u0Qp)-o0w$2((P70e_a`J5-Oy6@2uaxQ?E`HeXd8iRQ9I~FS`!)nVBx-1h~(o3 z>X@@W4x66lIRiWycMIu1C2UVcK;OWFcsyd`D#GB@U@07GS(XuwsC6$=L*miS88yPq z1{)I%Hv(3D!Rh%zCn7m1^8(E$0YcV?1GAmVfy`mUL5op&&YkDn;bjw1o9-kDBuT_$ zJ#`u*qnK7#q&&o86^}jomP~Rq4yI-Q?DsI;x8f>k+dM$5T}ySp6Nrna9+v|WmyGq# zh;7mA9ANRXl%Peq4c|#$Y4Uf_gv_>S#8nfe627^mw>G&yGdMMCrR^fmsA|^O+k5=` zB*m_kE-QpfJ;T8U;TlHaqABz$Cs=39GoNAYAO%kF!g2g-BFKy5#w0dI5M zmKuF8P=ZfEzw9Z#UB@qJOm)8DR41VMp&hYsI~}rrsRTS(X4_pJqRIPdZW8>bJ~TuxV>pU4bt5wuWShahC-B~|=yZ>$cIuWC{GXO&nQSQfn*9{+^W1cu zmn&jb#b!Vw6k5>?3&Kywc|CLd4&&z!(bYhQBr=~M+GaW3Ld|2FhLB2UTlUQ9Xk$m$ z?pCmTYdn9YrF25At{&3Iw1HUMbAv==6b1mntDSv>=`IU>^y?`Mb@}Aby~t%v#b6CO`y7Z>%j~f)i?#Yk;MVQAOJ)0hu3E-~e2dG;bYeqb~GFRc|`) zvrNw1-M$e4ZDu9~XO%hRj$g`@#|Rc4Y;o5OA*elqXt&sLBcVSsl@u>W(`8zcqR@S| z$yUFZ0-PkyFEBWE9XVzj>4of;*5yM)P2Vm&UpjDxm)37;9mK*KTm>*UU)c#1Gm%)$p@v(RGohgcGgjzw84Hk zrnQK-3U=V<>S0_JwWP3LlQcYP`6wLuR8w7W8mM1w`VV>TvI8eIOm9((>t6xICydvn z$XIzF{ZkLhl2=RHC`r;7z25PAIFR1-lsvxQfF6j}^`yPO;N;I;8OKM`lC*3j1DhZY z062ESxF`kY2smUy>c!Sf!E{~iC>`UD9+$7Uia+T)@|yv~wL20xgzvtmR>HsvmW9!Z z&z$i{UA@M!6GR6>*zdF#vqlAYfZ{xiv*+T~Tb%G(lGAKmYBF9;3oF+SsN3kIc)lUi zSKMW2^rL%{2J>z~v#%?1V>_XOkQ0rxl(|noAj!n{zyAZU%=te7%Pedh{~xf-#>Mvk zwkG}m+(Vq4T>sbZAvJInG_BTB?G9u-0V%69B(h@RKgEz(2I1HSp%9YfVCQJa=ZVR7 z#mezFNW~(SSYSKlufMmQzh2het!6bDPA{#md|r9qKIZVaO)Ug<*>qDl)nGv+?%;3! ziT3b4Q@%{rLu*z?;VDRdL)yJHP>dj`gL1 z%HS~t1cZd5Pu(~LX27oy8h{0XGl_yh*T7v0;m5G^A)5mHk@maf8~`!{8OHg05&x@>vqTOMvLzhU(dknF%idG>fkASshrd|ydGm`~hK6|z z{P@<~6wGgN?bWJ(b~xtn7uw?KtAz3M$d>{0+q~+B@`pl#LPN!b^xpaq3ncK^ZJ8XFsn@8oCu zu9w)uBb}o!P8|qp4;>A-unh(cBD??t_;;!hKJZHw{O(pmwHzOg=)O#2iSE0~V79k( z_C1ZU4d{3387$O@7OU@_qkr0;L;!awt?xJMq*wTd!}WLK!4K(+|5EY6!SyG`@h9*X z62>ur^YbgD=? z4Lg|O;awPw-xWkJ*a=)fV6&maSREv|KMv9zKVx#GO}0WD1m5uIE)o`brXN8CRCB=k zk5XEGIMx4_4G{~(U^Sxxzd`4lSirvgOdA046QYF*ga9dAg9BX|+<^6-P}2hMiStVL zMuYuI*c|TP#3nA^_7};0ul}@#_8ZvO!}o8oPMsL08@p&sik9F7VcwpUKbg147O~Rn z^>V$cA(AoKF{_K3jYWQD=sXBuo*#sgoK{?YbzAp#k07?~%SQZ}R{!CrJ9HW4$bvTG zSA2~md#OFA*2MB<>aJ)~ zC9afvYcdJs7$MrAZF5Mx&UwzF*22I8V<6oDeIVQ+ODZ$Z8{duH-cgP^rGQ$CL!NkL z(M0!l;X3YADP@4V&F_>q7n%(BkmBQ+xuNXMDHLNlR8Q_*-zAx zWY)1b2JCMK@89{aI*^{x_Pbv9EYemW4^M@q2EE!nMb(iwwtf_rN z6;)KidvK8zbq_ugzg0`#@1qTG)jgU19#E+b6u*>_zHG#8yjuKMHf9V@7v`uF)xk>U zL}Q#Ve_9bY5eB&>3$zm}9`j-hdkSZ=T@$=}t)=j!=5ZdcI8iYcYEJf&^OfP>9nq@p z+0Shv{cXXzISHxAv07HylGIH@Q zJjQm{xZ$9QelT{7x*Pc1TDj3^`tlMnWE#5Q;?&(f=4{A#yWucb6Z7=)ffpNr5ec1S z1`ArkRFw=fuS7xZ$&Zq$|G~z7gCEEDzE4o=_PFs_L2ad_Ggu%(m;UTftD&(>SnQjcPES%M(h*y0)3D^*6gvO|0#QGn;oR8nN=rAo|F_ha?T; zMxj{r&oKz{FeYvGuDhA$6PiAG*TfYh%0aT9z~%#0l*n&?DVu_(*^eblQ;2EpCDRvk z$HJ1RhtFTC6q^C?t4xD6Kp?J0mZbE zCX%|mg53xnWbQTZwx+(2Iv+lCQbwf}tICa3rR#5*!;MLqyi6+seIsn~yyr)_M2hg6 z8+fL;8g8l(*lzkoOi#aN<&g7^x5hQG0DSo))9D1>7-74IQpZmZm~-SuAbiM(P0i%3 zepEP)EmvspFGZ@h%Bp?#Y>CzJX17`|6T96t1p z@)?%pks^{zLfzQAAO!91(#mZziym%pCXSnEIXD6BgEPRlg**046Iz*Q*PASqjUP8q z8~i^J?}>XoF{edn^S{##4Z;CvtwMz8{-K_Kf%gQKI(Q@HJ4sA`piJ-V{*3d`Df?ah zY*2|aB7KI`I2L_=NH}hWtLASDq#nH*XlcPn z-}!cMx^+ZdxRkQG%P7kR)t$grW}cR@7QSCm4r}(L|L5tLA2k~1fzLe(sYTFJWQ|Zt z*B|h{$E+xyVaXS;LP=}O9Yaonk%NvPAUHIuz#ndmX4{egcB@m^z@(3JX11UVl7nn39;`O|F11} zj7jveHL=_640(wr^!<%go`XFJdDzTPxWDx7D|aoQp&N61;vXyktsLEh)TP@84OID{ zU#d$lj1sBdbV^E^{qFvoJI%IzisWR}-tB*v;>dd9D#d)-47)ECO*L=_Uu~o(oOSkP zFs*JMuXgT(It2d%*~1yNpAJc=_Qjw#OZw2AJ*A>6pZK@{9UIamSb<}C2`%+Pcbw7i zx4@NWMgRi0^uaXjz7@JvGlZe4W|I_MGMov$0uD!J| z4`pshE7oSx=ymBgvEVuvhgHYzHis4CC-Or&$$H5 z-i%-Dd*Pm^eo;F74mMPbk6eMYu25^?JS8`+#9d0NVu0#h7Ij|8U!G^80~g!79uu%Q z>95;Ny1Si8^T9($Zed_0Pb`bhfT!XkA*LR;p0stP{-F@vj|{;* zV$Y00ZUbaeupP8qTJBtU)yt^Y`mRcPUs(lEE3CJ{ zNK+GFV&?8KiH7cVzH7KxJ1Npp!jH=en|2@S?As^;I0 zxW0qajH>QcbE8LT`r0l%4ssq^SKZ78gP>o#fC?U_^OZjk)N$BpO*VK#IJ5d ztOMS2jz|++v4>^~%_M<0%PN&;3q9wmX8@sPhm6sjt)_IlKXRYQi$l}Q0kW?h2u;&f z^Y0jVaub119qSCO-!XL0Dhtf#I=DU5!H;}yUN=hYncNiR*re|24sO_&`y``N5zFR* z#Vo+L-nKWatPD_Nx%`)TT7@2$`XoJAN0Nj~w%W%8g+5^C%DmYK{e6U~Wq z?k5XG$tS;qJ4K|Nmo$~g`<@#n4^UH|cHS&t5|#q~+p?jn-MI}fhN13?hu*#%;u`~v zmWy__Ac6=Zu^#%Tc>^)5bbZ6^i@IV{*rIn5r=KJM+$9B&tQXiE$$jtqLr6ZOuMq2!CrP4%k&DAvrim?>$1GFu@h zC)~?VA)JvURVp=?Cn#yFmt7}CxjnY44ZmoJHG%xEOPN2T=m}6?$S9%YiMa#8#5vaV z-gYLLw3N5O3fI+KjhYB8Gc9Tf7c7@T4j-hZ;L9p4#`nP!uUs)D)x?GCtS{(Hf&!3)VHY4;=K<_9X5y!w@>>( z2?jj$18+yxyLVScM96@Gt=cu&jjD8Ce-{gASp~;NJW9a~iY^7@_zg9|)Vrwgpd8S7 zK%^cG{AsugVqvCQB9%9A)oDA&PnVww88G;Uj>F$Bu||iFGR}!c#ZG(rR!qtB6=`k4 zp=~8Er?On7PTh&K`&L2Iv#EJ^o>id6TbGkH$$Z}FDeaHK`*(1;O!xj{!x1je=l7UX zqb_{8X?nKeHIa+fCmx}I**`Y_OlNXXAu!Q*ke{KjoZ?Y0x_j3sa(%N7Ta~yD+>wY& zla@G-;cCd6Z`K;Cl_*4=ZT=L!Zgd=a7u&Yo*^+>tnp8X}J#Ck$6cnnD+hlBpaKFu+ z$>eI6*_n^tqyap9rhxUa?Lq&YV3A&+gu0%-O8FQ`^IG#~k#|GEbE5bx^oqzT z;uTdrqmW9(I`FQpR&G^lfZBZcs-cuy=7is$q=L1ovQ;!-e0*d79iP||>3u00+5jb> z>!|u)jGaS}X3@fB)3$9}m9|;wO53(=J1cG5wr$(`(l)w!(A|GTzrh=x*^M}Zb0gMX zd&|?hELHg6)r_vQg=Aw;H|WP@=O;Wyw8|iHdk}E%NzuZ7$=y6?su64=O^Fq+`s`!v zuB7wIQSP*$h}wV3&Xl#bv`N>h(4SOWdyL6AyW09R4G>^4)Vi*G`^)iCbXiha+S-cL z{_61SuuA0HKxVWQKfRVp3gR7GPe$;m8 zf7L}z_U7ae#E9J9k``2;GV&|<>rz$fJM5zG0E*517?TnM1t4NrLQY~&T8bLE@HKH@r0bv*L*_%OssqA&?lwsRbX*3*vmLXRn@(sGB zuBcz_Io1Hf3gnS}Zbn>JKW_O`#r?#Fxg)%fGo=W(v4GeS>F2RK2rM$dDW63bkuvsj zX)eW>G-6q?^Z+Tq+SY>%jdJLf^m*$nwIFzD8F!fwJwF2b?T>!PEJLZ_Ip9rx16tcB z0Bb4#CT`#1T=>4EG|Y{?vX|Q2+_d(IrBmp{XLr-F7NVuMfZ5LtePV%P>(lr9FsFzs zxBc6eO0H{8s@yK^>tMQBJwUs8pDUwYFLmhK`cx$A<{_QiZ6GYkLL5?lLq(&AP-T)4 zXE4fsoltZ*?uL3-6&0gKsH5pP%4TcaGXK0HhNFIZO;Oh=L8uRP z#COvBY6&%X>qI7xGdt9*Kv?5yuuyGt=wjvOR2FRaonMk$ua{Z>LY*siy3kw?;Ox*K zbR>?-0i5VDOMgIHS#6ICId1~8h9Vl>AEjH|>5pMQB-Gg5C?c8SOfLDOGRTU&Y) znz>um?;<}pSaEZls(cmsgqwN@eA5Syzu{t9fXZo0t!;ICeY2xaIElU7oMkLpJFOkk znwji0p+JyDvH4A7GvrVL_-U@fzZ%%)x(4M+CA-s5yK*TU$5L|Vm_`}-qHER^1M=ZU zc*fnEwU>x6ceK=I*XZOS*i7Eqx(mx5SYNrj8GpRVEBhW5)d&wN8vsd3DTgkr`Eo++ z7MH0ev5e0N<*+Z5EA#J%*4V7dU3ciM{5i@MS5lA^&)v7)a(K3kY84p?1~PAZu7?B) zZV%c#Aeg)RQ93`c&@)0!gH{r%j0IHqekH=c|C;(DyUM z2m>pvkdnCiU-2(b6eAFItkj&ZQUK#I{ezR9a?}gi)ia*xrkvvG&xCjx8Droa zu<`dhNA$|TK>mF@Pn{@ zkympaXo66nM9#4ou7X|XWPb;Cbkvq~`??D)XiN^NFF@D&T_W?D+M%KPd~X=1mmdaJ z%_~W~@?O>K27L=dWE#uv)JW~ArH4=Zbb?|>WB=^8w$tCqzc5+mgnhb;wgvTE><6F{ zN>-$5_ zIT=@aP3*?;slB+LaLvvb`%GH1$|$yp-u@I*s(yMBxK_&}eo}L)Wy8dpxKVSk-Bqq8 z@o^`Q&_dtbD=sRJn(pakLp_2}{wAgy2(3+_I@ET|tmo#VK%H4u7wH+#t-hW&kCIZ- z^SM{ho-c>cz`1A4VDegkBNL`gokiV8q`yvbQoZKiF-CIo`$@#(^|jpl40)jIsKtuQ z?2&eHJbeqEYe?Kr-Tz$^K5WRA)J_NCo+!B{OZ|HWOfK_qk&HOZ5Y(kIQSvR;kqmtD zlQ-nt*G(*a+#&#z^tcu0B%3wJ!#D!SwRQA_%v)616*J3&P=Km{eiYCYZ-c@I&!c-u z)bkq6YSCOk;&TIYJMM1yFB10ZVC8yN?oEaG=hfB|3pD+;uF2Y=04+ z4zJPCV=(gsw4@rOlHJ!DKdp$#Na~Gm^%z0mlw9P{`!1m1`j$-Fgf8wtJdpZMG7QZt z_71X|!hDSVCd&X@M%O_RuQd5`ZCF5J2taa_d48ok0-)kgZ^%`;4kbh5(z2rD2;ULU z&4VFnk}kMDU6?b?v8Zj1ecH-wwGxm)q<&`KDjS_sx^Fb`V4_pH;nc#yTzD?xF-Ks_qyFfUOjCIWq*@8idi2c`^zT89G@px?)kW zkYEuRSuz8;n4r@4;;F~(%TL#?+ssRLcH_31-m1@+?+f;iixI1$s#z1NHf+p5r0`JR zy`YPTGByzw9Wew%6zJ>QG_tzsDKrri^0$f>`c)t(O=ec>UAl$$*d{pgyEvW(! z1yu0Z_;~myG-L(IJ{A~UBnXahy{$c24+-2kG@HmElD+kwfD#l{n?b$qJyCpbZ!Z=a zfHZWZjRrar=nGk$BaeCuGWITr2h=YPmMxHE-wy&6^cHk_8;Reqe0q*S-H!?aVThI& znTc}(l5j7|G1SQabwiL<2XxPdk@K9Zm?ZA8Z8xgOcJk)zOgx`1um6;103bcfQ4^Z#NqM-gB(`Pkg;CI#Xzx5r7{crA0 zB83@-UJ3i>ClHN1q@5mnotR#}Tbe#U=NfxD1sFJp$+3U{dpjatpc9Dq>@D6o*zZxO zx9X7>!oUY%FJPTp(moL+2K!G$pi|JNAkca&J$I;UKiqF>U?QYER*+C|?tUF)sy@Gl z!)5!_UgOUb=5U}r9VP;IB%;@s(_Km)-j=L+s@cAuwjT`!$w^JE#WmsAe@FK6@_bN# zPDKaoys|blEU19+C{UBzuy{XH=1`LFYmm=eb)95b9I6+!##gO(wLxD$JH0(SLnx4+ z^hu}~2|7HgTSEWMz~VlpPt2nq+!H_HZ@aVa?BgHc+n;NR$<@V&IMuz@x1T!U1gP1* z-YfU6cf-3i4$(tw|93kznO8mMU%@=2-U&Z8%frHVcnV_ep5GrR$o!h&Ky8i8Ah1p! zurz)EdSBEj)PO+TLLa1FLbN<8Ft~3<+#FRV#LvS0pwUA@R6O|%zmz4>{<)dnb#exB z_+Ue(IYA)bVRtE*@Sr`5GdRT8Ablc9xR8+p5&zdaVSfg5xV;yC@?(FZ&&EfsH;Iu| zV1uuDzau}iz&ArC_lz%Kke(>NaX(J@Fvvawe}EL*dOv+TBYM_R1E@k>|L#< zDRksP2{V09DVs4MkkN_clv$zz@RjYHoB9hJLDjU4(LOWAZp<)4NiJhHa28)lRzfWk zSebO{CN$TkV&&0Z(LOSxvI< z%dC+o$C(BB@wmOcO`ZprFcY2@^Nx5hY#x`hIR=g|MZT@!puNCBYd4WIV)hEmbt6AX z28{(KARKL7ZNg`0byXYF&$d~S9WGC_$*9tlC8t^^TqRW116iuNIyVUM;eFuD)jmlZ z9nPiJV`C;93JaS7 zb|y_)W(M<}e`bBQPk2;YFv)x&tr0!{wgb=niI|Tj=Gk68Hs~*t(78NEPkIY1x-@HY zo8^X4^zDp>BuD1{@1FB!Wk}%__-m&vO&j4T&hFJ+GU_tbc*lXW)!XkgsW#^2?CfQh zlky{1#$XBQpu&&qp`A!0FISr|)8Y`K4DVB|>SKc9&Wwb~pxE{2P^v@UhhXZ3lEgR# z$e!(5XU4J*pI=$&1*K$(vSV>9%WKwC+8{pUAOcw!g#!{7d+ zNOER^vndl>n|JGY;+Y7 z{p<#2LWr20&3=ay#8a=unn*Qa-E$#=4&QAv*eE|&QO`-4Z46_juIQ)4F>`{nvQ{19 z%Ql%uEYrUA`$w~pndKm#&nEOlcRW|{bb;{Im-4+nmjE5)wB1edYxeqfw)zAegFQAm z6v#&Inc?M3Tp~olUw7uCzwH7x|dg*8IUT%lAp=S}g*dP08CbC7YTrsh%DQNrR8{FtwPr3Ye zT1iJ#>E{AiIHEYYm}nHqe)jHe>@Um&+927(lvb9%NoqOkXq zW1wuUZvNh3xs534Nw6Vgb9R`O4J6g0A^n^Nr1gtY8@B|-`)g~Nk#ERP-5s80Svo+N zoruimy!^UlW9Qy?l2G8k4^$K%yhpk%lO*r$w?@voIsNyJ^L@+W{X~=Q83#a5%y4&cAy$$gsMW|76@7H@U0F(L6NvzAXzBqdE&t2R^Xw=(M751aL zyGdzYRA)1TeYvW$?rc#e7R`WI*cHz|9T%Ni%ZA%p<}14+Zs{gm6q_514SM`ss0=NW z$3f5P+iZW_|@ z2k79x#v7&5+&y6)8%4zgAB)YvTf*Hf<(R-9q9^`!wR|o6-FGJxsMa^*l7he z!^-~mY513p68nHQ;RoliHH}o_->zZ#-N`5b+^atYmz`4H3+pCqaUXDC``_8*Rn)ni4NJkyhnC}YPwQLW5g+)z{+ClB7j`+5K@L6E5dKy= zA*2CYUWQUjEyHvIWH^jw7OIqI+yf&;lv7a2|6DqQ7 z7@+J;DLxb+gqqPl`+*q# z{l88n3GhF5tPu>^Li*L^#sh|+d8Zf*!dmB-lp44+5xY)5k!rM!)h!lHcin~A>Zj*aT)oE-dtHA{c$kgvA(al27J zzAlOStFNVN*=+~kFS`WJt{HZM*=^vGUT%Y(zSp~f>4G=p>(R zjxT47&1>iHs%`4nLMOY~YDqqwNjul4)F_apHJx7eD`3QyNZuCj?ZnDWcYmjNhktW4 zscoshsjlzwDbl$!0b^rxl>D;sJL6VD_sDI=Hwzq84*nmP zTm}4wzikC&I#H1Nu{yf@7tfqu+*@F5j+8GkJ{WwPrIGSM+S+CunX+un@7VPZvUeakB}CX{kMCQ7BpxXw?U+bKoVB;+HA0ctCxdW8~8yWZ=O2Y=AjtkrlF zcc?u#`;Bm9^x)6zUCuC}t9d>E^d;DEqWJ=FW*IWO!c4+g%Bkd)BO2jzk1DZ={*J*2)cR)Y8_a>p6Z3W$wY1p&o)p-0rL5?WP|& zQ{7}TV+8xKG{lzh;D;t-{+-)WTOcO!y0nK5p5K@Yc5%sVJ**aWr_{JS+Si5>bKpS& zkB5s%@CSASGzW+m?NA7(RQygeqelXQ4J_#iG|VpH{Bmgr@V})BI?&mhoLA9=ySSBK ziMH>66eYjB0}I~}gO(Q$9uS>MED-23zb?__jOBJ;}8=^52T#-;ML>*eE*+$uS9 zR=a-7G<^?2v}t1rHT`LuhXn}~bGy%6zd^Z|I~Y~2i;>8pJiyDHGE>OsG2HyC*ym*f ziU;UNN8nq{d~IiDO{cWpXJ&u4aryHt&>c)b-|WH0dQ zIG1&gl%Y861~q9Mm%q=WTD;~wH~13_p?RekYiRGw9~q~<1vt;Hx%?w@9ki`UvBCGp~Sc2f@%rnU{0YQ^IPi76-csXM`&x9m(3eyL&AkYK1}ETD2e!9Pys z)wRl+KIp7H1 zZtpr)0UM4Lx2Z4HFO+VO>@bCVT0UL0gprB-Ta)?TYC)8zY(DvPb-{dC4if7L%E(_o z9x?owfdQWkE}V|JnK6G550jSbIa@H_qY4U$c{dGSD?2<)x#KL4@QFl#24`q z;}xZ@3Lg+q1+RCNht2T{aQ<#hDxcIAx7q5I)Uzs7EJ}*y*$58NJ#_IF3S@V-p3_nH zD5@ryg}Bg|lViI=v(KmW76H#!)s_CKAd@w%mLJKt9dyp^C7BMBn!7l>oo)B;E|kgM zq{Au6-MYrkLLMd`np$A|n@S7XB-(>tKD9zA0JyqG(>XxQGpK6TzSZ$F6I`;*NzX;5 z1)U~L2C0f|c>0QTQqmSCjH6)YNbW~*I>_q;V5@=xwBf#toW$Ba+$X&vT}lb z?rIf&r#lDev@;X*VgJ}j#6ndv&wc+T3d|7jh_Qdr=m^o^6hJtR(Ts<-sg|Ys0LMQMxlNrmXNX`sy`UOOtf9iBhI_x6AxE(QjK>_sH8N zYMsUu3%%;&dCs=3imDH{X$FQkj?3;|C>iUH%flqt@3BIy&Ym0W;kh*V!rbOMdui+P zOV)h){?=qSToNECq{#8`G4}f*F|%R%OBXQv>CX=+CJKaVw-r-bhDG7JzspQI|IJSH zFTbJZP=@PG!1otvge!M`=xOO}7^uJ8>QPtLWiH~PW%Fu_)V4Y}1~Mq!6pP}3QEh$+ z4Xua0F|?Y@_q-M##xG#1aGrFkAO)q(D-}EH*d>w=Kj~Y-kQADqFS{hF09(60ApSYw zyq%E&1~f3yw|K^6Yuw2OU$Y2$FGg z^4xv5%u=S3de!0OF%XMk|9LgtHW?|G@SmuVYzJ?)AY0jj%gXtuSw#1r8aV#=UO`OR5D2>bB%svy~yBT6)8r2i8gipTbjWtB0P2UBz z+$Fu73Iib3<=jyHqqgl-(JhUv?}7^QL)5K;$4_BqSf^`0jA~hRT$W&rDT9&dc$UwRn^SRUk4EG!qR_H)^{;lGcq6Y2fj4srum9ex>PrZYg+x69A*RgP z7w9nC5f)jFWVi&?r$(X5vd3naw0M=^ZmYbMLT7u=XCO5m?lxXeNskR!t4*sES)?8nu%vmAUG1S}w=mGFPEyc68nXj3cr-hbKTC(BDpWC*%E&B(7p-@2~w^ z`SLk8+>WZ+WLJpFWytT5=c&o#rO+DojlasR4@{Te;+RkcxrtShT9 zskG80$5Fi=NlKkK6$kNSf8hqrTR_|+$MRPdcC`7aauc$#u5uZggpqfx6Ohw1k9JWF1ieTU;QB?vem~^eYNU! zgQcF9YnpM(A!KLjCU$?h@BE}9>p?twe^_!m=F3BtR*}?@aZ?8G(yAaVSUfc!_37oW zKkl)vtCela&r~;K711O1*J2>Ol1{O2&u`j=JNq&E=$jb62X4mm_AX)c#SG&7l_DBx z8@_{bn0TrV1T?cp8&z7=RI3->N^P4a79nnZ=U9L38AY| zvQEF9EO5VX%t*P>m^vN^s=S7M<3)96qOVl*6mWFlp|*xJ=*%WuI6idpMOVShfuB_! zJsS*pLInM;KZ||ju#O9Y7a4kSI$`ue@}0IZa;y4E`Tkx1AE$I}tor-ntAwqpc&Bg{rj zZ%yI!$;JF6GVPhBdbC|bD6m7t<;C z`<(ZcmAe78uK{nijyzCm;mpT8GkOw3IK?BrSl>J#|nT5?@|-?Fh0!%3qZ+Ty6w ztSx5yNGZ^7?j1;|Qgib)2@VM)X?gP)%1(dIkfLB@-)mT5?7K2{BeC{*|5z2NRT5;1 zI&1VkeZiXNBQB?Q{Z7;*W<|9MqWEPL)|tSaLS_lKO;N*OB{cN?jUlBh_<27_>uNo*uw0W+ny7o%2svZcl|oD2m!7 zA)`cqSB?A3Vd4S?BzcjT5f&fq=wA(z=aRxpl!!74D6gH*He^EBw|UMoT2s^4wP#nD z&t(SKM3n45gFOx1{hdD!D{KPvmrYwTm)8@q!?e0D3c8vm@y-6c_1i~7U1+<2Q_h`$ zYy_&@N9O3}?lB2AE9VQ6pUn7$kHyXsmMrWx_c*1ZDfFgqP-)f3{!BFq9K+gt6N<#t z(*~CT8VwQ+$Qs0TuwO@CX`E>u!ZWJ^BzNJl)v#C*`zDKuI+?LyNGRyBduRH`r{A| zm0e@Jl6ExS64W!GH7G-i4MkGkDy_3w$H~`mW8nwV8uuRba4|h_W!JR?ZEC}#tXi_y zU0S}@HrLdMzk)m?`Gp@vWSME%xTU4v@VF-4tT}MsNECd{2(hUPIK7T-$5>j%bGp;+ zV1FMZWIsi+QErS4yb1?)f#XM@vn$og^)6ql)HA3{cl~i<;*zBsZoCgNx4l*SqFjY^ z_>f=#)yPB+yrN4Gojz&b&aJT9LuifUX?qZ!d>nupM2l@kBjEdZ93tLFg`)r+v?*IN z5n~Iz5^JpL3Ju0*R#LH!4zH0A4(G*lg_Ki1jL*H?ZC3(oVwkV* zy+n#36A=|7_x0SBF>AdQ7-bGn_z$d) z^N@gXGnvuAL4W8e^;yBai1VS^j{Jy{yZR8Qnq=33Lm><5`gb?igV?igtFJoh&9Q}c#k%*|Uj(-p_vlbYrlEaGp{cCF(dxLlq3HOibCWm2f zLkhHkLiNekCLu4uUR7BHSNril)hs^2tbvR$sqW(jpn!$mxZMMQ&4J-yKn4@cQSI7L z*I@l)5ttU{AkIAe_x<`d{D8Xrdow_hjxaw{JA14AxB>_KaC!U%q1+H5+XT?A;rs;+ z^!;-x*aapKhhgpgdA>ln`{JRRx`X0C(N6ZlAwGX^1Lsxf1KA6zy{h?0#$zslh8#%< z8}wSDy&gkso1(WRp$u%}!$}ZB`yQ9VJ%I$x`MhAhTD95Q2Q%{C-k^fPxCMUF432M# z^noEfJwjMf{e%cbL4DIZK@iYI$(k2D6at(|&sQdnM@dY|HhF^2Z<4#($J(Xh=SR0=$J$fcT*m zi3AlC6wrt$C_tdTO9_1-&-6S#!>S?h0)Zqyr7*WkdzGKxqCm6!=%Fz8a(kSS%})Y> zvwkQ#ekp)K3G0FV%sT(r-2WK8F*5$p&j0X`s@h>)w&pw_?)}X3w22se`w`Dg{qx9M z1t9}=z+e4Dru+Qf&OjPyTp&KHM=3BQs_-3Y%DP=U7ErL)eJHdIF#j56EFd9wkuI{e6iQPxR(#My#m!6=0Uwx$h1zr#`big}r!$pBm zz)b4RA?M77r@VILuznR(q|d%oUKG1+&PH@;LAUaDcfIx3aK#zmjfnd?C<5^&LKVWDFW;2p>+xnYZx=PReW4&}C zli;YOc!;47U%^*=B1Qy5se zbT76Knw0Lf^JVLC1+(+II=86C8l^S-?l3#e?o1?-2bPep%F#zxt+$a~@bK&A;^FpN zcH>5xhGiaute6wL71+T@h`MqtU`{!{8{hLO5*nIW`X=U7EmV6#ai~q-j1D)0+_Y30 zD&r(-P*lS2TNOnW!jUs(2xhIGlo_!2#fF3nD}4YxU)fQ%LC8x)zJFExMvg;R;B>YAkI#lLz}yT^W*A??170 zLP^)qA(DJuC9P;J&AMOR3zt*^b61!}n%FrdIc@7IFLHm~vHC2Nl4ak9CH)}3FYKly z)|MLgl01psc8B@w$9I!`c>Y3C5Nh^MW!dP$aF1}R2O$+)V#*+iQ%H%rjJme?jqF&-_96$|c8ZA9BNt=oGeid$OY7H? z7Q<{^+!(&ZGFg}g$)x_T>Twc$XsyU^g(GsOhfAs%bK zw)1?CZ57WdDiB-b`|8n&NIO-F&?c!+Lln`!;1wy}DST7M3@XUA%?W1W_CYMj*8;~a z=#~FoYS!~xMp0UIs623T{0A=0m*eBaOmp5Ju8 zwRhVbnM(T2rCo|oxpL62IV|Ojs}Uh~zm2Pr@-gl0Zlnk6J-9x7>2-S3C*{!~@+J6RxsG zc;>1vW92J?Zn1X^P2_UbY7Um9p(+Q;{kO}9$}6v3xN+aLeADS7N3UJ)Y3%2e(=NT3 z17Bq!ey`CZDIxv2lU6&3euM!+Rayh}bUw-h-?e7vwqn*YHW${AiSG{ha*7j^#pQBB zQEB`_G~|--l1n#!{17h-$1gc-StV@n7#5=&6A#ibc3Ml%DhLjuTROETYRG+Z+OC zLP$Srl&}sZ2A-qE_yq9f_8du79z0iyjj-FWcN@NK zYd?jbJ$5cszT-({$dB%XycW&eA=I-swxy|@jb*c6O;ne9+0RNuz9BIxOm;0|ibB{` zBos}io|iy4%6_f2Wm|(6$n>GG12sgG zw+mj3^l%iN^X@1{_xkFSlMnU$k%;;1f+niI=Zkg|Bh0@y|NEYVd$Or*YskziPgiMT zn$`U`#khvbpM$pxVkw@g1MO#57@?0|n`OUEEj#|sW(eBU?MQ-`t z6}cr2WR}H9#>wRBX)fAh&K`A&>_d?Jx*~@@W-tKCe{b99@jR%l|0}^(m2)H?7Wdxk zDYZ}-Nc>}Axn|urEYdo<`b7}FD zugLtb1O_`WpoZ-u5L`J?A~b=$nf5If*izb&&U#;H?=Oqq$!v_qVL^nEN$7j7hCsJ@ z>gW1bid7Mh)baPhDGO!nMnGJ*v-eeXaBT<^*ck+{wO&%7QHm!31!GqkwIfb!Sxa}Z zhi0AvBiGxbBN+;Z$0A)+fzDuM|)^fNO>bovf{BMbwtvZbRicxJC|9onCMca6NgSC zMpWuYMbttrdQfIVPus6<+&&%FtyArs%qDbAV^VNK8tvW7b_rKQGTC_V0PuDRB2&E^ zRlYpt*EJyxOpVK*G+rt`kM%IXHSz3V@&d_-8a54mUQz38YTbf!s4FJe`3zQ>t74R* z`s(>!*BQA_@d+b;2jnK5WkG-Nv6m=hn^*`tec&+65;Y?#i+f-TE@$h8+-XnEaHZj#UPC0zjCGU77NXlsTfhI7IU( z^{yeFXP?Bq4}Mw0%{-30m4)-VYXMUifpQe)=A&n}X}z2QZDDsUF8GB-mO?Le%K#I? zgUIi*WF}F-r~`)pa8PC9B=IpHR*&r@^9vT^5_tR2ElpBBU4$}d*nX8@=rEzd^e@m7 z$GM$Ow?mNMEyH0DL7tPw*}fg`xToZy@J(qQh<+2grFT{ChgEFSNuG(GZLbZaHz}fh zS2J-V_0pBZAhimJJW7yG1$JsgSZyzj+K@$fY`?+jtAg7~58y`aOI?0k8+bB=vP*w&)2T z>%W=xWRRsa0@$UO8>$5ARPI2t(n}57b4j?FOzk>HdXE>oVKxaFacf2Jq9_q9-*7l< z$vn~QVK)*{!yaZwNBMKkc5TR(*kioh-``K4LU@qDrwjteLSqc$a*Mb4iyJ4d)B9nm ze4wsUMkgEl$wm~lwT*E~!UcLgL|HJtre0ZVYIDzIqN84zCuXz2nj@vREG>72I%|TL zlK1BO1Av#7EoZU*`4@+}WH;O@>Db-|u;E$VrEgt6^Igd;MS57p`-tAl56OgH&%RrE zs_$P)p-{&kGrgcOp$Xid&UMGpWo-HO} zo%dwzqiW6AL}`Z+$)G3}mk1U$O1y9Z$=Q8a-ZkYWA#A4s5cJpCOitClQ*I^Ic)&6# zly+!XDebrWkY-7487I-5EMpLk$~zYFRmfJ?1O$Hds-b^&)c+DnkrWg5+M%ACeM{F{ zqBvnE$0fKBo_2;?95EPgkok@(3(&oOdQwQ9m&AZr&6pYI46VY96zx^V z0k**4cxMP;^1I->d{~5PehHHpOOx&!zU`hsEh03YYc*g3q(okOq00U&%*Qmv0n0Qf zgo0n--=%%hJ@)7eV`^sT8h*`D?p1rZ#T|l9V~I9;iyVsoS(EQ9#1BbF+K+?>onY*a zj4mlf)QBTfk>)N_(l&u2SRVtn$1#c*KGYgBLn1s^{;G zlaf3G)IqUoCn1ytOO<;-sn`liR|q>VG9)F3M{IZECVPYd=ifsdvN)jzhntMAVafQ% zjUj!DXAi_fwkzMk?OYz2WnOHegO0gBfP=7aylXE>fOZn20SdvCD_@riqXFj%UMaI$lm{?sxz7(rQNs8 zI<)ScVzg>6EL;?tTR@XK;yN1K(G>8kX?j*v$1GIcL|H$ws=C2XlMcB&PqS{DWAq*x zd}*txSUXa5Ej;H)g7r!HT^(^|o|9379Ys)w)s9ye%K89@crGfDTDnbld>KkR@0PkK z9K=WtZ2EJ#8Ib&icl=BlLe2ZXxsm(|{Sr1F_@Wj&_i`BMrZ;IQybXQHgL$|IbWUBx zpPp$YHC=A@;=d1^BTup&5$iv7EkU3uD6OJ z*m|Q8pJ0}S#@{EGB%JI*xo8ZYc$>)2#o-sI-G5;Wa%wU{OtRL>+iK+IFk-~aS%n!~ zi=$nXHb&(ukfoXJSOP0)&LF19m!M)7>$*GDds`%Sc-tkXFW)TkxjKKz0SuC~YfVK< z1v6-(%Aox~6Y5_-jlIGE&A5!#g= zTy|-DT_orpgBf^9*?j~{@mmYHaW70xV%45jid{@zVP$Ou5~HVwIHk0|Do6~S-~}ID z8o<6?1a?gaOy__eV%EEhJJw;r1R^wy{XqSGgzBHzpsrQ zlxcL|eq?~X2;JB&5B)R$=;@@s)zMkV6VKrm+UsnZ)&crE^DT15MnaQN3`ss*nlTP< zKU~s-jz{)jsY^%C73SJIvNpeio_aNILS43>nPol`2p+i;hPqwruTR-LY7)E?Yo{|U zZTa~K9&7DsxVvwk!f#bU;dMqEr8{q-m+Ut7f$=AN#{l&-Ht`gu7k>P!)hY|LFpm<{ zVz9VK^}~c~3mo``PMMj4N!R;cmVd>wtZKzqMX+{Rsn~c2h!vDM}#=qT7ng!r!QzO$xU4 zcJ9VzCHcn~q=1}Bj1)QV_CrO+@9ETk>6uP^V!*%lpDJPk>jgeEA3v9%Wn&>Dx){^D zI2yh;CH8EUnA>GW(X#s#F~Y3yGcKzQSK!fUK!6dxvg(9l-qCukv*tscNTwvZe`>e`J&EYh z7S*b6(XJV6zp8xW$X@kRCKR{W3hCGLUj_N0I^(10%3~{u59DRZfr|g#lxF3C zgR&7_3t?$5kJooR5WBESC}%ORy0LGxupsQ`o2}*87gurpcHOkQclV8++tp3%fvS7a zF<48rs%5wmt%=1pl>ziCJFjbLU$uvT&s|2xy<0HHNg5i3-1o4@J1%b3`&MShhjl^+R_yjNZ6s1beJmXy+MOMLOf4<8!ff9YlR>q8 zns2puazSWo=G%AqrT9(K2=w`}*uQTd$$-oDJG{zQvq2mu%=uchxj^j(T9#EnjTwyp6T(jB(OPr!shtA2$P1w1Mly_IX;RiedW_ zb2a4QuG#@W>WLpsxPff!^(M(m2gSvT5y8&(^Bf*QYMFh~=o_?uHFN=({F>y;$FK{; zL$}Wu1D~xdhA<8}W`?9E5Hs=`Zp}j6jID>5wUCd)iPm?E(uSM`qGoFXZsTXeDyq!K zMO=R!Zw9Gyp^iKxZLQ^)Emv{1_u%L+5oR@J;a-ArWPs^mlAEgogei?D5T^L@B#*W|a;5xxE3j?ndyvi9ZGkM7bZfP%JB$p!6De=5#x5hbr|a5M zH@#i&-p#|*guwVK>Pv8PsTGLaz9{(Jvd2b%$9Jn}ZxuNym0oWb;JeTWlnyBHKioQ&y%3YjXW}74OSWjfJ-S)#`ug)T| zAc$j+|ghA_%{YLDK!Es%=@6v@#l;3>xkVF32Eb5h_KdvkHA1IYy%QN^LL+|GY zQ-oZCT`@2h)_(}IJM_!<2%n>+lwG*=(l)D_~lLIr_SM465-J|-(sf%2Z; z5lkm;F9=>J{%FH2|`5x}f2U38dONuMOjgko-`2kg`mi7Jz7|8aYU?3~U z|5g21h}fA}IR6t2War{w{;y%6E2K)&b_+d}q}@W%co-TmXz)&P&?8N^7z$A`nDAM* zlpTp2GE$KnQjr=piCBmKBTXKNv_yM-meaN04(?%h0(0VJ`-!Gkb@%Bf3c?>9P+bqI zdtzDe2*C%K+W>N4F?vvCWFR<<1JEGwh=0u&`{rhAdTHT$-#%n`t=2o;8I>Oks}hpl8JKcsq%&)%Se%#+(;0_iYgId zY;XKWtRHG?fl}!?h=_=Z{~2uvW1W2p_F7ONbAfsI`V49KHpDajzzY}%A|IcHV5v=@ zI9D{|vp2`b!;lURry~EWv3HCSC1|&W$F^i}t2QY1~jWK|mxcAq8KmowisZT%_dDbDA@H>w62SK23rx6h3735pz z+U~hl$bRU?IINm>ei$|2_Al`zAa@%x%&g+vp|Dq>AOHy9muL`2Co$t2f;_|~<~@S& z>lP=7Li`FaK^ovs%!zGeKxe_$+veVMuh`*_DwxywI7AuI{4i*UKqvCoxjbY{z?xyq zR_M>n6c=HfE<|rHG&cv3<%<zpe#&G18o2r`r%j0WcLO>xhOg$jq3`|_RS;gr`48oq zGL}BphVcGu^RMXH*#rMn6-N(+p@G?di65ZpBi7L#%kKVYpYZ@ge~9>u zLHhs&@$fhJXV=~hwT&I70$O~7>r-(O|FfUIlyeY~L8plObEOb85fto49ma@Wn|$(M z5SMsjhY;f*@6V<>ra@%TcSHJr#5D!;3HU_xqcT85MF98#qww<{8U<=1o9ccK4<|ZTYj{DT$y2xVH-&^vc=Y=g1MJN zT65GUm_6@of0d-QEMn!DuA-3you&`pInDR^RdL;v>;9^3dZ*TWOgc>66k*8giG{g9 z+o;<1e9m3>n2^;&w*dr?pj25zow~nWK5tpomsDL+p9(5NM+9M0{QfKoH-i`Q*9;FJ z%b{o;oX&VJPa-pcqoaW}yn8ML!#%KgR)|pJDb6W>R5Y6QdTq+fCuS9Yuj5843m$6J zldzt#`TU(Ao)*Qyt{;vJ@9If8^d*e-^s*U7FwE}D2a8pQac6&&<{wFE5SbD3$v#5zk2PVG7nL&##px0c_iAd};^Kk9UL~tWc*vz~{_km*uEW=> z)UWqK{B?u9AcjiICQ7SEV?5khGS`G8`=sqm(L(8RCaozs7tzo~63*Ny8Zt)FN0V~U zdrTw~q-B~^S-DQdW_^>-gCH$wA@zzpW#c%_c8QUT(s7o2e8`p^E?X|SnY}+mw86O4= zMry_CR%1rZ0{N!ae-c~R)%UWBW(W^Do-f5BS9u3Km^LmBmoB;6Oh@iKc9hX?UK;c` zId>66(zj$ROl1@dNnY2>kp&2+9OnQESKtE>31)D$0+fjozNljx& z&4^#ri4>4|g7(~R$YzkqL^OOgoSieKUwL@55_6@Mw%&=zSv0i^$&rYQGHpT=JQ?h& zN^=>0EhOZlI9K$niM}VkTWMqR0D-kaje2sV_d}%dN%C*|VeQ4_RuQ})d&HDsPulrb zgJgn*g7r=u0jig{Azl6 zdD!`Gx{t&uP+abwQ3{`VFL|*hrTGyiJ1y&sFCvV*AHvXYK}-O+-*-u|M#)e`=vYXa zNi4K_#1Hq2k~7eEJqsFk|lpj=r&kT|wL5(NKx6^S}&FCWLD3S(E#phC2lV7o?l%5Eur|m7Me9IS^ z)_SC~2v1qqd`lY`Umr-T*;giHvxc!#ub74djcTd3M(X;MXxR!ao-A3Q;ESbkAfCzN z^D!ykNPVNd*(ga?=Zaaq^G4_mBQ8~7i7e*yjOy#vcD244BouqP>^`u8mNG6Avw)(K z!_&L_$tTG-@0)_O+bZQTkW!3(o-xETJcCmh4{M564J>-QUS+_x>P@X_JysK${&m0L zpUzzxd%~M|Aq{%Wor5DA5=lmKNDx)U(KIkSe(!i@-K4LO?^B8%`bUL@b8}pJrp>lO zkdvca$~mUdcmvWQq@KY2AvS1X-g%s1STmL`snKiQpi|X5iXdJl_*_;%<0fTf{ce0f zIEy)lBZSBwO**v;ujouKQGN&!*(Pt}ngZ-h3w7HRP7LP<6q0i*tv|#l3>32^MDYhe z(Zf=PlExbjPISsqfG4wWC#AJgb)1viUwLyU!raKi5J-zefKv!d9bBlJW@N8?ujUM; z*?r@CuxzA!iX>C};YsG-$#Lnj)lwwj>QCSDh0!jM zrB;E!p~ELo!Sz<}Yg^9S*xVzF!rj9g2ZXUlkuDlz=(po;rEg^;c|A3*IXVB(RB}9| z8mbz2CKs^p{~hUk&v-r!@aY=yTO?5gMq+CWPx>^hCIMCyJ>RIFZ7Oq2n zJJyye?ZqWq9tR!OXpJ*M_P<(iEhh$(dK^5#9mzR5MlgL9u3dy62s-iR$d1SY9oOPs zG7Rx;l^%D|qel+orT($WOjx8t3NVllw|R~13?Cf(r&9dC*P3(`=VHR>90SdMu~ z?5;(ZuGw4eS*~;W+se_QcKh1+T3mPJ`|Z zGj`#Y&ripOAi@8mj9b~&X3fm9ca6FD0*2p{!!VcYCp58x6n~@$|GQ@{ET#>6aIU#? zb))`@>9tX$D?|5lXTDUYMMVjUyp??0d%6`z*~48)x8(3$eAB=^zp%u_W1*+#tiLc|{}-O$5u%gR z%XiY0r+Lnni<2gW$pOP%(Cd5R7^HlTc`EhRp|84#^-S{8){~t9>LP!z;C>l0QY%zt zmoqoR8_0yN70^L7m2~CievtWvu`H`n6`nM*{-V0KmfRLLR#ZKk=Lnek0gHI7)CdIIvF^Qk%&fP{;lg=r z<5?3+hEq0t<^gzPx$$sPU_qWc0HSNqS;IlXBrDS2t1q*{DSJw^3b)_E=52~{`9s-9 zwrCk^_c(UDJ!^BGr#LwK;SQ%omXoISHrzQ4{wb>c7&YXMGrYT{5#|f0c1p8F!;V;J zg!7i)YDeKhx6KRH^qo&Wjpb#u8hLoL^dxU4l^8q%%J8&-%+QgPFH2~KWSM}qFltOE zBo`4ZF!@g5b%X`ito<@D$#n?Zw5xsKZ#Yui3AY4zZzETy)}Wg#8c5*cpbSKMj8`=? z@yc0GMX+S_qK~!Mt#HiN&I1RSdN?*-T?adoyTTZQ7>qvevd?4JQDZ`aXt_*e>^yvR zT_>1^IN>Gkn~Yqx^2uRA^#>AVQfl22G3*SzYK$9Lz{AqD=;ni8Pd+?XXyap(e|*LGqbdJ8vEpFlvqK=@)VF)C!~`D^aIhQU-cLVe)Q|kiSBM zp)VyM)w!UWcn|&d5q5lpjA}Gh{%@hT)GeZBLgEqYBwFqq$d()2q&*i%#_|%CNhP+y zO=%Gl_p;<3puIR4?gQ4_#fF28UIJbDJT#%&fS1&6=HSnN!^WMEU!~<^#s%P?Hj7)C z_S%|5hLe>0)u@V67lZ2H@??2I|jBcc^rE z$0cmD$NkcfIpas=W~D#!jt8Y!E}tOSOiTkZ_vDhHQ%+@BTJYyMmXP8GQkG&Tq?>ZfR6KQv?3YNVY$-YYrlmkH8;@9UAwMD%H^*;{i4V#?qjhhYf41Xw6sg9RYA;eVZj$fn)s88QHYAb`V6b&6 zg_Ed5aepmx5#G|Bb#6PmXt_PfbI!G^q9d;8fv#=!I;zbRhbQ$!tv_)LY2499Nu)Zi z09i84OYNasmz9>Sggd+v!rhntYDRzW{>Qs^gW!$q-{TKUZAh@Cb$ zOj1Fca0Uz4wIuL>>Bs%c+wQ>bkSbZsnIRdKCQ#F8Wv$HweQC$(qt3>#qPVoO#_!ZPf09#5DNJCQ4kVsy@44rGvR znp0>L!pEgh^;_H!M33w1zCX_kuO`Kb$LteU9JKa0OlIk#>F8G*BbHq`ItPC*vJKZubG4G7>A*?%i!!1Rw%9BGfS={Ux{08uVIBfEq3i*5l5!0q6(jKTbA6OOAXo_?7Hm+`1h6%hoADXNs1 zZanA)9g5zp^%P)Mrpr_D@0u{9j_m!?8h?*0Piv8w;rYrc(alBQCqvJ)z%uscRM+Pl(DmO{e|DmN9qyEj zqO2?LjhFfKRX=oIhXr(~4|^frYui+6oMHikKe$b@9 zA;IBgkGbYQxejbDXJZ#eIaLeF>F1n|?Pdmsl{K@3FSb(~{*QZWw-c?kr>*-*2f#+F zJV$&9v2-j9Zkej+V5-5%&&;LIi?wEm11SK#x{2=%+4E$Zpv)6SYaonN#e|s?m$~!?cmSD zqL<1&htbSQ3lzBE-S0DPyQ_J|ma7q@yE$+7%YTZHHA(-Th*iPg<#z`KP0t<&-Y0F} z<3`IW=tnN1K&Vk!B_vSDta-CO+jI;tn-!K_i9Xh0A?{Hh_pg!fDvDEcn(facZ@}Pr zn{KJ*q~FG4uTL0Yag@{2qXPDnc|Whx0Rv|YRt16VKyL{YV`rxr7-yDqFPvB)#;nj7 zs!~C1U@>Dh&eQPHjTJ=kbEdzMMOxWr(GHn2a?=oYx)k*^xsDrZa$ii#uOBXZtQ}Kj(w{%68fjoww0)2qHK#Pn2UZ#Z-F0%);EF~gZs%T$ zLgu{Qw6}U2i&Ly#6N+Y{-m*faw&ZC6ratXy@a%a%CaWBofjC8HMZE4rF8*qegk9+G z`_zgS7crj$!Hg`ga?310Vd#KBbp_1z_3Ksx1I;Rhahv9srhf{J; z%ht&c=`P@3wxSTN;1qrYJ@MM{MOJ#b7vxhgZ!tdiMQONpbuX<5nV+DvU#7fWVOF}n zQJzV8euw0`IBok^nNoW#8r@tlvA_4$p@evA)#~tLsW4VDBkFqL6W_wJQz<~keiUDy z{=3!9)O-9avyz5Uj{ZABLuxd6c~KLHFQaf5IQ1#aA?;E`L@Dgo465;E(p1o2u%Z}j z#3yeOFc|lqHVc;}wYf^N$Ub#2xF{&HX^JB2)2J@A2b)bI6<15N7ss6WJ6mdu zTcw1w)i#W@Gg3{|O^bVNcpNV-{v=sMv7$(q9;few3HN4cuj?@e^hB}zx(x}lGMDm@ zOq6`@kX{Wzlm{ot5@)RW!=5wmQ8|N{F}B>xBf>4wq2JKjI=0i$13dz|+$Rs)woP8b z6^(J^m+qWSSGQzG;a$2_wyE;9hnI36uljfh(br9oocZaPxkvFDLp|ISy=POm4`LiAVkbkSZI$i2(-M#iinWaBc^`^Ts9BT8Gwv$Gi9$(qh%eslg zrCIad#hpgIC3Jaz&+j6pUvMK-f5d9Vk^I#EIw^PbH+4~cv(%Q6t#a1s-*D|z2`j<^ z@|sumQwmgbEX_C7vQhQix73t_)tWu^AqI9^!Tkj}6dFl+caK$NxE*J6i(F33l$Ot~ z;i)d5suRpjULjegz>FoB{hieQk}3Xh5cWN%o%H|H$r+sGdl}qg7S)q@b zW-7O2@gKCK;zwUTh zdvmtmj0VGqNyCxlTiasSTf?=el5zj|21Gjaf$~9K8xrgQd$*{r8eU!^%%PA&8R$5r zUb&ahlE)GmH%+(KHQrmM0A%h8?!ff^cV#AR?K)lHxb0!JxUR`-Bb50F*D!>XH1wD( zpEJ+AzA89PI^<c>MiGZB1eXIZO;MWL-l=MAkgx+2|oREln8 z@ttGep3qMB@V?%vi5!F zf718ZI9NFTpAkD}P?cZqCEXT9bWtD>(f~t~goGP0F5Do1@MIr@GrJPfJgE{GEYkcI z0ilE&djJH~=LpBir{BqT^R-UnGW*WQrP+!xpCS)|E+3X_GS+u>w@SwHTg4vDF3)DWq zJrI99UL=oKZd`&Z2+;uoeGUQKsD@y!0=FQ4T!0P;2$+cbPjN^%2W^ybNf?MZ20jVMI>Ds`b@7)dvt0Zm=NYFe$ zaExDyoS<3TKy{u3fTxpxO#_y|0wmOru-b>PJH)FO8vp|R>CVx&=?@i1;Ex=bFad-( zIm0G0SSz5$AWj~DEGVmP68JeG08Hz&SW&*j53hh+1A!DI)XQpLe&9ZxL_vT6tMn02`j9Mv1ChT< zxv)aCel!c|@gW}o(r)vc!GUhS-oHMkU})*7K{opz_#by(pck2v6jhWCzM1cOjhL7q z;QiU*B_R49B!0P^cZK*w1)l&rekpT6gWoOvFS&nA+E{^ZPvu)rjo#HqZ2ds{?pAQJ z{QZ{a1@cs(LG3@q4@krzG2re1>Q)0OSG~)Dgxw=2 zre+SJI*5W4E|qJ$Y?f{pP)D*%ax{}SF(u~S@7b)K=R^Nq?0(dRT4jaeOWePnL*)pmr`P9J zlk>;G)HLEgd&L11jdBH^uY;HbDLS@Ejz16iHz(-(tm}}HtDECqyGjyb%S!Z=z|ya= ztBa@s32wa6SjOMuQTX=SZus=RuadA~-$%C^#!9W!dU875=gS>xJsn_>^bkK!3p+J2 zT0GU##8CHW$RF0wTrq<27`4d5+RsY8=+-~}D9f#xPX(1d4_{*wUh93lh|B{g(_^{A82;$~n zPn1cc9E)1;%fNdlfXAeip-zR|_PKZy$2ZE?!*5>xO9yfY#IT~n`v>dBnn2_LPSb*uhd6(-rPf9H$BdxNBuQ^3`UY=~x8GjJ~x@7!>BdSRJ z)Q8b$mN)QVMUIT8`wmrNbxC=y?-*#?d@$C{B1=CAHUI z{n|pj8$7C1Mm+uNnBmAjN)~@iX6ZRPr^*-ApS~tBvxefRmLj&k-6L*ot^eff;Hn*6 zAfe5jSR7t8!*g`SC3sWtzu%H;FcBH4uPu>ACmelIY`%yW1BcimCBkY3Qq-tG2-=V{ zzd6i|GwHfKJXvjoMv~@R5a--&S+~;a=`D8B`~4V0LhinhCy3!fA63_Ka&NDoDAx~W z%8x?b1Z83RVLjKTbDE&4SS~tF5btu%v+w0?07X91KxhglE|D3UQe(Z+@>sJG8XVg# z@_o=~AViD`JZAt2wnt{e<6tQ>g`#?4J*>wD73}T@c43-M< z-u(KjzZEJ_PR*p(j;xQ>$uB8UTOZ^r<*2kbKHI4pujS$AP}UkdCXUc_fHd2Ql*d`o z-JtN=|EME^p=+pXnVb-(e-gEe#!gD`uhZL+YZ$TwjNssL#(5`}_q~VuZ zKsg*Gyjt^ppF?D?`DR|BMFcWa)j#P>8yOPkSUbeI<54jv05VJ)*x&Dqn{IL~>|8@v zmo-do;!y2$yk!PWTJ_oduB#D$(!8wZd}Jy#^tmPx@$`6#2dn>h+-kF-OrBYsvk_-1Nt$B64Q-7b@w};A6lxqQjICP}A zgcr=RbBE1A@dSq5>M!q&s~MzFE4Mb- ziv}4iKI8;H!j7rjx`i8w{s~W*ss$PLyh|yfF(O9I_6EH!-uvjQFJ-4ChM9d46$_1M zudg_%$JU#H{pAAEK}?)SB24m(?0SWB(A?S|OUeQh>U`A$4`=yT!|_C~a=$+_lk2-5 zk15nDJPX>ot^6_t-tm*U8LTOD45$mZzABFV_tykYYCA2VCM%8lg?;2fHy;gq5I2|M z4jI?1x9uD7!Ww@>%XqES=tVhU@YR8S{$5TT;d5x+f6%oyu0oRB*!`w8VL_#i!Z*Z? zP-jCSS~pGzwDmqPb@;<^@{!G|i=6Th%`y2Fc9!ArQsD|lE#!&#jACA2z1cfgGkr~O zR$pa^mlwlAMqwVRRvdl*OBn@&nCg74_P0hR>B%Rbfp z(;=TTY(x~y*1mCKlx?`xn}O~bnU&SYyT{fXj5)=y)2yT&jfbzWdX;yV@YodZmT^Gfp$x}4)^5lbjMkDX! z6-HRTy1>K_V_i1{)cNRWq4u>*3ruscSkP^&e+ip6cIf|H)`Lfh-6e%39qO^k#;|3K2wdB)8O~JqOoTVigv&ANE%N z)OCy4l|nEJ=&Q@}XV-XmQ|UXaVL&)4k5#VjWx_C#JR1FjkwjMP4y4lFCMY`Chu*A- zhLc6IPm9HDe$R1(>b0~(4s7OGxTh5g-JXW*TqX)!YzJja+)W3b>z1a?(3WN;trEsT zdP|z5C_0O@RtA6KP}U7LL3JeFG1|P{IwJc9p@npXt@ouVcEj7`wF;t?n{+;|yq+m{ zfqQsue(4-2-XYMASO%9ttZ@@{+=7LM@-y6ICC+(jQoMKP4x6vWq@H{2dVy_j804|LW z5lc5{%`(wzQqgsiM-?~mnl>RbW9FLoG@|XqnJ``$N4UL1?dELw-jWABQKTWz0ovea zN*A7r*Ld8?{xyjx1#PA`_WhTMUu9omqGa-Qza<>nzs$YsB(rH>8tZIQL@P}>Btw&I z8gEvP+Lv4B`GI@#TuRCQX$4B${^3HKJ?+wsf@q=`VHYruk{LW|KU{n<<64@uW5q%D zim6fq*3Aan6S&wuLXxfR*=-;urEL9<%(v4APikhsf3{T+wp#5m{XB+3wqpOggm><~ zs~z&fk>K*{y68G)tx}?(AGFwah}IpU2=#{xUprzKv^9>L+t=lhDJFs8l$aW?aOI** zIxjWNhj*rx8?}gKAYmB{;E2^%C;w7mkL+KjwbI8w|5w)bPVxag-BRgUf+IntvYzK` z${uED)~=IQ&_;&#(YD(3rorN7c-L2q*Lok*L?djB?WHuz1q?dysh*ur9MOijG11qC z2_SK^JC7VhY_;YPg&nE3+wHbtU8j5(Bv%KH`Jib@bx4-h30@u!sj?fTXTCh<-ls0( zNHOfyBS;shoUmOyaEzH@$l+Ve6*|!D2%7fQ15_m=&p@hRGGbFC37Y+EhK@?7E;)!_ z^+2~6%pGUTxFln8CA!!I*H!t^l4)l2%1s6}Yve@h@-+rJ3m6OC@|(1Kbym|k#F|wG zc>755S68X(^*0nG9^J9U$Bv0rEt~K8mP)T;R;p?OUx{65;7a=n^P+&<=p@kQ(^l!5 z1!naPdOT~RfIDhFK-$+yrU&f3Qum4ZI=0RZ2R0kU#F~lG%nU-rgbayH9o`$pd~@<% z^k)ju3eA^rh;d}!sTZIia%WKOWj7?4Gd^zxe(gV>f6?h{(_=Mp1n@peA~?JWwXD$C z?|c-JkV=jYz=dRTW2eXYVwA7t;~<))EA@76G(Lk=pC!?iS6X~HS!2^eKpFQw#>}WscZ0$p~o~X@}a1YVybunR3b%pcH;h-oVmU2EurO>$09rtDH zad?W*hlO(g8#365qJDT{n(so(XMVQvGnfTARqv;`nBkXK@@NR|o-vg#(?#w&#MM4P z`2;qKspDi(Th8;(5*-utB*1S zc|%CJGfxLx`$fc)_bDTJ-POsmq^imHA*Yr+MuDbSy}DdOJ8gHCULGfB8{2^Kd){gX zk!VbqxZnRrsy$Z8Bv4#DL;6CJHqvV1p)kW|`g<)#k{yTH+;BUzl3J}6A1%L})}c5S z))$Q+lDT%Ua;R4sel!umHN0H1Z60S7(UyWf=Z=+J736y}rF$d0{g`!Oq2b9_$@p-H z-?Joe#zr-C`%u$|)#-8OA)Rg-;~I=HcLLpRFY50YMSv7os>TeWwL*L@b$qO?>$Ov% zF3@V@l?8o~P-ts*L09`9ge5^Ge|6-oN=a_8+5g4l|fW8?s(i|;vz(4 zL}ROHj6Mr_t@Ua5`89A)NYpwJ^#(XTX_PEy0&F-tvalE}$JvC(H9CmRh zb3D2R!x5=a%nFEe8!VHq&XMT}j7j6euPIDS(-jpqDsCtIv2CGV$4ZLFLM%h|_OyIO zIo<~piPCG^ab@wKc6%`8+X!VFZ6@$Q!qT07GSg`a)~Vgov=J2ov4HF*B}hhHrV=OD zCt(gW%L3BFx8K~1XbEE(r$zbghmGLLEDRQ1G|YTA-zLc(iwdNVv-CVMxQ)M5etEg- zZFlzbeA1p8z{)G`PF)_b9?5bpOnv%B3e8gG83fbbvaXwt@1`dfX5nNB7FOBh2`3+W zRw#;WMVVKkd4Mf3Nnt5$qV@+JyQ=HpxSJG0PtbdLpCuN@kn~Zr-2JM^#~e6HHq`hm zrz-kM*9M{d6NV%H_|ELpXe(6?jSzArquWVHSMeVtX<1t=I|Q>;Gmomic603>(7+ZwLYO~BA+R{{yXD(;SKg*d=7H!v_6=sbaV?d@?4 z3v~rCq=zF7y17%i{2?KezedrS--l--WePZ4Wc79?djn{W#2fD!vI0*I9l=V({CbrW zZAweurS06$>=1PJzM98*DM$B)8J>U%;iDuOQmv^zBvsqG_vKtoR}d%)=b|GU+rF4j zmom>xCmlLl+gcxpxSHL?wOF0Tz6dpTj|O?-b)2R~s(B`y94$A{&*oS=IXxu_8YLx-YsI!codu19~}_;dydvyGd5lnI%#`Oru9@co<( z(7H&ZNv=3(X{7&NmrdF%J1v-A&4&+xa1LRfRK)twrj;YbqggLVFOEA?%}lD{`+lgD zHuJP2^Y?ku1No(N5>obXVm0L~&JQl_@_q7|_dP7feIz~kWEG6>F-)5v>G8T-TCi1S z>{-U9@S8R&61ldVZt3%hH_G$GGg!-MnYYpTu@q1gZjbJ{gj9yl(DLDMFC25;B?RGX zBJPtVw_#X#$xCd>b8w4t1H~ew(>fgj1~Jp(WPM0wu_0;OY)9^h^B*o|N{)S;y{(`) zW$EC{V~Z*9l*M?LxUDrbZ06pR-ROcF)IK6})tUR#RbC%6&73cM{)1yH*g9cIXld-M;@~o;M*2^&X_s8Lfc7e-94FTvIsj zhqrmY-KR*wyuHvJR8o;V)?BEEWYS4iB(K{Rsx$47Hj7&2rjI|mCT9bT@W9et*WVE> zpu|h}y^iaT32w?_!xB1J?lkIwJH#<({)TfTTCwVTvB%0GT1tKr~Mh0;hBPS%~W6uePZrC8x^n81%0C4 z;8NI(3Gz+sdI@s-gg0s1*3&i>Ea(03iC425npo|2he8dTVNS0{uLrxdRHgX>BGw%x ziC0RhnSPP`)?|J|XYoyu2+NBY18!i(xt6yEs8ySr*yJkod`oxYXttapDC_le@StHtS%4sWZG*$@rXOx!y70iFTPLe zN>&r-7bHRY>=*UFD?U#mV8^qMb~WTo)Do-Xgg1oxn1AkD3y=YZxHK_W7e-lMSEs;G z%Nj{H^&HIcNY|tU1@;&-jmr}A8SHOmp)`B1)p9dZ=8Q`tovwC}K0As|iNhAjcpGC6 z$Dk-`sIuPdRfS%vJo>~H6%r;6ed@zV9N`>KR4fqRW2ENCbJI;LZ??#d)e-h?T77qI zlCMvk0PQBJ+Wbi!XXnpy^MX@--TsQwgPc}64ut=bf0AzBkNTq*4&FFw<&ci3HUhlE zd5_eRsSL>q-fFq{nYEeOVH_;ltuV|P8l=_?M^U-RT?9&Xheg~$j2ycSHJYf|eqYAz zBQf$GAVGGNgjDc>(1%Qtp{)u^@%0unI1*944qGJX^hTKoEUv-R9J{02j7(wga!e1M zh;4KR+H`qSDyeOWZ1q3*Fc@VpH943<^5No%BlZQ|?Q*VrTX>5`y5M%3T8S3aA?&)) z&z{pg;ugTEa<)7QZ z>}_+Iqy}H*;uWjh4m&EO601ltXGxQhg=9fln5{bA3Cq*KFG;8LyebHM6A7)vcr7*6 z+fsP@r(ASp8Rn4%m{=H4jd!}#*EheI_1gXrwBYUL4VwNzXJ)ZTn6i4{k6@BK{6D~E zoc{whQ*g91b}=$>B%rW2HdQgvpk@3`PN8FBpoF3qb~G_?w);KuTm9cf3p-m817{Ng z3K1?Q1}4Vejgyg`g@J*QmVuR=fr0$DovfYl|E-CNqk+A>i7^4an1QvE2^778il_#i zn2WWwp@FUKfBK?gZsA1myZu+6Xb99y9G!k|O~6dY$im3V$;8G=%S6Za-+lf6dPpE+ z;c7y_#K6c&FJfY7VPH#1U}bOMZ0=-YK;ZiSpUy`2djU!)KED49ik+b)6yyIC09Em@ zHzA;xH?&lCwt=FTBlr*3Pt3y6$@%xHO#clc5->6{{6BO3s#7=Q4kQplZoW`l+ACEz zPZEQ~pkN4T24zwPaRmMt_d&%I2-eR{c71)@WJcSJ`fJi%HdR)h-^^_3SV-@aP`D#y z6g82+NES?M-k+n8N2pUH!w7sB?L(vo(Nx0u3#S=HSXP*-uTDk4n~=$Yh963t zSX~{I{n;@QCR@@-W57Kj8c!RMg@O=^YveY2emMQmJLO>0Oj&*hp&N+h=AjNxRnh~c&b(^nadgrd42Hojg# zq+%@`B&#+taZr`#;}d7mCNW)oQa)U}t6Pk5-X7Y2pw5-*>3Fnd z|6TT!(79{Rz7(AFFJw`{BX(S?I3TN)vP1`Rvl*(K)QF|43$8AyuyB`yhgZFhn>v2g z@Tv{rBa8AYNQxA*Ryi7D4S?YSk;h9Famp(=KU?JaT=xL83+y`o(%7Pz3iipoI-J-U zBa-?HMGeqYRV0>b-Ea=f;Np8-?cefRax~&U5$R<9_dTRP-{i3q5ow;V>o%;qg6T3B zuK^i0!$w|LilU2Z?bCaxYT{Ro&ow+M2m*@vlPA0kncbv)qDIogCO>==^y&|thV2zC z{Uc|zo^a10;AVrpu5j=#pyDG_&MApCJS`JjtO^NW4c>?y-mt6MgP%;-wAj1t%-z^# z4{NM=-BKD!;Xc5K+%J)5Q=g7)XB5d89zd^ z>lXMc1*483k{jB?bB(yLV)*c6rN|ygkSf$gi=5qw3;NiRXthW>;K%G=E!?_b6AEP$ z3*QD0Z-0UZ@CB?_A(%`sGwV4!O`uzh-PSC7x(umP8Uwz}8Q1xu66N*e_-{o1m6BT# z;31%{%n;n86TVM{O^7ZN-T6p}?L51Zm&OnA$`au(XUE;kl1+T21flY$$YKqD%tpY&T`0{X}kou19KU%&u>kmzj#EJs28VsZ*61yQCP6i@ZrFM6Xt*&#Ls%X zp(Ubv?pjkojk^4FQ{WdOO16}GsO2o+eQ`FQIviHQ1r)wf(HAhqfJ1&TRO9oQK23a9 zv`rtxx3;>T$QKdYbj%B}G*6Uj{b~E&&+gbkbklLL(Ox%zrF*w(y>Jlc;z@vmwdhtu zE9rIY^leE_eywh>=(?HJYuCQuT8~A`Fz>l};zIsLoxfsQRP=3{{&fZH|BRSgD#ySz zcoEtok5Kvaoj3sB^!fahTJ8U&5@(H$LARO7raT{aOi>|>mT&e0j9fo;``^Pj%l|Yg z{jb=ip=4qTMK5VY~gA0y9Y(DPN2<5z(nw$Iwduc6a<8M>bX_239CiQc-y^sQ(2Q@q1JN literal 0 HcmV?d00001 diff --git a/doc/_static/templates/subroutines/qpe.svg b/doc/_static/templates/subroutines/qpe.svg new file mode 100644 index 00000000000..a2e9d4c623f --- /dev/null +++ b/doc/_static/templates/subroutines/qpe.svg @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/templates/subroutines/qpe.tex b/doc/_static/templates/subroutines/qpe.tex new file mode 100644 index 00000000000..c8a06867665 --- /dev/null +++ b/doc/_static/templates/subroutines/qpe.tex @@ -0,0 +1,25 @@ +\documentclass{standalone} +\usepackage{qcircuit} + +\begin{document} +\Qcircuit @C=1em @R=0.5em { +& & & & & & & & &\\ +& & & & \hspace{1.3cm}\mbox{target wires} & &\\ +\\ +& \qw & \multigate{3}{U} & \multigate{3}{U^{2}} & \qw & \cdots & & \multigate{3}{U^{2^{n - 1}}} & \qw & \qw \\ +& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ +& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ +& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ +& & & & & & & & &\\ +& & & & & & & & &\\ +& & & & & & & & &\\ +& \gate{H} & \ctrl{-4} & \qw & \qw & \cdots & & \qw & \multigate{4}{QFT^{-1}} & \qw \\ +& \gate{H} & \qw & \ctrl{-5} & \qw & \cdots & & \qw & \ghost{QFT^{-1}} & \qw\\ +& \vdots & & & & \ddots & & & \\ +& & & & & & & &\\ +& \gate{H} \gategroup{10}{1}{17}{10}{.8em}{--}\gategroup{1}{1}{8}{10}{.8em}{--} & \qw & \qw & \qw & \cdots & & \ctrl{-8} & \ghost{QFT^{-1}} & \qw + \\ + & & & \hspace{2.6cm}\mbox{estimation wires} & & & & & & \\ + & & & & & & & & & \\ +} +\end{document} \ No newline at end of file diff --git a/doc/introduction/templates.rst b/doc/introduction/templates.rst index 5c1e1154523..c42927ab6b1 100644 --- a/doc/introduction/templates.rst +++ b/doc/introduction/templates.rst @@ -193,6 +193,11 @@ of other templates. :description: Permute :figure: ../_static/templates/subroutines/permute.png +.. customgalleryitem:: + :link: ../code/api/pennylane.templates.subroutines.QuantumPhaseEstimation.html + :description: QuantumPhaseEstimation + :figure: ../_static/templates/subroutines/qpe.svg + .. raw:: html
diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 30d655fae29..86df131afdf 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -23,6 +23,33 @@ @template def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): + r"""Performs the + `quantum phase estimation `__ + circuit. + + Given a unitary :math:`U`, this template applies the circuit for quantum phase + estimation. The unitary is applied to the qubits specified by ``target_wires`` and :math:`n` + qubits are used for phase estimation as specified by ``estimation_wires``. + + .. figure:: ../../_static/templates/subroutines/qpe.svg + :align: center + :width: 60% + :target: javascript:void(0); + + Args: + unitary (array): the phase estimation unitary + target_wires (Union[Wires, Sequence[int], or int]): the target wires to apply the unitary + estimation_wires (Union[Wires, Sequence[int], or int]): the wires to be used for phase + estimation + + Raises: + QuantumFunctionError: if the ``target_wires`` and ``estimation_wires`` share a common + element + + .. UsageDetails:: + + TODO + """ target_wires = Wires(target_wires) estimation_wires = Wires(estimation_wires) From 15b9ecda77093283cec27d9097fc649fbad11e40 Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 22 Feb 2021 16:39:08 -0500 Subject: [PATCH 04/30] Add note --- pennylane/templates/subroutines/qpe.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 86df131afdf..a11f708c3ea 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -59,7 +59,10 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): for i, wire in enumerate(estimation_wires): qml.Hadamard(wire) + + # Could we calculate the matrix power more efficiently by diagonalizing? u = matrix_power(unitary, 2 ** i) + qml.ControlledQubitUnitary(u, control_wires=wire, target_wires=target_wires) qml.QFT(estimation_wires).inv() From ed57ccd5d59927b1bb42cbfdb2ac0969a28ec28f Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 22 Feb 2021 17:04:40 -0500 Subject: [PATCH 05/30] Add to changelog --- .github/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index dcd435d193e..4d56719b580 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,6 +2,14 @@

New features since last release

+- Added the `QuantumPhaseEstimation` template for performing quantum phase estimation for an input + unitary matrix. + [(#1095)](https://github.com/PennyLaneAI/pennylane/pull/1095) + + ```python + TODO + ``` + - The number of shots can now be specified on a temporary basis when evaluating a QNode. [(#1075)](https://github.com/PennyLaneAI/pennylane/pull/1075) From c857820936728fbd069c160af10037ef6dfb5d99 Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 22 Feb 2021 17:04:46 -0500 Subject: [PATCH 06/30] add test --- pennylane/templates/subroutines/qpe.py | 4 ++-- tests/templates/test_integration.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index a11f708c3ea..623af795041 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -63,6 +63,6 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): # Could we calculate the matrix power more efficiently by diagonalizing? u = matrix_power(unitary, 2 ** i) - qml.ControlledQubitUnitary(u, control_wires=wire, target_wires=target_wires) + # qml.ControlledQubitUnitary(u, control_wires=wire, target_wires=target_wires) - qml.QFT(estimation_wires).inv() + # qml.QFT(wires=estimation_wires).inv() diff --git a/tests/templates/test_integration.py b/tests/templates/test_integration.py index d450279d247..861366103ba 100644 --- a/tests/templates/test_integration.py +++ b/tests/templates/test_integration.py @@ -155,6 +155,14 @@ {'weights': [[[ 0.17586701, -0.20382066]]]}, {'wires': [0, 1], 'init_state': np.array([1, 0], requires_grad=False)}, 2), + (qml.templates.QuantumPhaseEstimation, + {}, + { + "unitary": np.array([[0, 1], [1, 0]]), + "target_wires": [0], + "estimation_wires": [1, 2], + }, + 3), ] CV_DIFFABLE_NONDIFFABLE = [(qml.templates.DisplacementEmbedding, @@ -706,6 +714,9 @@ def circuit_consec(): if template.__name__ == 'UCCSD': kwargs2['s_wires'] = [nonconsecutive_wires[:3], nonconsecutive_wires[1:]] kwargs2['d_wires'] = [[nonconsecutive_wires[:2], nonconsecutive_wires[2:]]] + if template.__name__ == "QuantumPhaseEstimation": + kwargs2["target_wires"] = [nonconsecutive_wires[0]] + kwargs2["estimation_wires"] = nonconsecutive_wires[1:3] dev_nonconsec = qml.device('default.qubit', wires=nonconsecutive_wires) From 5a16220df841cd927bcd529f2a341a2bc04ec166 Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 22 Feb 2021 17:06:54 -0500 Subject: [PATCH 07/30] fix test --- pennylane/templates/subroutines/qpe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 623af795041..06b8401edac 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -63,6 +63,6 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): # Could we calculate the matrix power more efficiently by diagonalizing? u = matrix_power(unitary, 2 ** i) - # qml.ControlledQubitUnitary(u, control_wires=wire, target_wires=target_wires) + qml.ControlledQubitUnitary(u, control_wires=wire, wires=target_wires) - # qml.QFT(wires=estimation_wires).inv() + qml.QFT(wires=estimation_wires).inv() From 9938f7a38569b2e93b480ae3eb3073ba1395d3fd Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 22 Feb 2021 17:24:01 -0500 Subject: [PATCH 08/30] Add test --- tests/templates/test_subroutines.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 79593ae545f..11adf1e273b 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -30,6 +30,7 @@ UCCSD, ApproxTimeEvolution, Permute, + QuantumPhaseEstimation, ) from pennylane.templates.subroutines.arbitrary_unitary import ( @@ -1477,3 +1478,36 @@ def test_subset_permutations_tape( # Make sure to start comparison after the set of RZs have been applied assert all(op.name == "SWAP" for op in tape.operations[len(wire_labels) :]) assert [op.wires.labels for op in tape.operations[len(wire_labels) :]] == expected_wires + + +class TestQuantumPhaseEstimation: + """Tests for the QuantumPhaseEstimation template from the pennylane.templates.subroutine + module.""" + + def test_same_wires(self): + """Tests if a QuantumFunctionError is raised if target_wires and estimation_wires contain a + common element""" + + with pytest.raises(qml.QuantumFunctionError, match="The target wires and estimation wires"): + QuantumPhaseEstimation(np.eye(2), target_wires=[0, 1], estimation_wires=[1, 2]) + + def test_expected_tape(self): + """Tests if QuantumPhaseEstimation populates the tape as expected for a fixed example""" + + m = qml.RX(0.3, wires=0).matrix + + with qml.tape.QuantumTape() as tape: + QuantumPhaseEstimation(m, target_wires=[0], estimation_wires=[1, 2]) + + with qml.tape.QuantumTape() as tape2: + qml.Hadamard(1), + qml.ControlledQubitUnitary(m, control_wires=[1], wires=[0]), + qml.Hadamard(2), + qml.ControlledQubitUnitary(m @ m, control_wires=[2], wires=[0]), + qml.QFT(wires=[1, 2]).inv() + + assert len(tape2.queue) == len(tape.queue) + assert all([op1.name == op2.name for op1, op2 in zip(tape.queue, tape2.queue)]) + assert all([op1.wires == op2.wires for op1, op2 in zip(tape.queue, tape2.queue)]) + assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix) + assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix) From 4026fc3a62981ed25f0d0219ef0a79ff6855f6a1 Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 08:25:10 -0500 Subject: [PATCH 09/30] Fix circuit --- pennylane/templates/subroutines/qpe.py | 4 +++- tests/templates/test_subroutines.py | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 06b8401edac..32b47e24be5 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -57,11 +57,13 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): if len(Wires.shared_wires([target_wires, estimation_wires])) != 0: raise qml.QuantumFunctionError("The target wires and estimation wires must be different") + num_estimation_wires = len(estimation_wires) + for i, wire in enumerate(estimation_wires): qml.Hadamard(wire) # Could we calculate the matrix power more efficiently by diagonalizing? - u = matrix_power(unitary, 2 ** i) + u = matrix_power(unitary, 2 ** (num_estimation_wires - i - 1)) qml.ControlledQubitUnitary(u, control_wires=wire, wires=target_wires) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 11adf1e273b..2da240aabe0 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -1501,9 +1501,9 @@ def test_expected_tape(self): with qml.tape.QuantumTape() as tape2: qml.Hadamard(1), - qml.ControlledQubitUnitary(m, control_wires=[1], wires=[0]), + qml.ControlledQubitUnitary(m @ m, control_wires=[1], wires=[0]), qml.Hadamard(2), - qml.ControlledQubitUnitary(m @ m, control_wires=[2], wires=[0]), + qml.ControlledQubitUnitary(m, control_wires=[2], wires=[0]), qml.QFT(wires=[1, 2]).inv() assert len(tape2.queue) == len(tape.queue) @@ -1511,3 +1511,19 @@ def test_expected_tape(self): assert all([op1.wires == op2.wires for op1, op2 in zip(tape.queue, tape2.queue)]) assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix) assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix) + + # def test_expected(self): + # """TODO""" + # wires = 10 + # dev = qml.device("default.qubit", wires=wires) + # m = qml.RX(0.3, wires=0).matrix + # target_wires = [0] + # estimation_wires = range(1, wires) + # + # with qml.tape.QuantumTape() as tape: + # QuantumPhaseEstimation(m, target_wires=target_wires, estimation_wires=estimation_wires) + # qml.probs(estimation_wires) + # + # res = tape.execute(dev) + # + # print(np.argmax(res)) From b8378fcb93aac01cad4662563720bc4f77d3e7c0 Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 09:08:51 -0500 Subject: [PATCH 10/30] Add test --- tests/templates/test_subroutines.py | 49 ++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 2da240aabe0..7aa2441f8bf 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -1512,18 +1512,37 @@ def test_expected_tape(self): assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix) assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix) - # def test_expected(self): - # """TODO""" - # wires = 10 - # dev = qml.device("default.qubit", wires=wires) - # m = qml.RX(0.3, wires=0).matrix - # target_wires = [0] - # estimation_wires = range(1, wires) - # - # with qml.tape.QuantumTape() as tape: - # QuantumPhaseEstimation(m, target_wires=target_wires, estimation_wires=estimation_wires) - # qml.probs(estimation_wires) - # - # res = tape.execute(dev) - # - # print(np.argmax(res)) + def test_expected(self): + """TODO""" + phase = 6 + estimates = [] + wire_range = range(2, 10) + + for wires in wire_range: + dev = qml.device("default.qubit", wires=wires) + m = qml.RX(phase, wires=0).matrix + target_wires = [0] + estimation_wires = range(1, wires) + + with qml.tape.QuantumTape() as tape: + qml.Hadamard(wires=target_wires) + qml.templates.QuantumPhaseEstimation(m, target_wires=target_wires, estimation_wires=estimation_wires) + qml.probs(estimation_wires) + + res = tape.execute(dev).flatten() + initial_estimate = np.argmax(res) / 2 ** (wires - 1) + + # We need to rescale because RX is exp(- i theta X / 2) and we expect a unitary of the + # form exp(2 pi i theta X) + rescaled_estimate = (1 - initial_estimate) * np.pi * 4 + estimates.append(rescaled_estimate) + + # Check that the error is monotonically decreasing + for i in range(len(estimates) - 1): + err1 = np.abs(estimates[i] - phase) + err2 = np.abs(estimates[i + 1] - phase) + assert err1 >= err2 + + # This is quite a large error, but we'd need to push the qubit number up more to get it + # lower + assert np.allclose(estimates[-1], phase, rtol=1e-2) \ No newline at end of file From 59755cb3f2a635d2704d52dfb667a922241d48b7 Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 09:09:55 -0500 Subject: [PATCH 11/30] Run black on test --- tests/templates/test_subroutines.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 7aa2441f8bf..1ef6580650f 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -1526,7 +1526,9 @@ def test_expected(self): with qml.tape.QuantumTape() as tape: qml.Hadamard(wires=target_wires) - qml.templates.QuantumPhaseEstimation(m, target_wires=target_wires, estimation_wires=estimation_wires) + qml.templates.QuantumPhaseEstimation( + m, target_wires=target_wires, estimation_wires=estimation_wires + ) qml.probs(estimation_wires) res = tape.execute(dev).flatten() From dc5cebfe6d22e4c3f5e602215357d98e62ab72be Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 09:12:05 -0500 Subject: [PATCH 12/30] Add to docstring --- tests/templates/test_subroutines.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 1ef6580650f..355d10f6724 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -1512,8 +1512,8 @@ def test_expected_tape(self): assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix) assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix) - def test_expected(self): - """TODO""" + def test_phase_estimated(self): + """Tests that the QPE circuit can correctly estimate the phase of a simple RX rotation.""" phase = 6 estimates = [] wire_range = range(2, 10) @@ -1525,7 +1525,9 @@ def test_expected(self): estimation_wires = range(1, wires) with qml.tape.QuantumTape() as tape: + # We want to prepare ourselves in an eigenstate of RX, in this case |+> qml.Hadamard(wires=target_wires) + qml.templates.QuantumPhaseEstimation( m, target_wires=target_wires, estimation_wires=estimation_wires ) @@ -1547,4 +1549,4 @@ def test_expected(self): # This is quite a large error, but we'd need to push the qubit number up more to get it # lower - assert np.allclose(estimates[-1], phase, rtol=1e-2) \ No newline at end of file + assert np.allclose(estimates[-1], phase, rtol=1e-2) From b8d4f9bb4fc1c377d7a324d448e2c3ed26623bd5 Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 09:37:24 -0500 Subject: [PATCH 13/30] Add to docstring: --- pennylane/templates/subroutines/qpe.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 32b47e24be5..7852fb1a493 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -36,6 +36,23 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): :width: 60% :target: javascript:void(0); + This circuit can be used to perform the standard quantum phase estimation algorithm, consisting + of the following steps: + + #. Prepare ``target_wires`` in an eigenstate of ``unitary``. If that eigenstate has a + corresponding eigenvalue :math:`e^{2 \pi i \theta}` with phase :math:`\theta \in [0, 1)`, + this algorithm will measure :math:`\theta`. + #. Apply the ``QuantumPhaseEstimation`` circuit. + #. Measure ``estimation_wires`` using :func:`~.probs`, giving a probability distribution over + measurement outcomes in the computational basis. + #. Find the index of the largest value in the probability distribution and divide that number by + :math:`2^{n}`. This number will be an estimate of :math:`\theta` with an error that decreases + exponentially with the number of qubits :math:`n`. + + Note that if :math:`\theta \in (-1, 0]`, we can estimate the phase by again finding the index + :math:`i` found in step 4 and calculating :math:`\theta \approx \frac{1 - i}{2^{n}}`. The + usage details below give an example of this case. + Args: unitary (array): the phase estimation unitary target_wires (Union[Wires, Sequence[int], or int]): the target wires to apply the unitary From 0a42c6b01d89587c874b767fdb5878793ec67041 Mon Sep 17 00:00:00 2001 From: trbromley Date: Tue, 23 Feb 2021 09:42:10 -0500 Subject: [PATCH 14/30] Update image --- doc/_static/templates/subroutines/qpe.pdf | Bin 65569 -> 65724 bytes doc/_static/templates/subroutines/qpe.svg | 288 +++++++++++----------- doc/_static/templates/subroutines/qpe.tex | 12 +- 3 files changed, 156 insertions(+), 144 deletions(-) diff --git a/doc/_static/templates/subroutines/qpe.pdf b/doc/_static/templates/subroutines/qpe.pdf index c39e16bae7c50312f14d5193b4bbc17adb37f273..f61d277b34ea8907aadd25d815717da314d3895d 100644 GIT binary patch delta 9847 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 diff --git a/doc/_static/templates/subroutines/qpe.svg b/doc/_static/templates/subroutines/qpe.svg index a2e9d4c623f..19eae5e1755 100644 --- a/doc/_static/templates/subroutines/qpe.svg +++ b/doc/_static/templates/subroutines/qpe.svg @@ -1,5 +1,5 @@ - + @@ -72,28 +72,31 @@ - - - - + - + - + + + + - + + + + @@ -103,128 +106,137 @@ - + - + - - - - - - + + + + + + - - - - - + + + + + - + - - - - - - + - + + + + + + + + + + + + + + + - - - - - - - + - + - + - + + + + + + + - + - + - + - + - - - - - - - + + + + + + + - - + + - + - + - + - - - + + + - - + + - + - + - + - - - + + + - - + + - + - + - + - - - + + + @@ -234,41 +246,41 @@ - + - - - - + + + + - + - + - + - + - - + + - + - + - + - - - - - - + + + + + + @@ -277,25 +289,25 @@ - + - + - - - + + + - + - + - + - - - + + + @@ -306,13 +318,13 @@ - + - + - + @@ -323,50 +335,50 @@ - - + + - - + + - - - + + + - + - + - + - + - - - - + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + diff --git a/doc/_static/templates/subroutines/qpe.tex b/doc/_static/templates/subroutines/qpe.tex index c8a06867665..f0f3f809b3b 100644 --- a/doc/_static/templates/subroutines/qpe.tex +++ b/doc/_static/templates/subroutines/qpe.tex @@ -4,12 +4,12 @@ \begin{document} \Qcircuit @C=1em @R=0.5em { & & & & & & & & &\\ -& & & & \hspace{1.3cm}\mbox{target wires} & &\\ +& & & & \hspace{-0.5cm}\mbox{target wires} & &\\ \\ -& \qw & \multigate{3}{U} & \multigate{3}{U^{2}} & \qw & \cdots & & \multigate{3}{U^{2^{n - 1}}} & \qw & \qw \\ -& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ -& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ -& \qw & \ghost{U} & \ghost{U^{2}} & \qw & \cdots & & \ghost{U^{2^{n - 1}}} & \qw & \qw \\ +& \qw & \multigate{3}{U^{2^{n - 1}}} & \multigate{3}{U^{2^{n - 2}}} & \qw & \cdots & & \multigate{3}{U} & \qw & \qw \\ +& \qw & \ghost{U^{2^{n - 1}}} & \ghost{U^{2^{n - 2}}} & \qw & \cdots & & \ghost{U} & \qw & \qw \\ +& \qw & \ghost{U^{2^{n - 1}}} & \ghost{U^{2^{n - 2}}} & \qw & \cdots & & \ghost{U} & \qw & \qw \\ +& \qw & \ghost{U^{2^{n - 1}}} & \ghost{U^{2^{n - 2}}} & \qw & \cdots & & \ghost{U} & \qw & \qw \\ & & & & & & & & &\\ & & & & & & & & &\\ & & & & & & & & &\\ @@ -19,7 +19,7 @@ & & & & & & & &\\ & \gate{H} \gategroup{10}{1}{17}{10}{.8em}{--}\gategroup{1}{1}{8}{10}{.8em}{--} & \qw & \qw & \qw & \cdots & & \ctrl{-8} & \ghost{QFT^{-1}} & \qw \\ - & & & \hspace{2.6cm}\mbox{estimation wires} & & & & & & \\ + & & & \hspace{1.6cm}\mbox{estimation wires} & & & & & & \\ & & & & & & & & & \\ } \end{document} \ No newline at end of file From 242edcae762522f71a40972907e219394f14cc6e Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 24 Feb 2021 16:05:14 -0600 Subject: [PATCH 15/30] Test commit: adding qpe example --- pennylane/templates/subroutines/qpe.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 7852fb1a493..6afd39b954a 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -65,6 +65,22 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): .. UsageDetails:: + An example of how to use this template is shown below: + + .. code-block:: python + + import pennylane as qml + from pennylane.templates import QuantumPhaseEstimation + + dev = qml.device('default.qubit', wires=3) + + @qml.qnode(dev) + def circuit(weight, wires=None): + SingleExcitationUnitary(weight, wires=wires) + return qml.expval(qml.PauliZ(0)) + + weight = 0.56 + print(circuit(weight, wires=[0, 1, 2])) TODO """ From 4b39d7964f5724471430c29f1dc7b73e4dcc0bb8 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 25 Feb 2021 08:23:36 -0600 Subject: [PATCH 16/30] Added first attempt at qpe example --- pennylane/templates/subroutines/qpe.py | 27 +++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 6afd39b954a..4cac5804a87 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -68,19 +68,32 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): An example of how to use this template is shown below: .. code-block:: python - + import pennylane as qml from pennylane.templates import QuantumPhaseEstimation + from pennylane import numpy as np + + # We initialize a qubit to the |+> state and determine the phase after applying qml.RX + + phase = 5 + target_wires = [0] + u = qml.RX(phase,wires=0).matrix - dev = qml.device('default.qubit', wires=3) + n_estimation_wires = 5 + estimation_wires = range(1,n_estimation_wires+1) + dev = qml.device("default.qubit",wires=n_estimation_wires+1) + @qml.qnode(dev) - def circuit(weight, wires=None): - SingleExcitationUnitary(weight, wires=wires) - return qml.expval(qml.PauliZ(0)) + def circuit(): + qml.Hadamard(wires=target_wires) + + QuantumPhaseEstimation(u,target_wires=target_wires,estimation_wires=estimation_wires) - weight = 0.56 - print(circuit(weight, wires=[0, 1, 2])) + return qml.expval(qml.Hermitian(np.diag(range(2**n_estimation_wires)),wires=range(1,n_estimation_wires+1))) + + resultphase = 4*np.pi*(1-circuit()/2**n_estimation_wires) + print(resultphase) TODO """ From e5f9285fc33fbe15e8732663fa7987b1c5aaffc0 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 14:37:50 -0500 Subject: [PATCH 17/30] Update example --- pennylane/templates/subroutines/qpe.py | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 4cac5804a87..6a7ce258b44 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -27,7 +27,7 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): `quantum phase estimation `__ circuit. - Given a unitary :math:`U`, this template applies the circuit for quantum phase + Given a unitary matrix :math:`U`, this template applies the circuit for quantum phase estimation. The unitary is applied to the qubits specified by ``target_wires`` and :math:`n` qubits are used for phase estimation as specified by ``estimation_wires``. @@ -39,7 +39,7 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): This circuit can be used to perform the standard quantum phase estimation algorithm, consisting of the following steps: - #. Prepare ``target_wires`` in an eigenstate of ``unitary``. If that eigenstate has a + #. Prepare ``target_wires`` in an eigenstate of :math:`U`. If that eigenstate has a corresponding eigenvalue :math:`e^{2 \pi i \theta}` with phase :math:`\theta \in [0, 1)`, this algorithm will measure :math:`\theta`. #. Apply the ``QuantumPhaseEstimation`` circuit. @@ -54,7 +54,7 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): usage details below give an example of this case. Args: - unitary (array): the phase estimation unitary + unitary (array): the phase estimation unitary, specified as a matrix target_wires (Union[Wires, Sequence[int], or int]): the target wires to apply the unitary estimation_wires (Union[Wires, Sequence[int], or int]): the wires to be used for phase estimation @@ -65,36 +65,46 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): .. UsageDetails:: - An example of how to use this template is shown below: + Consider the matrix corresponding to a rotation from an :class:`~.RX` gate: .. code-block:: python - + import pennylane as qml from pennylane.templates import QuantumPhaseEstimation from pennylane import numpy as np - # We initialize a qubit to the |+> state and determine the phase after applying qml.RX - phase = 5 target_wires = [0] - u = qml.RX(phase,wires=0).matrix + u = qml.RX(phase, wires=0).matrix + + The ``phase`` parameter can be estimated using ``QuantumPhaseEstimation``. An example is + shown below using a register of five phase-estimation qubits: + + .. code-block:: python n_estimation_wires = 5 - estimation_wires = range(1,n_estimation_wires+1) + estimation_wires = range(1, n_estimation_wires + 1) + + dev = qml.device("default.qubit", wires=n_estimation_wires + 1) - dev = qml.device("default.qubit",wires=n_estimation_wires+1) - @qml.qnode(dev) def circuit(): + # Start in the |+> eigenstate of the unitary qml.Hadamard(wires=target_wires) - QuantumPhaseEstimation(u,target_wires=target_wires,estimation_wires=estimation_wires) + QuantumPhaseEstimation( + u, + target_wires=target_wires, + estimation_wires=estimation_wires, + ) + + return qml.probs(estimation_wires) + + + phase = np.argmax(circuit()) / 2 ** n_estimation_wires - return qml.expval(qml.Hermitian(np.diag(range(2**n_estimation_wires)),wires=range(1,n_estimation_wires+1))) - - resultphase = 4*np.pi*(1-circuit()/2**n_estimation_wires) - print(resultphase) - TODO + # Need to rescale phase due to convention of RX gate + phase = 4 * np.pi * (1 - phase) """ target_wires = Wires(target_wires) From f9cc5f2c49cf39a580825e6bfcc3181bf1561f84 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 14:41:18 -0500 Subject: [PATCH 18/30] Add to changelog --- .github/CHANGELOG.md | 38 +++++++++++++++++++++++++- pennylane/templates/subroutines/qpe.py | 4 +-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index cacd0d5e3eb..7da75d160a0 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -6,10 +6,46 @@ unitary matrix. [(#1095)](https://github.com/PennyLaneAI/pennylane/pull/1095) + Consider the matrix corresponding to a rotation from an :class:`~.RX` gate: + + >>> phase = 5 + >>> target_wires = [0] + >>> u = qml.RX(phase, wires=0).matrix + + The ``phase`` parameter can be estimated using ``QuantumPhaseEstimation``. For example, using five + phase-estimation qubits: + ```python - TODO + n_estimation_wires = 5 + estimation_wires = range(1, n_estimation_wires + 1) + + dev = qml.device("default.qubit", wires=n_estimation_wires + 1) + + @qml.qnode(dev) + def circuit(): + # Start in the |+> eigenstate of the unitary + qml.Hadamard(wires=target_wires) + + QuantumPhaseEstimation( + u, + target_wires=target_wires, + estimation_wires=estimation_wires, + ) + + return qml.probs(estimation_wires) + + + phase_estimated = np.argmax(circuit()) / 2 ** n_estimation_wires + + # Need to rescale phase due to convention of RX gate + phase_estimated = 4 * np.pi * (1 - phase) ``` + The resulting phase is a close approximation to the true value: + + >>> phase_estimated + >>> 5.105088062083414 + - The number of shots can now be specified on a temporary basis when evaluating a QNode. [(#1075)](https://github.com/PennyLaneAI/pennylane/pull/1075) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 6a7ce258b44..0a55fb3f132 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -101,10 +101,10 @@ def circuit(): return qml.probs(estimation_wires) - phase = np.argmax(circuit()) / 2 ** n_estimation_wires + phase_estimated = np.argmax(circuit()) / 2 ** n_estimation_wires # Need to rescale phase due to convention of RX gate - phase = 4 * np.pi * (1 - phase) + phase_estimated = 4 * np.pi * (1 - phase) """ target_wires = Wires(target_wires) From 4e1a708fe3e9c6c8f3f2af41a2eb249c9ce208a7 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 14:42:19 -0500 Subject: [PATCH 19/30] update --- .github/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 7da75d160a0..02eb2ac3238 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -8,9 +8,11 @@ Consider the matrix corresponding to a rotation from an :class:`~.RX` gate: + ```pycon >>> phase = 5 >>> target_wires = [0] >>> u = qml.RX(phase, wires=0).matrix + ``` The ``phase`` parameter can be estimated using ``QuantumPhaseEstimation``. For example, using five phase-estimation qubits: @@ -43,8 +45,10 @@ The resulting phase is a close approximation to the true value: + ```pycon >>> phase_estimated >>> 5.105088062083414 + ``` - The number of shots can now be specified on a temporary basis when evaluating a QNode. [(#1075)](https://github.com/PennyLaneAI/pennylane/pull/1075) From 76fc3d18fbf7af3c36e83facc5dae9b786c84b15 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 14:44:10 -0500 Subject: [PATCH 20/30] Update --- .github/CHANGELOG.md | 5 ++--- pennylane/templates/subroutines/qpe.py | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 02eb2ac3238..e6139b15f1e 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -6,7 +6,7 @@ unitary matrix. [(#1095)](https://github.com/PennyLaneAI/pennylane/pull/1095) - Consider the matrix corresponding to a rotation from an :class:`~.RX` gate: + Consider the matrix corresponding to a rotation from an `RX` gate: ```pycon >>> phase = 5 @@ -36,7 +36,6 @@ return qml.probs(estimation_wires) - phase_estimated = np.argmax(circuit()) / 2 ** n_estimation_wires # Need to rescale phase due to convention of RX gate @@ -47,7 +46,7 @@ ```pycon >>> phase_estimated - >>> 5.105088062083414 + 5.105088062083414 ``` - The number of shots can now be specified on a temporary basis when evaluating a QNode. diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 0a55fb3f132..d1c104ac65b 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -100,7 +100,6 @@ def circuit(): return qml.probs(estimation_wires) - phase_estimated = np.argmax(circuit()) / 2 ** n_estimation_wires # Need to rescale phase due to convention of RX gate From d1b7521469c2d11c05fa01482be58ca70d1e83d3 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 14:51:05 -0500 Subject: [PATCH 21/30] Update --- .github/CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index e6139b15f1e..c40ed25fa3f 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -155,9 +155,7 @@ This release contains contributions from (in alphabetical order): -Thomas Bromley, Kyle Godbey, Josh Izaac, Daniel Polatajko, Chase Roberts, Maria Schuld. - - +Thomas Bromley, Diego Guala, Kyle Godbey, Josh Izaac, Daniel Polatajko, Chase Roberts, Maria Schuld. # Release 0.14.1 (current release) From 1f700a1da2de258d2d7e3f9051b2abd4b0fb6c2a Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 15:24:50 -0500 Subject: [PATCH 22/30] Add more efficient version --- pennylane/templates/subroutines/qpe.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index d1c104ac65b..0d1e0bbf3a2 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -14,7 +14,7 @@ """ Contains the ``QuantumPhaseEstimation`` template. """ -from numpy.linalg import matrix_power +from numpy.linalg import eig import pennylane as qml from pennylane.templates.decorator import template @@ -112,14 +112,14 @@ def circuit(): if len(Wires.shared_wires([target_wires, estimation_wires])) != 0: raise qml.QuantumFunctionError("The target wires and estimation wires must be different") - num_estimation_wires = len(estimation_wires) + unitary_powers = [unitary] - for i, wire in enumerate(estimation_wires): - qml.Hadamard(wire) - - # Could we calculate the matrix power more efficiently by diagonalizing? - u = matrix_power(unitary, 2 ** (num_estimation_wires - i - 1)) + for i in range(len(estimation_wires) - 1): + new_power = unitary_powers[0] @ unitary_powers[0] + unitary_powers.insert(0, new_power) - qml.ControlledQubitUnitary(u, control_wires=wire, wires=target_wires) + for wire, unitary in zip(estimation_wires, unitary_powers): + qml.Hadamard(wire) + qml.ControlledQubitUnitary(unitary, control_wires=wire, wires=target_wires) qml.QFT(wires=estimation_wires).inv() From 1c66ebd7c068bfc9d1b5963570614e0cf52b7e1a Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 15:29:55 -0500 Subject: [PATCH 23/30] Fix --- pennylane/templates/subroutines/qpe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 0d1e0bbf3a2..2f8e56f60f3 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -118,8 +118,8 @@ def circuit(): new_power = unitary_powers[0] @ unitary_powers[0] unitary_powers.insert(0, new_power) - for wire, unitary in zip(estimation_wires, unitary_powers): + for wire, u in zip(estimation_wires, unitary_powers): qml.Hadamard(wire) - qml.ControlledQubitUnitary(unitary, control_wires=wire, wires=target_wires) + qml.ControlledQubitUnitary(u, control_wires=wire, wires=target_wires) qml.QFT(wires=estimation_wires).inv() From 25f126c6bb3d3fd7002d75166dab42dd9c7c6d46 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 15:32:29 -0500 Subject: [PATCH 24/30] New --- pennylane/templates/subroutines/qpe.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 2f8e56f60f3..a4928510f88 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -115,11 +115,11 @@ def circuit(): unitary_powers = [unitary] for i in range(len(estimation_wires) - 1): - new_power = unitary_powers[0] @ unitary_powers[0] - unitary_powers.insert(0, new_power) + new_power = unitary_powers[-1] @ unitary_powers[-1] + unitary_powers.append(new_power) - for wire, u in zip(estimation_wires, unitary_powers): + for wire in estimation_wires: qml.Hadamard(wire) - qml.ControlledQubitUnitary(u, control_wires=wire, wires=target_wires) + qml.ControlledQubitUnitary(unitary_powers.pop(), control_wires=wire, wires=target_wires) qml.QFT(wires=estimation_wires).inv() From eee7cdae62c3a2981180a02ea9503228d0498de9 Mon Sep 17 00:00:00 2001 From: trbromley Date: Thu, 25 Feb 2021 15:33:56 -0500 Subject: [PATCH 25/30] Fix --- pennylane/templates/subroutines/qpe.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index a4928510f88..725b3c87b5c 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -14,8 +14,6 @@ """ Contains the ``QuantumPhaseEstimation`` template. """ -from numpy.linalg import eig - import pennylane as qml from pennylane.templates.decorator import template from pennylane.wires import Wires @@ -114,7 +112,7 @@ def circuit(): unitary_powers = [unitary] - for i in range(len(estimation_wires) - 1): + for _ in range(len(estimation_wires) - 1): new_power = unitary_powers[-1] @ unitary_powers[-1] unitary_powers.append(new_power) From 8b7d6d282d201e8418fff0c031f6e3627dfa844a Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 1 Mar 2021 11:37:27 -0500 Subject: [PATCH 26/30] Improve tests --- tests/templates/test_subroutines.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index 355d10f6724..be96e29afb6 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -1512,9 +1512,9 @@ def test_expected_tape(self): assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix) assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix) - def test_phase_estimated(self): + @pytest.mark.parametrize("phase", [2, 3, 6, np.pi]) + def test_phase_estimated(self, phase): """Tests that the QPE circuit can correctly estimate the phase of a simple RX rotation.""" - phase = 6 estimates = [] wire_range = range(2, 10) @@ -1525,7 +1525,7 @@ def test_phase_estimated(self): estimation_wires = range(1, wires) with qml.tape.QuantumTape() as tape: - # We want to prepare ourselves in an eigenstate of RX, in this case |+> + # We want to prepare an eigenstate of RX, in this case |+> qml.Hadamard(wires=target_wires) qml.templates.QuantumPhaseEstimation( From 29193dc26987f52e5057adc54870621016427a7d Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 1 Mar 2021 11:59:19 -0500 Subject: [PATCH 27/30] Add test --- tests/templates/test_subroutines.py | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/templates/test_subroutines.py b/tests/templates/test_subroutines.py index be96e29afb6..34284fa7774 100644 --- a/tests/templates/test_subroutines.py +++ b/tests/templates/test_subroutines.py @@ -17,6 +17,7 @@ """ # pylint: disable=protected-access,cell-var-from-loop import pytest +from scipy.stats import unitary_group import pennylane as qml import pennylane._queuing from pennylane import numpy as np @@ -1550,3 +1551,50 @@ def test_phase_estimated(self, phase): # This is quite a large error, but we'd need to push the qubit number up more to get it # lower assert np.allclose(estimates[-1], phase, rtol=1e-2) + + def test_phase_estimated_two_qubit(self): + """Tests that the QPE circuit can correctly estimate the phase of a random two-qubit + unitary.""" + + unitary = unitary_group.rvs(4, random_state=1967) + eigvals, eigvecs = np.linalg.eig(unitary) + + state = eigvecs[:, 0] + eigval = eigvals[0] + phase = np.real_if_close(np.log(eigval) / (2 * np.pi * 1j)) + + estimates = [] + wire_range = range(3, 11) + + for wires in wire_range: + dev = qml.device("default.qubit", wires=wires) + + target_wires = [0, 1] + estimation_wires = range(2, wires) + + with qml.tape.QuantumTape() as tape: + # We want to prepare an eigenstate of RX, in this case |+> + qml.QubitStateVector(state, wires=target_wires) + + qml.templates.QuantumPhaseEstimation( + unitary, target_wires=target_wires, estimation_wires=estimation_wires + ) + qml.probs(estimation_wires) + + res = tape.execute(dev).flatten() + + if phase < 0: + estimate = np.argmax(res) / 2 ** (wires - 2) - 1 + else: + estimate = np.argmax(res) / 2 ** (wires - 2) + estimates.append(estimate) + + # Check that the error is monotonically decreasing + for i in range(len(estimates) - 1): + err1 = np.abs(estimates[i] - phase) + err2 = np.abs(estimates[i + 1] - phase) + assert err1 >= err2 + + # This is quite a large error, but we'd need to push the qubit number up more to get it + # lower + assert np.allclose(estimates[-1], phase, rtol=1e-2) From 2d5abfbdd79d461968d42fc59201bdb6df95018e Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 1 Mar 2021 12:01:43 -0500 Subject: [PATCH 28/30] u -> unitary --- .github/CHANGELOG.md | 4 ++-- pennylane/templates/subroutines/qpe.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 70ba93b0135..f1bfee9e945 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -11,7 +11,7 @@ ```pycon >>> phase = 5 >>> target_wires = [0] - >>> u = qml.RX(phase, wires=0).matrix + >>> unitary = qml.RX(phase, wires=0).matrix ``` The ``phase`` parameter can be estimated using ``QuantumPhaseEstimation``. For example, using five @@ -29,7 +29,7 @@ qml.Hadamard(wires=target_wires) QuantumPhaseEstimation( - u, + unitary, target_wires=target_wires, estimation_wires=estimation_wires, ) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 725b3c87b5c..997a1741ed1 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -73,7 +73,7 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): phase = 5 target_wires = [0] - u = qml.RX(phase, wires=0).matrix + unitary = qml.RX(phase, wires=0).matrix The ``phase`` parameter can be estimated using ``QuantumPhaseEstimation``. An example is shown below using a register of five phase-estimation qubits: @@ -91,7 +91,7 @@ def circuit(): qml.Hadamard(wires=target_wires) QuantumPhaseEstimation( - u, + unitary, target_wires=target_wires, estimation_wires=estimation_wires, ) From af75be2a601ce8c014efdabcaa8b0109147e4891 Mon Sep 17 00:00:00 2001 From: trbromley Date: Mon, 1 Mar 2021 12:07:05 -0500 Subject: [PATCH 29/30] Update docstring --- pennylane/templates/subroutines/qpe.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 997a1741ed1..49d198fc4b7 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -37,9 +37,10 @@ def QuantumPhaseEstimation(unitary, target_wires, estimation_wires): This circuit can be used to perform the standard quantum phase estimation algorithm, consisting of the following steps: - #. Prepare ``target_wires`` in an eigenstate of :math:`U`. If that eigenstate has a - corresponding eigenvalue :math:`e^{2 \pi i \theta}` with phase :math:`\theta \in [0, 1)`, - this algorithm will measure :math:`\theta`. + #. Prepare ``target_wires`` in a given state. If ``target_wires`` are prepared in an eigenstate + of :math:`U` that has corresponding eigenvalue :math:`e^{2 \pi i \theta}` with phase + :math:`\theta \in [0, 1)`, this algorithm will measure :math:`\theta`. Other input states can + be prepared more generally. #. Apply the ``QuantumPhaseEstimation`` circuit. #. Measure ``estimation_wires`` using :func:`~.probs`, giving a probability distribution over measurement outcomes in the computational basis. From 5255248c45e7e069aff85dfec4f4d8dd5b57a737 Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 1 Mar 2021 11:47:02 -0600 Subject: [PATCH 30/30] QPE example: phase_estimated rescale edit --- pennylane/templates/subroutines/qpe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 49d198fc4b7..b83544bc3a0 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -102,7 +102,7 @@ def circuit(): phase_estimated = np.argmax(circuit()) / 2 ** n_estimation_wires # Need to rescale phase due to convention of RX gate - phase_estimated = 4 * np.pi * (1 - phase) + phase_estimated = 4 * np.pi * (1 - phase_estimated) """ target_wires = Wires(target_wires)